From 4b6af185d73d1332c3f2ac4b3e1dd9b17a42a04d Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Wed, 22 Jun 2016 20:41:02 +0800 Subject: [PATCH 01/12] Implement modifiers in the from side. This commit makes two modifiers as a key possible (#69). The expression grammar becomes 'ModKeyA:ModKeyB=Key[|OtherKey][;NextExpression]'. ModKeyB being pressed along will only be remapped if ModKeyA is being pressed. Leaving out ModKeyA behaves like the old xcape. Examples, 'Alt_L:Control_L=equal;Control_L:Alt_L=grave;Control_L=Escape' *Be aware the output `equal` and `grave` will become `Alt_L + equal` and `Control_L + grave`.* --- xcape.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/xcape.c b/xcape.c index 7c067eb..20dc2d5 100644 --- a/xcape.c +++ b/xcape.c @@ -32,6 +32,7 @@ #include #include +#define BIT(c, x) ( c[x/8]&(1<<(x%8)) ) /************************************************************************ * Internal data types @@ -47,6 +48,8 @@ typedef struct _KeyMap_t Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */ KeySym from_ks; KeyCode from_kc; + Bool UseModifier; + KeySym modifier; Key_t *to_keys; Bool used; Bool pressed; @@ -320,6 +323,16 @@ void handle_key (XCape_t *self, KeyMap_t *key, if (timercmp (&timev, &self->timeout, <)) { + char buf[32], *keys = buf; + XQueryKeymap(self->ctrl_conn, keys); + if (key->UseModifier) { + if (!BIT(keys, XKeysymToKeycode (self->ctrl_conn, key->modifier))) { + goto skip; + } + } else { + for (int i = 0; i < 32; i++) + if (keys[i]) goto skip; + } for (k = key->to_keys; k != NULL; k = k->next) { if (self->debug) fprintf (stdout, "Generating %s!\n", @@ -339,6 +352,7 @@ void handle_key (XCape_t *self, KeyMap_t *key, XFlush (self->ctrl_conn); } } + skip: key->used = False; key->pressed = False; } @@ -409,7 +423,7 @@ void intercept (XPointer user_data, XRecordInterceptData *data) } exit: - XUnlockDisplay (self->ctrl_conn); + XUnlockDisplay (self->ctrl_conn); XRecordFreeData (data); } @@ -417,11 +431,17 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug) { KeyMap_t *km = NULL; KeySym ks; - char *from, *to, *key; + char *modifier, *from, *to, *key; KeyCode code; /* keycode (to) */ long fromcode; /* keycode (from) */ to = token; + modifier = strsep (&to, ":"); + if (to == NULL) { + to = token; + modifier = NULL; + } + from = strsep (&to, "="); if (to != NULL) { @@ -476,6 +496,28 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug) } } + if (modifier != NULL) { + if ((ks = XStringToKeysym (modifier)) == NoSymbol) + { + fprintf (stderr, "Invalid key: %s\n", token); + return NULL; + } + + km->UseModifier = True; + km->modifier = ks; + + if (debug) + { + fprintf(stderr, "Assigned mapping with modifier \"%s\" ( keysym 0x%x, " + "key code %d)\n", + XKeysymToString (km->modifier), + (unsigned) km->modifier, + (unsigned) XKeysymToKeycode (dpy, km->modifier)); + } + } else { + km->UseModifier = False; + } + for(;;) { key = strsep (&to, "|"); From 7e275d7f0ce486153a7c03ff013b3385cf3fcaf1 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Wed, 5 Jul 2017 04:04:10 +0800 Subject: [PATCH 02/12] use /usr/local. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fc90900..73d5b1b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ INSTALL=install -PREFIX=/usr -MANDIR?=/local/man/man1 +PREFIX=/usr/local +MANDIR?=/man/man1 TARGET := xcape From 6f9069a9ef30a5b38fd1693d59a702fe657d796d Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Wed, 5 Jul 2017 14:52:26 +0800 Subject: [PATCH 03/12] some keycodes are invalid if xkb changes. --- xcape.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/xcape.c b/xcape.c index 20dc2d5..280a6ad 100644 --- a/xcape.c +++ b/xcape.c @@ -452,26 +452,16 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug) { errno = 0; fromcode = strtoul (from, NULL, 0); /* dec, oct, hex automatically */ - if (errno == 0 - && fromcode <=255 - && XkbKeycodeToKeysym (dpy, (KeyCode) fromcode, 0, 0) != NoSymbol) - { - km->UseKeyCode = True; - km->from_kc = (KeyCode) fromcode; - if (debug) - { - KeySym ks_temp = XkbKeycodeToKeysym (dpy, (KeyCode) fromcode, 0, 0); - fprintf(stderr, "Assigned mapping from from \"%s\" ( keysym 0x%x, " - "key code %d)\n", - XKeysymToString(ks_temp), - (unsigned) ks_temp, - (unsigned) km->from_kc); - } - } - else + km->UseKeyCode = True; + km->from_kc = (KeyCode) fromcode; + if (debug) { - fprintf (stderr, "Invalid keycode: %s\n", from); - return NULL; + KeySym ks_temp = XkbKeycodeToKeysym (dpy, (KeyCode) fromcode, 0, 0); + fprintf(stderr, "Assigned mapping from from \"%s\" ( keysym 0x%x, " + "key code %d)\n", + XKeysymToString(ks_temp), + (unsigned) ks_temp, + (unsigned) km->from_kc); } } else From 821f0bd2c7c6d87b6bfd355ab6e00d7d7bdec892 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Thu, 27 Jul 2017 22:47:56 +0800 Subject: [PATCH 04/12] fix ctrl+return. --- xcape.c | 877 ++++++++++++++++++++++++++------------------------------ 1 file changed, 407 insertions(+), 470 deletions(-) diff --git a/xcape.c b/xcape.c index 280a6ad..82e2173 100644 --- a/xcape.c +++ b/xcape.c @@ -18,585 +18,522 @@ * ***********************************************************************/ -#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#define BIT(c, x) ( c[x/8]&(1<<(x%8)) ) +#define BIT(c, x) (c[x / 8] & (1 << (x % 8))) /************************************************************************ * Internal data types ***********************************************************************/ -typedef struct _Key_t -{ - KeyCode key; - struct _Key_t *next; +typedef struct _Key_t { + KeyCode key; + struct _Key_t *next; } Key_t; -typedef struct _KeyMap_t -{ - Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */ - KeySym from_ks; - KeyCode from_kc; - Bool UseModifier; - KeySym modifier; - Key_t *to_keys; - Bool used; - Bool pressed; - Bool mouse; - struct timeval down_at; - struct _KeyMap_t *next; +typedef struct _KeyMap_t { + Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */ + KeySym from_ks; + KeyCode from_kc; + Bool UseModifier; + Bool UseModifierCode; + KeySym modifier; + KeyCode modifier_code; + Key_t *to_keys; + Bool used; + Bool pressed; + Bool mouse; + struct timeval down_at; + struct _KeyMap_t *next; } KeyMap_t; -typedef struct _XCape_t -{ - Display *data_conn; - Display *ctrl_conn; - XRecordContext record_ctx; - pthread_t sigwait_thread; - sigset_t sigset; - Bool debug; - KeyMap_t *map; - Key_t *generated; - struct timeval timeout; +typedef struct _XCape_t { + Display *data_conn; + Display *ctrl_conn; + XRecordContext record_ctx; + pthread_t sigwait_thread; + sigset_t sigset; + Bool debug; + KeyMap_t *map; + Key_t *generated; + struct timeval timeout; } XCape_t; /************************************************************************ * Internal function declarations ***********************************************************************/ -void *sig_handler (void *user_data); +void *sig_handler(void *user_data); -void intercept (XPointer user_data, XRecordInterceptData *data); +void intercept(XPointer user_data, XRecordInterceptData *data); -KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping, Bool debug); +KeyMap_t *parse_mapping(Display *ctrl_conn, char *mapping, Bool debug); -void delete_mapping (KeyMap_t *map); +void delete_mapping(KeyMap_t *map); -Key_t *key_add_key (Key_t *keys, KeyCode key); +Key_t *key_add_key(Key_t *keys, KeyCode key); -void delete_keys (Key_t *keys); +void delete_keys(Key_t *keys); -void print_usage (const char *program_name); +void print_usage(const char *program_name); /************************************************************************ * Main function ***********************************************************************/ -int main (int argc, char **argv) -{ - XCape_t *self = malloc (sizeof (XCape_t)); - - int dummy, ch; - - static char default_mapping[] = "Control_L=Escape"; - char *mapping = default_mapping; - - XRecordRange *rec_range = XRecordAllocRange(); - XRecordClientSpec client_spec = XRecordAllClients; - - self->debug = False; - self->timeout.tv_sec = 0; - self->timeout.tv_usec = 500000; - self->generated = NULL; - - rec_range->device_events.first = KeyPress; - rec_range->device_events.last = ButtonRelease; - - while ((ch = getopt (argc, argv, "de:t:")) != -1) - { - switch (ch) - { - case 'd': - self->debug = True; - break; - case 'e': - mapping = optarg; - break; - case 't': - { - int ms = atoi (optarg); - if (ms > 0) - { - self->timeout.tv_sec = ms / 1000; - self->timeout.tv_usec = (ms % 1000) * 1000; - } - else - { - fprintf (stderr, "Invalid argument for '-t': %s.\n", optarg); - print_usage (argv[0]); - return EXIT_FAILURE; - } - } - break; - default: - print_usage (argv[0]); - return EXIT_SUCCESS; - } +int main(int argc, char **argv) { + XCape_t *self = malloc(sizeof(XCape_t)); + + int dummy, ch; + + static char default_mapping[] = "Control_L=Escape"; + char *mapping = default_mapping; + + XRecordRange *rec_range = XRecordAllocRange(); + XRecordClientSpec client_spec = XRecordAllClients; + + self->debug = False; + self->timeout.tv_sec = 0; + self->timeout.tv_usec = 500000; + self->generated = NULL; + + rec_range->device_events.first = KeyPress; + rec_range->device_events.last = ButtonRelease; + + while ((ch = getopt(argc, argv, "de:t:")) != -1) { + switch (ch) { + case 'd': + self->debug = True; + break; + case 'e': + mapping = optarg; + break; + case 't': { + int ms = atoi(optarg); + if (ms > 0) { + self->timeout.tv_sec = ms / 1000; + self->timeout.tv_usec = (ms % 1000) * 1000; + } else { + fprintf(stderr, "Invalid argument for '-t': %s.\n", optarg); + print_usage(argv[0]); + return EXIT_FAILURE; + } + } break; + default: + print_usage(argv[0]); + return EXIT_SUCCESS; } + } - if (optind < argc) - { - fprintf (stderr, "Not a command line option: '%s'\n", argv[optind]); - print_usage (argv[0]); - return EXIT_SUCCESS; - } + if (optind < argc) { + fprintf(stderr, "Not a command line option: '%s'\n", argv[optind]); + print_usage(argv[0]); + return EXIT_SUCCESS; + } - if (!XInitThreads ()) - { - fprintf (stderr, "Failed to initialize threads.\n"); - exit (EXIT_FAILURE); - } + if (!XInitThreads()) { + fprintf(stderr, "Failed to initialize threads.\n"); + exit(EXIT_FAILURE); + } - self->data_conn = XOpenDisplay (NULL); - self->ctrl_conn = XOpenDisplay (NULL); + self->data_conn = XOpenDisplay(NULL); + self->ctrl_conn = XOpenDisplay(NULL); - if (!self->data_conn || !self->ctrl_conn) - { - fprintf (stderr, "Unable to connect to X11 display. Is $DISPLAY set?\n"); - exit (EXIT_FAILURE); - } - if (!XQueryExtension (self->ctrl_conn, - "XTEST", &dummy, &dummy, &dummy)) - { - fprintf (stderr, "Xtst extension missing\n"); - exit (EXIT_FAILURE); - } - if (!XRecordQueryVersion (self->ctrl_conn, &dummy, &dummy)) - { - fprintf (stderr, "Failed to obtain xrecord version\n"); - exit (EXIT_FAILURE); - } - if (!XkbQueryExtension (self->ctrl_conn, &dummy, &dummy, - &dummy, &dummy, &dummy)) - { - fprintf (stderr, "Failed to obtain xkb version\n"); - exit (EXIT_FAILURE); - } + if (!self->data_conn || !self->ctrl_conn) { + fprintf(stderr, "Unable to connect to X11 display. Is $DISPLAY set?\n"); + exit(EXIT_FAILURE); + } + if (!XQueryExtension(self->ctrl_conn, "XTEST", &dummy, &dummy, &dummy)) { + fprintf(stderr, "Xtst extension missing\n"); + exit(EXIT_FAILURE); + } + if (!XRecordQueryVersion(self->ctrl_conn, &dummy, &dummy)) { + fprintf(stderr, "Failed to obtain xrecord version\n"); + exit(EXIT_FAILURE); + } + if (!XkbQueryExtension(self->ctrl_conn, &dummy, &dummy, &dummy, &dummy, + &dummy)) { + fprintf(stderr, "Failed to obtain xkb version\n"); + exit(EXIT_FAILURE); + } - self->map = parse_mapping (self->ctrl_conn, mapping, self->debug); + self->map = parse_mapping(self->ctrl_conn, mapping, self->debug); - if (self->map == NULL) - { - fprintf (stderr, "Failed to parse_mapping\n"); - exit (EXIT_FAILURE); - } + if (self->map == NULL) { + fprintf(stderr, "Failed to parse_mapping\n"); + exit(EXIT_FAILURE); + } - if (self->debug != True) - daemon (0, 0); + if (self->debug != True) + daemon(0, 0); - sigemptyset (&self->sigset); - sigaddset (&self->sigset, SIGINT); - sigaddset (&self->sigset, SIGTERM); - pthread_sigmask (SIG_BLOCK, &self->sigset, NULL); + sigemptyset(&self->sigset); + sigaddset(&self->sigset, SIGINT); + sigaddset(&self->sigset, SIGTERM); + pthread_sigmask(SIG_BLOCK, &self->sigset, NULL); - pthread_create (&self->sigwait_thread, - NULL, sig_handler, self); + pthread_create(&self->sigwait_thread, NULL, sig_handler, self); - self->record_ctx = XRecordCreateContext (self->ctrl_conn, - 0, &client_spec, 1, &rec_range, 1); + self->record_ctx = + XRecordCreateContext(self->ctrl_conn, 0, &client_spec, 1, &rec_range, 1); - if (self->record_ctx == 0) - { - fprintf (stderr, "Failed to create xrecord context\n"); - exit (EXIT_FAILURE); - } + if (self->record_ctx == 0) { + fprintf(stderr, "Failed to create xrecord context\n"); + exit(EXIT_FAILURE); + } - XSync (self->ctrl_conn, False); + XSync(self->ctrl_conn, False); - if (!XRecordEnableContext (self->data_conn, - self->record_ctx, intercept, (XPointer)self)) - { - fprintf (stderr, "Failed to enable xrecord context\n"); - exit (EXIT_FAILURE); - } + if (!XRecordEnableContext(self->data_conn, self->record_ctx, intercept, + (XPointer)self)) { + fprintf(stderr, "Failed to enable xrecord context\n"); + exit(EXIT_FAILURE); + } - pthread_join (self->sigwait_thread, NULL); + pthread_join(self->sigwait_thread, NULL); - if (!XRecordFreeContext (self->ctrl_conn, self->record_ctx)) - { - fprintf (stderr, "Failed to free xrecord context\n"); - } + if (!XRecordFreeContext(self->ctrl_conn, self->record_ctx)) { + fprintf(stderr, "Failed to free xrecord context\n"); + } - if (self->debug) fprintf (stdout, "main exiting\n"); + if (self->debug) + fprintf(stdout, "main exiting\n"); - XFree (rec_range); + XFree(rec_range); - XCloseDisplay (self->ctrl_conn); - XCloseDisplay (self->data_conn); + XCloseDisplay(self->ctrl_conn); + XCloseDisplay(self->data_conn); - delete_mapping (self->map); + delete_mapping(self->map); - free (self); + free(self); - return EXIT_SUCCESS; + return EXIT_SUCCESS; } - /************************************************************************ * Internal functions ***********************************************************************/ -void *sig_handler (void *user_data) -{ - XCape_t *self = (XCape_t*)user_data; - int sig; +void *sig_handler(void *user_data) { + XCape_t *self = (XCape_t *)user_data; + int sig; - if (self->debug) fprintf (stdout, "sig_handler running...\n"); + if (self->debug) + fprintf(stdout, "sig_handler running...\n"); - sigwait(&self->sigset, &sig); + sigwait(&self->sigset, &sig); - if (self->debug) fprintf (stdout, "Caught signal %d!\n", sig); + if (self->debug) + fprintf(stdout, "Caught signal %d!\n", sig); - XLockDisplay (self->ctrl_conn); + XLockDisplay(self->ctrl_conn); - if (!XRecordDisableContext (self->ctrl_conn, - self->record_ctx)) - { - fprintf (stderr, "Failed to disable xrecord context\n"); - exit(EXIT_FAILURE); - } + if (!XRecordDisableContext(self->ctrl_conn, self->record_ctx)) { + fprintf(stderr, "Failed to disable xrecord context\n"); + exit(EXIT_FAILURE); + } - XSync (self->ctrl_conn, False); + XSync(self->ctrl_conn, False); - XUnlockDisplay (self->ctrl_conn); + XUnlockDisplay(self->ctrl_conn); - if (self->debug) fprintf (stdout, "sig_handler exiting...\n"); + if (self->debug) + fprintf(stdout, "sig_handler exiting...\n"); - return NULL; + return NULL; } -Key_t *key_add_key (Key_t *keys, KeyCode key) -{ - Key_t *rval = keys; +Key_t *key_add_key(Key_t *keys, KeyCode key) { + Key_t *rval = keys; - if (keys == NULL) - { - keys = malloc (sizeof (Key_t)); - rval = keys; - } - else - { - while (keys->next != NULL) keys = keys->next; - keys = (keys->next = malloc (sizeof (Key_t))); - } + if (keys == NULL) { + keys = malloc(sizeof(Key_t)); + rval = keys; + } else { + while (keys->next != NULL) + keys = keys->next; + keys = (keys->next = malloc(sizeof(Key_t))); + } - keys->key = key; - keys->next = NULL; + keys->key = key; + keys->next = NULL; - return rval; + return rval; } -void handle_key (XCape_t *self, KeyMap_t *key, - Bool mouse_pressed, int key_event) -{ - Key_t *k; +void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, + int key_event) { + Key_t *k; - if (key_event == KeyPress) - { - if (self->debug) fprintf (stdout, "Key pressed!\n"); + if (key_event == KeyPress) { + if (self->debug) + fprintf(stdout, "Key pressed!\n"); - key->pressed = True; + key->pressed = True; - gettimeofday (&key->down_at, NULL); + gettimeofday(&key->down_at, NULL); - if (mouse_pressed) - { - key->used = True; - } + if (mouse_pressed) { + key->used = True; } - else - { - if (self->debug) fprintf (stdout, "Key released!\n"); - if (key->used == False) - { - struct timeval timev = self->timeout; - gettimeofday (&timev, NULL); - timersub (&timev, &key->down_at, &timev); - - if (timercmp (&timev, &self->timeout, <)) - { - char buf[32], *keys = buf; - XQueryKeymap(self->ctrl_conn, keys); - if (key->UseModifier) { - if (!BIT(keys, XKeysymToKeycode (self->ctrl_conn, key->modifier))) { - goto skip; - } - } else { - for (int i = 0; i < 32; i++) - if (keys[i]) goto skip; - } - for (k = key->to_keys; k != NULL; k = k->next) - { - if (self->debug) fprintf (stdout, "Generating %s!\n", - XKeysymToString (XkbKeycodeToKeysym (self->ctrl_conn, - k->key, 0, 0))); - - XTestFakeKeyEvent (self->ctrl_conn, - k->key, True, 0); - self->generated = key_add_key (self->generated, k->key); - } - for (k = key->to_keys; k != NULL; k = k->next) - { - XTestFakeKeyEvent (self->ctrl_conn, - k->key, False, 0); - self->generated = key_add_key (self->generated, k->key); - } - XFlush (self->ctrl_conn); - } + } else { + if (self->debug) + fprintf(stdout, "Key released!\n"); + if (key->used == False) { + struct timeval timev = self->timeout; + gettimeofday(&timev, NULL); + timersub(&timev, &key->down_at, &timev); + + if (timercmp(&timev, &self->timeout, <)) { + char buf[32], *keys = buf; + XQueryKeymap(self->ctrl_conn, keys); + if (key->UseModifier) { + if (!BIT(keys, XKeysymToKeycode(self->ctrl_conn, key->modifier))) { + goto skip; + } + } else if (key->UseModifierCode) { + if (!BIT(keys, key->modifier_code)) { + goto skip; + } + } else { + for (int i = 0; i < 32; i++) + if (keys[i]) + goto skip; + } + for (k = key->to_keys; k != NULL; k = k->next) { + if (self->debug) + fprintf(stdout, "Generating %s!\n", + XKeysymToString( + XkbKeycodeToKeysym(self->ctrl_conn, k->key, 0, 0))); + + XTestFakeKeyEvent(self->ctrl_conn, k->key, True, 0); + self->generated = key_add_key(self->generated, k->key); } - skip: - key->used = False; - key->pressed = False; + for (k = key->to_keys; k != NULL; k = k->next) { + XTestFakeKeyEvent(self->ctrl_conn, k->key, False, 0); + self->generated = key_add_key(self->generated, k->key); + } + XFlush(self->ctrl_conn); + } } + skip: + key->used = False; + key->pressed = False; + } } -void intercept (XPointer user_data, XRecordInterceptData *data) -{ - XCape_t *self = (XCape_t*)user_data; - static Bool mouse_pressed = False; - KeyMap_t *km; - - XLockDisplay (self->ctrl_conn); - - if (data->category == XRecordFromServer) - { - int key_event = data->data[0]; - KeyCode key_code = data->data[1]; - Key_t *g, *g_prev = NULL; - - for (g = self->generated; g != NULL; g = g->next) - { - if (g->key == key_code) - { - if (self->debug) fprintf (stdout, - "Ignoring generated event.\n"); - if (g_prev != NULL) - { - g_prev->next = g->next; - } - else - { - self->generated = g->next; - } - free (g); - goto exit; - } - g_prev = g; - } +void intercept(XPointer user_data, XRecordInterceptData *data) { + XCape_t *self = (XCape_t *)user_data; + static Bool mouse_pressed = False; + KeyMap_t *km; - if (self->debug) fprintf (stdout, - "Intercepted key event %d, key code %d\n", - key_event, key_code); + XLockDisplay(self->ctrl_conn); - if (key_event == ButtonPress) - { - mouse_pressed = True; - } - else if (key_event == ButtonRelease) - { - mouse_pressed = False; - } - for (km = self->map; km != NULL; km = km->next) - { - if ((km->UseKeyCode == False - && XkbKeycodeToKeysym (self->ctrl_conn, key_code, 0, 0) - == km->from_ks) - || (km->UseKeyCode == True - && key_code == km->from_kc)) - { - handle_key (self, km, mouse_pressed, key_event); - } - else if (km->pressed - && (key_event == KeyPress || key_event == ButtonPress)) - { - km->used = True; - } + if (data->category == XRecordFromServer) { + int key_event = data->data[0]; + KeyCode key_code = data->data[1]; + Key_t *g, *g_prev = NULL; + + for (g = self->generated; g != NULL; g = g->next) { + if (g->key == key_code) { + if (self->debug) + fprintf(stdout, "Ignoring generated event.\n"); + if (g_prev != NULL) { + g_prev->next = g->next; + } else { + self->generated = g->next; } + free(g); + goto exit; + } + g_prev = g; + } + + if (self->debug) + fprintf(stdout, "Intercepted key event %d, key code %d\n", key_event, + key_code); + + if (key_event == ButtonPress) { + mouse_pressed = True; + } else if (key_event == ButtonRelease) { + mouse_pressed = False; + } + for (km = self->map; km != NULL; km = km->next) { + if ((km->UseKeyCode == False && + XkbKeycodeToKeysym(self->ctrl_conn, key_code, 0, 0) == + km->from_ks) || + (km->UseKeyCode == True && key_code == km->from_kc)) { + handle_key(self, km, mouse_pressed, key_event); + } else if (km->pressed && + (key_event == KeyPress || key_event == ButtonPress)) { + km->used = True; + } } + } exit: - XUnlockDisplay (self->ctrl_conn); - XRecordFreeData (data); + XUnlockDisplay(self->ctrl_conn); + XRecordFreeData(data); } -KeyMap_t *parse_token (Display *dpy, char *token, Bool debug) -{ - KeyMap_t *km = NULL; - KeySym ks; - char *modifier, *from, *to, *key; - KeyCode code; /* keycode (to) */ - long fromcode; /* keycode (from) */ +KeyMap_t *parse_token(Display *dpy, char *token, Bool debug) { + KeyMap_t *km = NULL; + KeySym ks; + char *modifier, *from, *to, *key; + KeyCode code; /* keycode (to) */ + long fromcode; /* keycode (from) */ + to = token; + modifier = strsep(&to, ":"); + if (to == NULL) { to = token; - modifier = strsep (&to, ":"); - if (to == NULL) { - to = token; - modifier = NULL; + modifier = NULL; + } + + from = strsep(&to, "="); + if (to != NULL) { + km = calloc(1, sizeof(KeyMap_t)); + + if (!strncmp(from, "#", 1) && strsep(&from, "#") != NULL) { + errno = 0; + fromcode = strtoul(from, NULL, 0); /* dec, oct, hex automatically */ + km->UseKeyCode = True; + km->from_kc = (KeyCode)fromcode; + if (debug) { + KeySym ks_temp = XkbKeycodeToKeysym(dpy, (KeyCode)fromcode, 0, 0); + fprintf(stderr, "Assigned mapping from from \"%s\" ( keysym 0x%x, " + "key code %d)\n", + XKeysymToString(ks_temp), (unsigned)ks_temp, + (unsigned)km->from_kc); + } + } else { + if ((ks = XStringToKeysym(from)) == NoSymbol) { + fprintf(stderr, "Invalid key: %s\n", token); + return NULL; + } + + km->UseKeyCode = False; + km->from_ks = ks; + km->to_keys = NULL; + + if (debug) { + fprintf(stderr, "Assigned mapping from \"%s\" ( keysym 0x%x, " + "key code %d)\n", + XKeysymToString(km->from_ks), (unsigned)km->from_ks, + (unsigned)XKeysymToKeycode(dpy, km->from_ks)); + } } - from = strsep (&to, "="); - if (to != NULL) - { - km = calloc (1, sizeof (KeyMap_t)); - - if (!strncmp (from, "#", 1) - && strsep (&from, "#") != NULL) - { - errno = 0; - fromcode = strtoul (from, NULL, 0); /* dec, oct, hex automatically */ - km->UseKeyCode = True; - km->from_kc = (KeyCode) fromcode; - if (debug) - { - KeySym ks_temp = XkbKeycodeToKeysym (dpy, (KeyCode) fromcode, 0, 0); - fprintf(stderr, "Assigned mapping from from \"%s\" ( keysym 0x%x, " - "key code %d)\n", - XKeysymToString(ks_temp), - (unsigned) ks_temp, - (unsigned) km->from_kc); - } + if (modifier != NULL) { + if (!strncmp(modifier, "#", 1) && strsep(&modifier, "#") != NULL) { + km->UseModifierCode = True; + km->modifier_code = + strtoul(modifier, NULL, 0); /* dec, oct, hex automatically */ + } else { + if ((ks = XStringToKeysym(modifier)) == NoSymbol) { + fprintf(stderr, "Invalid key: %s\n", token); + return NULL; } - else - { - if ((ks = XStringToKeysym (from)) == NoSymbol) - { - fprintf (stderr, "Invalid key: %s\n", token); - return NULL; - } - - km->UseKeyCode = False; - km->from_ks = ks; - km->to_keys = NULL; - - if (debug) - { - fprintf(stderr, "Assigned mapping from \"%s\" ( keysym 0x%x, " - "key code %d)\n", - XKeysymToString (km->from_ks), - (unsigned) km->from_ks, - (unsigned) XKeysymToKeycode (dpy, km->from_ks)); - } + km->UseModifier = True; + km->modifier = ks; + if (debug) { + fprintf(stderr, + "Assigned mapping with modifier \"%s\" ( keysym 0x%x, " + "key code %d)\n", + XKeysymToString(km->modifier), (unsigned)km->modifier, + (unsigned)XKeysymToKeycode(dpy, km->modifier)); } + } - if (modifier != NULL) { - if ((ks = XStringToKeysym (modifier)) == NoSymbol) - { - fprintf (stderr, "Invalid key: %s\n", token); - return NULL; - } + } else { + km->UseModifier = False; + } - km->UseModifier = True; - km->modifier = ks; + for (;;) { + key = strsep(&to, "|"); + if (key == NULL) + break; - if (debug) - { - fprintf(stderr, "Assigned mapping with modifier \"%s\" ( keysym 0x%x, " - "key code %d)\n", - XKeysymToString (km->modifier), - (unsigned) km->modifier, - (unsigned) XKeysymToKeycode (dpy, km->modifier)); - } - } else { - km->UseModifier = False; - } + if ((ks = XStringToKeysym(key)) == NoSymbol) { + fprintf(stderr, "Invalid key: %s\n", key); + return NULL; + } - for(;;) - { - key = strsep (&to, "|"); - if (key == NULL) - break; - - if ((ks = XStringToKeysym (key)) == NoSymbol) - { - fprintf (stderr, "Invalid key: %s\n", key); - return NULL; - } - - code = XKeysymToKeycode (dpy, ks); - if (code == 0) - { - fprintf (stderr, "WARNING: No keycode found for keysym " + code = XKeysymToKeycode(dpy, ks); + if (code == 0) { + fprintf(stderr, "WARNING: No keycode found for keysym " "%s (0x%x) in mapping %s. Ignoring this " - "mapping.\n", key, (unsigned int)ks, token); - return NULL; - } - km->to_keys = key_add_key (km->to_keys, code); - - if (debug) - { - fprintf(stderr, "to \"%s\" (keysym 0x%x, key code %d)\n", - key, - (unsigned) XStringToKeysym (key), - (unsigned) code); - } - } + "mapping.\n", + key, (unsigned int)ks, token); + return NULL; + } + km->to_keys = key_add_key(km->to_keys, code); + + if (debug) { + fprintf(stderr, "to \"%s\" (keysym 0x%x, key code %d)\n", key, + (unsigned)XStringToKeysym(key), (unsigned)code); + } } - else - fprintf (stderr, "WARNING: Mapping without = has no effect: '%s'\n", token); - + } else + fprintf(stderr, "WARNING: Mapping without = has no effect: '%s'\n", token); - return km; + return km; } -KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping, Bool debug) -{ - char *token; - KeyMap_t *rval, *km, *nkm; - - rval = km = NULL; - - for(;;) - { - token = strsep (&mapping, ";"); - if (token == NULL) - break; - - nkm = parse_token (ctrl_conn, token, debug); - - if (nkm != NULL) - { - if (km == NULL) - rval = km = nkm; - else - { - km->next = nkm; - km = nkm; - } - } +KeyMap_t *parse_mapping(Display *ctrl_conn, char *mapping, Bool debug) { + char *token; + KeyMap_t *rval, *km, *nkm; + + rval = km = NULL; + + for (;;) { + token = strsep(&mapping, ";"); + if (token == NULL) + break; + + nkm = parse_token(ctrl_conn, token, debug); + + if (nkm != NULL) { + if (km == NULL) + rval = km = nkm; + else { + km->next = nkm; + km = nkm; + } } + } - return rval; + return rval; } -void delete_mapping (KeyMap_t *map) -{ - while (map != NULL) { - KeyMap_t *next = map->next; - delete_keys (map->to_keys); - free (map); - map = next; - } +void delete_mapping(KeyMap_t *map) { + while (map != NULL) { + KeyMap_t *next = map->next; + delete_keys(map->to_keys); + free(map); + map = next; + } } -void delete_keys (Key_t *keys) -{ - while (keys != NULL) { - Key_t *next = keys->next; - free (keys); - keys = next; - } +void delete_keys(Key_t *keys) { + while (keys != NULL) { + Key_t *next = keys->next; + free(keys); + keys = next; + } } -void print_usage (const char *program_name) -{ - fprintf (stdout, "Usage: %s [-d] [-t timeout_ms] [-e ]\n", program_name); - fprintf (stdout, "Runs as a daemon unless -d flag is set\n"); +void print_usage(const char *program_name) { + fprintf(stdout, "Usage: %s [-d] [-t timeout_ms] [-e ]\n", + program_name); + fprintf(stdout, "Runs as a daemon unless -d flag is set\n"); } From 7fea11028a18c62e218c710f942f86fd23b4cc31 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Sat, 28 Oct 2017 22:53:56 +0800 Subject: [PATCH 05/12] make copyq in sync --- .dir-locals.el | 1 + xcape.c | 1 + 2 files changed, 2 insertions(+) create mode 100644 .dir-locals.el diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..714af85 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1 @@ +((nil . ((cmake-ide-project-dir . "/home/amos/git/xcape") (cmake-ide-build-dir . "/home/amos/git/xcape")))) diff --git a/xcape.c b/xcape.c index 82e2173..640a942 100644 --- a/xcape.c +++ b/xcape.c @@ -309,6 +309,7 @@ void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, if (keys[i]) goto skip; } + if (key->from_kc == 108) system("copyq select 0"); for (k = key->to_keys; k != NULL; k = k->next) { if (self->debug) fprintf(stdout, "Generating %s!\n", From c8e52a97812bed2a1841220d9f22de958285022d Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Mon, 26 Mar 2018 20:15:29 +0800 Subject: [PATCH 06/12] revert this stupid thing. --- .dir-locals.el | 1 - xcape.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 .dir-locals.el diff --git a/.dir-locals.el b/.dir-locals.el deleted file mode 100644 index 714af85..0000000 --- a/.dir-locals.el +++ /dev/null @@ -1 +0,0 @@ -((nil . ((cmake-ide-project-dir . "/home/amos/git/xcape") (cmake-ide-build-dir . "/home/amos/git/xcape")))) diff --git a/xcape.c b/xcape.c index 640a942..55dbaf0 100644 --- a/xcape.c +++ b/xcape.c @@ -309,7 +309,7 @@ void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, if (keys[i]) goto skip; } - if (key->from_kc == 108) system("copyq select 0"); + /* if (key->from_kc == 108) system("copyq select 0"); */ for (k = key->to_keys; k != NULL; k = k->next) { if (self->debug) fprintf(stdout, "Generating %s!\n", From 530953b4ef8aa3156fa46f03d43a3d4fad3371ab Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Wed, 2 Jan 2019 10:29:52 +0800 Subject: [PATCH 07/12] good stuff --- xcape.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/xcape.c b/xcape.c index 55dbaf0..ac9d1c7 100644 --- a/xcape.c +++ b/xcape.c @@ -278,6 +278,21 @@ void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, if (self->debug) fprintf(stdout, "Key pressed!\n"); + + char buf[32], *keys = buf; + XQueryKeymap(self->ctrl_conn, keys); + if ((BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) + { + XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0); + /* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */ + self->generated = key_add_key(self->generated, 22); + XFlush(self->ctrl_conn); + key->pressed = True; + key->used = True; + key->mouse = True; + return; + } + key->pressed = True; gettimeofday(&key->down_at, NULL); @@ -288,7 +303,14 @@ void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, } else { if (self->debug) fprintf(stdout, "Key released!\n"); - if (key->used == False) { + if (key->mouse) + { + XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); + self->generated = key_add_key(self->generated, 22); + XFlush(self->ctrl_conn); + key->mouse = False; + } + else if (key->used == False) { struct timeval timev = self->timeout; gettimeofday(&timev, NULL); timersub(&timev, &key->down_at, &timev); From 30fe0d197a98e1c4ad62af6bf8f4a8239a4141e0 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Tue, 19 Feb 2019 02:09:11 +0800 Subject: [PATCH 08/12] dedup --- xcape.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xcape.c b/xcape.c index ac9d1c7..1ed8e5e 100644 --- a/xcape.c +++ b/xcape.c @@ -175,6 +175,7 @@ int main(int argc, char **argv) { if (self->debug != True) daemon(0, 0); + self->debug = False; sigemptyset(&self->sigset); sigaddset(&self->sigset, SIGINT); @@ -281,7 +282,7 @@ void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, char buf[32], *keys = buf; XQueryKeymap(self->ctrl_conn, keys); - if ((BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) + if (!key->UseModifier && (BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) { XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0); /* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */ From 6dbbd4c3340a76bbe3199ffd0c705e77f9eead8b Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Fri, 1 Mar 2019 17:14:00 +0800 Subject: [PATCH 09/12] fix --- xcape.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xcape.c b/xcape.c index 1ed8e5e..48c5a41 100644 --- a/xcape.c +++ b/xcape.c @@ -282,7 +282,8 @@ void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, char buf[32], *keys = buf; XQueryKeymap(self->ctrl_conn, keys); - if (!key->UseModifier && (BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) + + if ((BIT(keys, 64) || BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) { XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0); /* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */ From 067c8c0a2a23ce827bafb6163f1febf1774bcc32 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Sun, 7 Apr 2019 00:19:45 +0800 Subject: [PATCH 10/12] do not use alt-bs --- xcape.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xcape.c b/xcape.c index 48c5a41..fbaf5bc 100644 --- a/xcape.c +++ b/xcape.c @@ -283,7 +283,8 @@ void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, char buf[32], *keys = buf; XQueryKeymap(self->ctrl_conn, keys); - if ((BIT(keys, 64) || BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) + // lshift and rshift + if ((BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) { XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0); /* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */ From 626288987603b3dc664661d6a09214db85265b6f Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Wed, 4 Dec 2019 14:09:29 +0800 Subject: [PATCH 11/12] what can I say --- Makefile | 2 +- xcape.c | 831 +++++++++++++++++++++++++++---------------------------- 2 files changed, 411 insertions(+), 422 deletions(-) diff --git a/Makefile b/Makefile index 73d5b1b..84f244f 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ MANDIR?=/man/man1 TARGET := xcape -CFLAGS += -Wall +CFLAGS += -Wall -g -O0 CFLAGS += `pkg-config --cflags xtst x11` LDFLAGS += `pkg-config --libs xtst x11` LDFLAGS += -pthread diff --git a/xcape.c b/xcape.c index fbaf5bc..9487967 100644 --- a/xcape.c +++ b/xcape.c @@ -38,528 +38,517 @@ * Internal data types ***********************************************************************/ typedef struct _Key_t { - KeyCode key; - struct _Key_t *next; + KeyCode key; + struct _Key_t* next; } Key_t; typedef struct _KeyMap_t { - Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */ - KeySym from_ks; - KeyCode from_kc; - Bool UseModifier; - Bool UseModifierCode; - KeySym modifier; - KeyCode modifier_code; - Key_t *to_keys; - Bool used; - Bool pressed; - Bool mouse; - struct timeval down_at; - struct _KeyMap_t *next; + Bool UseKeyCode; /* (for from) instead of KeySym; ignore latter */ + KeySym from_ks; + KeyCode from_kc; + Bool UseModifier; + Bool UseModifierCode; + KeySym modifier; + KeyCode modifier_code; + Key_t* to_keys; + Bool used; + Bool pressed; + Bool mouse; + struct timeval down_at; + struct _KeyMap_t* next; } KeyMap_t; typedef struct _XCape_t { - Display *data_conn; - Display *ctrl_conn; - XRecordContext record_ctx; - pthread_t sigwait_thread; - sigset_t sigset; - Bool debug; - KeyMap_t *map; - Key_t *generated; - struct timeval timeout; + Display* data_conn; + Display* ctrl_conn; + XRecordContext record_ctx; + pthread_t sigwait_thread; + sigset_t sigset; + Bool debug; + KeyMap_t* map; + Key_t* generated; + struct timeval timeout; } XCape_t; /************************************************************************ * Internal function declarations ***********************************************************************/ -void *sig_handler(void *user_data); +void* sig_handler(void* user_data); -void intercept(XPointer user_data, XRecordInterceptData *data); +void intercept(XPointer user_data, XRecordInterceptData* data); -KeyMap_t *parse_mapping(Display *ctrl_conn, char *mapping, Bool debug); +KeyMap_t* parse_mapping(Display* ctrl_conn, char* mapping, Bool debug); -void delete_mapping(KeyMap_t *map); +void delete_mapping(KeyMap_t* map); -Key_t *key_add_key(Key_t *keys, KeyCode key); +Key_t* key_add_key(Key_t* keys, KeyCode key); -void delete_keys(Key_t *keys); +void delete_keys(Key_t* keys); -void print_usage(const char *program_name); +void print_usage(const char* program_name); /************************************************************************ * Main function ***********************************************************************/ -int main(int argc, char **argv) { - XCape_t *self = malloc(sizeof(XCape_t)); - - int dummy, ch; - - static char default_mapping[] = "Control_L=Escape"; - char *mapping = default_mapping; - - XRecordRange *rec_range = XRecordAllocRange(); - XRecordClientSpec client_spec = XRecordAllClients; - - self->debug = False; - self->timeout.tv_sec = 0; - self->timeout.tv_usec = 500000; - self->generated = NULL; - - rec_range->device_events.first = KeyPress; - rec_range->device_events.last = ButtonRelease; - - while ((ch = getopt(argc, argv, "de:t:")) != -1) { - switch (ch) { - case 'd': - self->debug = True; - break; - case 'e': - mapping = optarg; - break; - case 't': { - int ms = atoi(optarg); - if (ms > 0) { - self->timeout.tv_sec = ms / 1000; - self->timeout.tv_usec = (ms % 1000) * 1000; - } else { - fprintf(stderr, "Invalid argument for '-t': %s.\n", optarg); - print_usage(argv[0]); - return EXIT_FAILURE; - } - } break; - default: - print_usage(argv[0]); - return EXIT_SUCCESS; +int main(int argc, char** argv) { + XCape_t* self = malloc(sizeof(XCape_t)); + + int dummy, ch; + + static char default_mapping[] = "#37=Escape;#62=Return;#108=Shift_L|Insert;#100=BackSpace"; + char* mapping = default_mapping; + + XRecordRange* rec_range = XRecordAllocRange(); + XRecordClientSpec client_spec = XRecordAllClients; + + self->debug = False; + self->timeout.tv_sec = 0; + self->timeout.tv_usec = 500000; + self->generated = NULL; + + rec_range->device_events.first = KeyPress; + rec_range->device_events.last = ButtonRelease; + + while ((ch = getopt(argc, argv, "de:t:")) != -1) { + switch (ch) { + case 'd': + self->debug = True; + break; + case 'e': + mapping = optarg; + break; + case 't': { + int ms = atoi(optarg); + if (ms > 0) { + self->timeout.tv_sec = ms / 1000; + self->timeout.tv_usec = (ms % 1000) * 1000; + } else { + fprintf(stderr, "Invalid argument for '-t': %s.\n", optarg); + print_usage(argv[0]); + return EXIT_FAILURE; + } + } break; + default: + print_usage(argv[0]); + return EXIT_SUCCESS; + } } - } - if (optind < argc) { - fprintf(stderr, "Not a command line option: '%s'\n", argv[optind]); - print_usage(argv[0]); - return EXIT_SUCCESS; - } + if (optind < argc) { + fprintf(stderr, "Not a command line option: '%s'\n", argv[optind]); + print_usage(argv[0]); + return EXIT_SUCCESS; + } - if (!XInitThreads()) { - fprintf(stderr, "Failed to initialize threads.\n"); - exit(EXIT_FAILURE); - } + if (!XInitThreads()) { + fprintf(stderr, "Failed to initialize threads.\n"); + exit(EXIT_FAILURE); + } - self->data_conn = XOpenDisplay(NULL); - self->ctrl_conn = XOpenDisplay(NULL); + self->data_conn = XOpenDisplay(NULL); + self->ctrl_conn = XOpenDisplay(NULL); - if (!self->data_conn || !self->ctrl_conn) { - fprintf(stderr, "Unable to connect to X11 display. Is $DISPLAY set?\n"); - exit(EXIT_FAILURE); - } - if (!XQueryExtension(self->ctrl_conn, "XTEST", &dummy, &dummy, &dummy)) { - fprintf(stderr, "Xtst extension missing\n"); - exit(EXIT_FAILURE); - } - if (!XRecordQueryVersion(self->ctrl_conn, &dummy, &dummy)) { - fprintf(stderr, "Failed to obtain xrecord version\n"); - exit(EXIT_FAILURE); - } - if (!XkbQueryExtension(self->ctrl_conn, &dummy, &dummy, &dummy, &dummy, - &dummy)) { - fprintf(stderr, "Failed to obtain xkb version\n"); - exit(EXIT_FAILURE); - } + if (!self->data_conn || !self->ctrl_conn) { + fprintf(stderr, "Unable to connect to X11 display. Is $DISPLAY set?\n"); + exit(EXIT_FAILURE); + } + if (!XQueryExtension(self->ctrl_conn, "XTEST", &dummy, &dummy, &dummy)) { + fprintf(stderr, "Xtst extension missing\n"); + exit(EXIT_FAILURE); + } + if (!XRecordQueryVersion(self->ctrl_conn, &dummy, &dummy)) { + fprintf(stderr, "Failed to obtain xrecord version\n"); + exit(EXIT_FAILURE); + } + if (!XkbQueryExtension(self->ctrl_conn, &dummy, &dummy, &dummy, &dummy, &dummy)) { + fprintf(stderr, "Failed to obtain xkb version\n"); + exit(EXIT_FAILURE); + } - self->map = parse_mapping(self->ctrl_conn, mapping, self->debug); + self->map = parse_mapping(self->ctrl_conn, mapping, self->debug); - if (self->map == NULL) { - fprintf(stderr, "Failed to parse_mapping\n"); - exit(EXIT_FAILURE); - } + if (self->map == NULL) { + fprintf(stderr, "Failed to parse_mapping\n"); + exit(EXIT_FAILURE); + } - if (self->debug != True) - daemon(0, 0); - self->debug = False; + if (self->debug != True) + daemon(0, 0); + /* self->debug = False; */ - sigemptyset(&self->sigset); - sigaddset(&self->sigset, SIGINT); - sigaddset(&self->sigset, SIGTERM); - pthread_sigmask(SIG_BLOCK, &self->sigset, NULL); + sigemptyset(&self->sigset); + sigaddset(&self->sigset, SIGINT); + sigaddset(&self->sigset, SIGTERM); + pthread_sigmask(SIG_BLOCK, &self->sigset, NULL); - pthread_create(&self->sigwait_thread, NULL, sig_handler, self); + pthread_create(&self->sigwait_thread, NULL, sig_handler, self); - self->record_ctx = - XRecordCreateContext(self->ctrl_conn, 0, &client_spec, 1, &rec_range, 1); + self->record_ctx = XRecordCreateContext(self->ctrl_conn, 0, &client_spec, 1, &rec_range, 1); - if (self->record_ctx == 0) { - fprintf(stderr, "Failed to create xrecord context\n"); - exit(EXIT_FAILURE); - } + if (self->record_ctx == 0) { + fprintf(stderr, "Failed to create xrecord context\n"); + exit(EXIT_FAILURE); + } - XSync(self->ctrl_conn, False); + XSync(self->ctrl_conn, False); - if (!XRecordEnableContext(self->data_conn, self->record_ctx, intercept, - (XPointer)self)) { - fprintf(stderr, "Failed to enable xrecord context\n"); - exit(EXIT_FAILURE); - } + if (!XRecordEnableContext(self->data_conn, self->record_ctx, intercept, (XPointer)self)) { + fprintf(stderr, "Failed to enable xrecord context\n"); + exit(EXIT_FAILURE); + } - pthread_join(self->sigwait_thread, NULL); + pthread_join(self->sigwait_thread, NULL); - if (!XRecordFreeContext(self->ctrl_conn, self->record_ctx)) { - fprintf(stderr, "Failed to free xrecord context\n"); - } + if (!XRecordFreeContext(self->ctrl_conn, self->record_ctx)) { + fprintf(stderr, "Failed to free xrecord context\n"); + } - if (self->debug) - fprintf(stdout, "main exiting\n"); + if (self->debug) + fprintf(stdout, "main exiting\n"); - XFree(rec_range); + XFree(rec_range); - XCloseDisplay(self->ctrl_conn); - XCloseDisplay(self->data_conn); + XCloseDisplay(self->ctrl_conn); + XCloseDisplay(self->data_conn); - delete_mapping(self->map); + delete_mapping(self->map); - free(self); + free(self); - return EXIT_SUCCESS; + return EXIT_SUCCESS; } /************************************************************************ * Internal functions ***********************************************************************/ -void *sig_handler(void *user_data) { - XCape_t *self = (XCape_t *)user_data; - int sig; +void* sig_handler(void* user_data) { + XCape_t* self = (XCape_t*)user_data; + int sig; - if (self->debug) - fprintf(stdout, "sig_handler running...\n"); + if (self->debug) + fprintf(stdout, "sig_handler running...\n"); - sigwait(&self->sigset, &sig); + sigwait(&self->sigset, &sig); - if (self->debug) - fprintf(stdout, "Caught signal %d!\n", sig); + if (self->debug) + fprintf(stdout, "Caught signal %d!\n", sig); - XLockDisplay(self->ctrl_conn); + XLockDisplay(self->ctrl_conn); - if (!XRecordDisableContext(self->ctrl_conn, self->record_ctx)) { - fprintf(stderr, "Failed to disable xrecord context\n"); - exit(EXIT_FAILURE); - } + if (!XRecordDisableContext(self->ctrl_conn, self->record_ctx)) { + fprintf(stderr, "Failed to disable xrecord context\n"); + exit(EXIT_FAILURE); + } - XSync(self->ctrl_conn, False); + XSync(self->ctrl_conn, False); - XUnlockDisplay(self->ctrl_conn); + XUnlockDisplay(self->ctrl_conn); - if (self->debug) - fprintf(stdout, "sig_handler exiting...\n"); + if (self->debug) + fprintf(stdout, "sig_handler exiting...\n"); - return NULL; + return NULL; } -Key_t *key_add_key(Key_t *keys, KeyCode key) { - Key_t *rval = keys; +Key_t* key_add_key(Key_t* keys, KeyCode key) { + Key_t* rval = keys; - if (keys == NULL) { - keys = malloc(sizeof(Key_t)); - rval = keys; - } else { - while (keys->next != NULL) - keys = keys->next; - keys = (keys->next = malloc(sizeof(Key_t))); - } + if (keys == NULL) { + keys = malloc(sizeof(Key_t)); + rval = keys; + } else { + while (keys->next != NULL) + keys = keys->next; + keys = (keys->next = malloc(sizeof(Key_t))); + } - keys->key = key; - keys->next = NULL; + keys->key = key; + keys->next = NULL; - return rval; + return rval; } -void handle_key(XCape_t *self, KeyMap_t *key, Bool mouse_pressed, - int key_event) { - Key_t *k; - - if (key_event == KeyPress) { - if (self->debug) - fprintf(stdout, "Key pressed!\n"); - - - char buf[32], *keys = buf; - XQueryKeymap(self->ctrl_conn, keys); - - // lshift and rshift - if ((BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) - { - XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0); - /* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */ - self->generated = key_add_key(self->generated, 22); - XFlush(self->ctrl_conn); - key->pressed = True; - key->used = True; - key->mouse = True; - return; - } - - key->pressed = True; +void handle_key(XCape_t* self, KeyMap_t* key, Bool mouse_pressed, int key_event) { + Key_t* k; - gettimeofday(&key->down_at, NULL); - - if (mouse_pressed) { - key->used = True; - } - } else { - if (self->debug) - fprintf(stdout, "Key released!\n"); - if (key->mouse) - { - XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); - self->generated = key_add_key(self->generated, 22); - XFlush(self->ctrl_conn); - key->mouse = False; - } - else if (key->used == False) { - struct timeval timev = self->timeout; - gettimeofday(&timev, NULL); - timersub(&timev, &key->down_at, &timev); + if (key_event == KeyPress) { + if (self->debug) + fprintf(stdout, "Key pressed!\n"); - if (timercmp(&timev, &self->timeout, <)) { char buf[32], *keys = buf; XQueryKeymap(self->ctrl_conn, keys); - if (key->UseModifier) { - if (!BIT(keys, XKeysymToKeycode(self->ctrl_conn, key->modifier))) { - goto skip; - } - } else if (key->UseModifierCode) { - if (!BIT(keys, key->modifier_code)) { - goto skip; - } - } else { - for (int i = 0; i < 32; i++) - if (keys[i]) - goto skip; - } - /* if (key->from_kc == 108) system("copyq select 0"); */ - for (k = key->to_keys; k != NULL; k = k->next) { - if (self->debug) - fprintf(stdout, "Generating %s!\n", - XKeysymToString( - XkbKeycodeToKeysym(self->ctrl_conn, k->key, 0, 0))); - - XTestFakeKeyEvent(self->ctrl_conn, k->key, True, 0); - self->generated = key_add_key(self->generated, k->key); - } - for (k = key->to_keys; k != NULL; k = k->next) { - XTestFakeKeyEvent(self->ctrl_conn, k->key, False, 0); - self->generated = key_add_key(self->generated, k->key); - } - XFlush(self->ctrl_conn); - } - } - skip: - key->used = False; - key->pressed = False; - } -} -void intercept(XPointer user_data, XRecordInterceptData *data) { - XCape_t *self = (XCape_t *)user_data; - static Bool mouse_pressed = False; - KeyMap_t *km; + // lshift and rshift + if ((BIT(keys, 50) || BIT(keys, 62)) && key->from_kc == 100) { + XTestFakeKeyEvent(self->ctrl_conn, 22, True, 0); + /* XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); */ + self->generated = key_add_key(self->generated, 22); + XFlush(self->ctrl_conn); + key->pressed = True; + key->used = True; + key->mouse = True; + return; + } - XLockDisplay(self->ctrl_conn); + key->pressed = True; - if (data->category == XRecordFromServer) { - int key_event = data->data[0]; - KeyCode key_code = data->data[1]; - Key_t *g, *g_prev = NULL; + gettimeofday(&key->down_at, NULL); - for (g = self->generated; g != NULL; g = g->next) { - if (g->key == key_code) { + /* if (mouse_pressed) { */ + /* key->used = True; */ + /* } */ + } else { if (self->debug) - fprintf(stdout, "Ignoring generated event.\n"); - if (g_prev != NULL) { - g_prev->next = g->next; - } else { - self->generated = g->next; + fprintf(stdout, "Key released!\n"); + if (key->mouse) { + XTestFakeKeyEvent(self->ctrl_conn, 22, False, 0); + self->generated = key_add_key(self->generated, 22); + XFlush(self->ctrl_conn); + key->mouse = False; + } else if (key->used == False) { + struct timeval timev = self->timeout; + gettimeofday(&timev, NULL); + timersub(&timev, &key->down_at, &timev); + + if (timercmp(&timev, &self->timeout, <)) { + char buf[32], *keys = buf; + XQueryKeymap(self->ctrl_conn, keys); + if (key->UseModifier) { + if (!BIT(keys, XKeysymToKeycode(self->ctrl_conn, key->modifier))) { + goto skip; + } + } else if (key->UseModifierCode) { + if (!BIT(keys, key->modifier_code)) { + goto skip; + } + } + /* else { */ + /* for (int i = 0; i < 32; i++) */ + /* if (keys[i]) */ + /* goto skip; */ + /* } */ + /* if (key->from_kc == 108) system("copyq select 0"); */ + for (k = key->to_keys; k != NULL; k = k->next) { + if (self->debug) + fprintf(stdout, "Generating %s!\n", + XKeysymToString(XkbKeycodeToKeysym(self->ctrl_conn, k->key, 0, 0))); + + XTestFakeKeyEvent(self->ctrl_conn, k->key, True, 0); + self->generated = key_add_key(self->generated, k->key); + } + for (k = key->to_keys; k != NULL; k = k->next) { + XTestFakeKeyEvent(self->ctrl_conn, k->key, False, 0); + self->generated = key_add_key(self->generated, k->key); + } + XFlush(self->ctrl_conn); + } } - free(g); - goto exit; - } - g_prev = g; + skip: + key->used = False; + key->pressed = False; } +} - if (self->debug) - fprintf(stdout, "Intercepted key event %d, key code %d\n", key_event, - key_code); +void intercept(XPointer user_data, XRecordInterceptData* data) { + XCape_t* self = (XCape_t*)user_data; + static Bool mouse_pressed = False; + KeyMap_t* km; + + XLockDisplay(self->ctrl_conn); + + if (data->category == XRecordFromServer) { + int key_event = data->data[0]; + KeyCode key_code = data->data[1]; + Key_t *g, *g_prev = NULL; + + for (g = self->generated; g != NULL; g = g->next) { + if (g->key == key_code) { + if (self->debug) + fprintf(stdout, "Ignoring generated event.\n"); + if (g_prev != NULL) { + g_prev->next = g->next; + } else { + self->generated = g->next; + } + free(g); + goto exit; + } + g_prev = g; + } - if (key_event == ButtonPress) { - mouse_pressed = True; - } else if (key_event == ButtonRelease) { - mouse_pressed = False; - } - for (km = self->map; km != NULL; km = km->next) { - if ((km->UseKeyCode == False && - XkbKeycodeToKeysym(self->ctrl_conn, key_code, 0, 0) == - km->from_ks) || - (km->UseKeyCode == True && key_code == km->from_kc)) { - handle_key(self, km, mouse_pressed, key_event); - } else if (km->pressed && - (key_event == KeyPress || key_event == ButtonPress)) { - km->used = True; - } + if (self->debug) + fprintf(stdout, "Intercepted key event %d, key code %d\n", key_event, key_code); + + if (key_event == ButtonPress) { + mouse_pressed = True; + } else if (key_event == ButtonRelease) { + mouse_pressed = False; + } + for (km = self->map; km != NULL; km = km->next) { + if ((km->UseKeyCode == False + && XkbKeycodeToKeysym(self->ctrl_conn, key_code, 0, 0) == km->from_ks) + || (km->UseKeyCode == True && key_code == km->from_kc)) { + handle_key(self, km, mouse_pressed, key_event); + } else if (km->pressed && (key_event == KeyPress || key_event == ButtonPress)) { + km->used = True; + } + } } - } exit: - XUnlockDisplay(self->ctrl_conn); - XRecordFreeData(data); + XUnlockDisplay(self->ctrl_conn); + XRecordFreeData(data); } -KeyMap_t *parse_token(Display *dpy, char *token, Bool debug) { - KeyMap_t *km = NULL; - KeySym ks; - char *modifier, *from, *to, *key; - KeyCode code; /* keycode (to) */ - long fromcode; /* keycode (from) */ +KeyMap_t* parse_token(Display* dpy, char* token, Bool debug) { + KeyMap_t* km = NULL; + KeySym ks; + char *modifier, *from, *to, *key; + KeyCode code; /* keycode (to) */ + long fromcode; /* keycode (from) */ - to = token; - modifier = strsep(&to, ":"); - if (to == NULL) { to = token; - modifier = NULL; - } - - from = strsep(&to, "="); - if (to != NULL) { - km = calloc(1, sizeof(KeyMap_t)); - - if (!strncmp(from, "#", 1) && strsep(&from, "#") != NULL) { - errno = 0; - fromcode = strtoul(from, NULL, 0); /* dec, oct, hex automatically */ - km->UseKeyCode = True; - km->from_kc = (KeyCode)fromcode; - if (debug) { - KeySym ks_temp = XkbKeycodeToKeysym(dpy, (KeyCode)fromcode, 0, 0); - fprintf(stderr, "Assigned mapping from from \"%s\" ( keysym 0x%x, " - "key code %d)\n", - XKeysymToString(ks_temp), (unsigned)ks_temp, - (unsigned)km->from_kc); - } - } else { - if ((ks = XStringToKeysym(from)) == NoSymbol) { - fprintf(stderr, "Invalid key: %s\n", token); - return NULL; - } + modifier = strsep(&to, ":"); + if (to == NULL) { + to = token; + modifier = NULL; + } - km->UseKeyCode = False; - km->from_ks = ks; - km->to_keys = NULL; + from = strsep(&to, "="); + if (to != NULL) { + km = calloc(1, sizeof(KeyMap_t)); + + if (!strncmp(from, "#", 1) && strsep(&from, "#") != NULL) { + errno = 0; + fromcode = strtoul(from, NULL, 0); /* dec, oct, hex automatically */ + km->UseKeyCode = True; + km->from_kc = (KeyCode)fromcode; + if (debug) { + KeySym ks_temp = XkbKeycodeToKeysym(dpy, (KeyCode)fromcode, 0, 0); + fprintf(stderr, + "Assigned mapping from from \"%s\" ( keysym 0x%x, " + "key code %d)\n", + XKeysymToString(ks_temp), (unsigned)ks_temp, (unsigned)km->from_kc); + } + } else { + if ((ks = XStringToKeysym(from)) == NoSymbol) { + fprintf(stderr, "Invalid key: %s\n", token); + return NULL; + } + + km->UseKeyCode = False; + km->from_ks = ks; + km->to_keys = NULL; + + if (debug) { + fprintf(stderr, + "Assigned mapping from \"%s\" ( keysym 0x%x, " + "key code %d)\n", + XKeysymToString(km->from_ks), (unsigned)km->from_ks, + (unsigned)XKeysymToKeycode(dpy, km->from_ks)); + } + } - if (debug) { - fprintf(stderr, "Assigned mapping from \"%s\" ( keysym 0x%x, " + if (modifier != NULL) { + if (!strncmp(modifier, "#", 1) && strsep(&modifier, "#") != NULL) { + km->UseModifierCode = True; + km->modifier_code = strtoul(modifier, NULL, 0); /* dec, oct, hex automatically */ + } else { + if ((ks = XStringToKeysym(modifier)) == NoSymbol) { + fprintf(stderr, "Invalid key: %s\n", token); + return NULL; + } + km->UseModifier = True; + km->modifier = ks; + if (debug) { + fprintf(stderr, + "Assigned mapping with modifier \"%s\" ( keysym 0x%x, " "key code %d)\n", - XKeysymToString(km->from_ks), (unsigned)km->from_ks, - (unsigned)XKeysymToKeycode(dpy, km->from_ks)); - } - } + XKeysymToString(km->modifier), (unsigned)km->modifier, + (unsigned)XKeysymToKeycode(dpy, km->modifier)); + } + } - if (modifier != NULL) { - if (!strncmp(modifier, "#", 1) && strsep(&modifier, "#") != NULL) { - km->UseModifierCode = True; - km->modifier_code = - strtoul(modifier, NULL, 0); /* dec, oct, hex automatically */ - } else { - if ((ks = XStringToKeysym(modifier)) == NoSymbol) { - fprintf(stderr, "Invalid key: %s\n", token); - return NULL; - } - km->UseModifier = True; - km->modifier = ks; - if (debug) { - fprintf(stderr, - "Assigned mapping with modifier \"%s\" ( keysym 0x%x, " - "key code %d)\n", - XKeysymToString(km->modifier), (unsigned)km->modifier, - (unsigned)XKeysymToKeycode(dpy, km->modifier)); + } else { + km->UseModifier = False; } - } - } else { - km->UseModifier = False; - } - - for (;;) { - key = strsep(&to, "|"); - if (key == NULL) - break; - - if ((ks = XStringToKeysym(key)) == NoSymbol) { - fprintf(stderr, "Invalid key: %s\n", key); - return NULL; - } - - code = XKeysymToKeycode(dpy, ks); - if (code == 0) { - fprintf(stderr, "WARNING: No keycode found for keysym " - "%s (0x%x) in mapping %s. Ignoring this " - "mapping.\n", - key, (unsigned int)ks, token); - return NULL; - } - km->to_keys = key_add_key(km->to_keys, code); - - if (debug) { - fprintf(stderr, "to \"%s\" (keysym 0x%x, key code %d)\n", key, - (unsigned)XStringToKeysym(key), (unsigned)code); - } - } - } else - fprintf(stderr, "WARNING: Mapping without = has no effect: '%s'\n", token); + for (;;) { + key = strsep(&to, "|"); + if (key == NULL) + break; + + if ((ks = XStringToKeysym(key)) == NoSymbol) { + fprintf(stderr, "Invalid key: %s\n", key); + return NULL; + } + + code = XKeysymToKeycode(dpy, ks); + if (code == 0) { + fprintf(stderr, + "WARNING: No keycode found for keysym " + "%s (0x%x) in mapping %s. Ignoring this " + "mapping.\n", + key, (unsigned int)ks, token); + return NULL; + } + km->to_keys = key_add_key(km->to_keys, code); + + if (debug) { + fprintf(stderr, "to \"%s\" (keysym 0x%x, key code %d)\n", key, + (unsigned)XStringToKeysym(key), (unsigned)code); + } + } + } else + fprintf(stderr, "WARNING: Mapping without = has no effect: '%s'\n", token); - return km; + return km; } -KeyMap_t *parse_mapping(Display *ctrl_conn, char *mapping, Bool debug) { - char *token; - KeyMap_t *rval, *km, *nkm; - - rval = km = NULL; - - for (;;) { - token = strsep(&mapping, ";"); - if (token == NULL) - break; +KeyMap_t* parse_mapping(Display* ctrl_conn, char* mapping, Bool debug) { + char* token; + KeyMap_t *rval, *km, *nkm; - nkm = parse_token(ctrl_conn, token, debug); + rval = km = NULL; - if (nkm != NULL) { - if (km == NULL) - rval = km = nkm; - else { - km->next = nkm; - km = nkm; - } + for (;;) { + token = strsep(&mapping, ";"); + if (token == NULL) + break; + + nkm = parse_token(ctrl_conn, token, debug); + + if (nkm != NULL) { + if (km == NULL) + rval = km = nkm; + else { + km->next = nkm; + km = nkm; + } + } } - } - return rval; + return rval; } -void delete_mapping(KeyMap_t *map) { - while (map != NULL) { - KeyMap_t *next = map->next; - delete_keys(map->to_keys); - free(map); - map = next; - } +void delete_mapping(KeyMap_t* map) { + while (map != NULL) { + KeyMap_t* next = map->next; + delete_keys(map->to_keys); + free(map); + map = next; + } } -void delete_keys(Key_t *keys) { - while (keys != NULL) { - Key_t *next = keys->next; - free(keys); - keys = next; - } +void delete_keys(Key_t* keys) { + while (keys != NULL) { + Key_t* next = keys->next; + free(keys); + keys = next; + } } -void print_usage(const char *program_name) { - fprintf(stdout, "Usage: %s [-d] [-t timeout_ms] [-e ]\n", - program_name); - fprintf(stdout, "Runs as a daemon unless -d flag is set\n"); +void print_usage(const char* program_name) { + fprintf(stdout, "Usage: %s [-d] [-t timeout_ms] [-e ]\n", program_name); + fprintf(stdout, "Runs as a daemon unless -d flag is set\n"); } From 9c2543b9d15405c6edad706be4a05f9bb3a446c1 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Mon, 16 Dec 2019 15:23:03 +0800 Subject: [PATCH 12/12] fix --- xcape.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/xcape.c b/xcape.c index 9487967..078f3e3 100644 --- a/xcape.c +++ b/xcape.c @@ -313,21 +313,12 @@ void handle_key(XCape_t* self, KeyMap_t* key, Bool mouse_pressed, int key_event) if (timercmp(&timev, &self->timeout, <)) { char buf[32], *keys = buf; XQueryKeymap(self->ctrl_conn, keys); - if (key->UseModifier) { - if (!BIT(keys, XKeysymToKeycode(self->ctrl_conn, key->modifier))) { - goto skip; - } - } else if (key->UseModifierCode) { - if (!BIT(keys, key->modifier_code)) { - goto skip; - } + printf("keys[12] = %d\n", keys[12]); + if (keys[12]) + { + XTestFakeKeyEvent(self->ctrl_conn, 50, True, 0); + self->generated = key_add_key(self->generated, 50); } - /* else { */ - /* for (int i = 0; i < 32; i++) */ - /* if (keys[i]) */ - /* goto skip; */ - /* } */ - /* if (key->from_kc == 108) system("copyq select 0"); */ for (k = key->to_keys; k != NULL; k = k->next) { if (self->debug) fprintf(stdout, "Generating %s!\n", @@ -336,6 +327,11 @@ void handle_key(XCape_t* self, KeyMap_t* key, Bool mouse_pressed, int key_event) XTestFakeKeyEvent(self->ctrl_conn, k->key, True, 0); self->generated = key_add_key(self->generated, k->key); } + if (keys[12]) + { + XTestFakeKeyEvent(self->ctrl_conn, 50, False, 0); + self->generated = key_add_key(self->generated, 50); + } for (k = key->to_keys; k != NULL; k = k->next) { XTestFakeKeyEvent(self->ctrl_conn, k->key, False, 0); self->generated = key_add_key(self->generated, k->key); @@ -343,7 +339,6 @@ void handle_key(XCape_t* self, KeyMap_t* key, Bool mouse_pressed, int key_event) XFlush(self->ctrl_conn); } } - skip: key->used = False; key->pressed = False; }