#import <ApplicationServices/ApplicationServices.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static CGEventFlags flags_from_names(const char *names) {
  CGEventFlags flags = 0;
  if (!names) return flags;
  if (strstr(names, "command")) flags |= kCGEventFlagMaskCommand;
  if (strstr(names, "control")) flags |= kCGEventFlagMaskControl;
  if (strstr(names, "shift")) flags |= kCGEventFlagMaskShift;
  if (strstr(names, "alt") || strstr(names, "option")) flags |= kCGEventFlagMaskAlternate;
  return flags;
}

static bool post_key(CGKeyCode code, bool down, CGEventFlags flags) {
  CGEventRef event = CGEventCreateKeyboardEvent(NULL, code, down);
  if (!event) {
    return false;
  }
  CGEventSetFlags(event, flags);
  CGEventPost(kCGHIDEventTap, event);
  CFRelease(event);
  return true;
}

static void trim_newline(char *line) {
  size_t len = strlen(line);
  while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
    line[len - 1] = '\0';
    len -= 1;
  }
}

int main(void) {
  char line[256];

  while (fgets(line, sizeof(line), stdin)) {
    trim_newline(line);
    if (line[0] == '\0') {
      continue;
    }

    char action[16] = {0};
    int code = -1;
    char modifiers[128] = {0};
    int parsed = sscanf(line, "%15s %d %127s", action, &code, modifiers);
    if (parsed < 2 || code < 0) {
      fprintf(stderr, "bad command: %s\n", line);
      fflush(stderr);
      continue;
    }

    CGEventFlags flags = parsed >= 3 ? flags_from_names(modifiers) : 0;
    bool ok = false;
    if (strcmp(action, "tap") == 0) {
      ok = post_key((CGKeyCode)code, true, flags);
      usleep(2000);
      ok = post_key((CGKeyCode)code, false, flags) && ok;
    } else if (strcmp(action, "down") == 0) {
      ok = post_key((CGKeyCode)code, true, flags);
    } else if (strcmp(action, "up") == 0) {
      ok = post_key((CGKeyCode)code, false, flags);
    } else if (strcmp(action, "quit") == 0) {
      return 0;
    } else {
      fprintf(stderr, "unknown action: %s\n", action);
      fflush(stderr);
      continue;
    }

    if (!ok) {
      fprintf(stderr, "post failed: %s %d\n", action, code);
      fflush(stderr);
    }
  }

  return 0;
}
