sxhkd-rc

[fork] simple X hotkey daemon (but for the rc shell)
Log | Files | Refs | README | LICENSE

commit 2f00b6836f2e7b9ce5c51a7ddd778f1ab58afb29
parent 278d76e618e7c0515d641b56e1e7d511cfcbeb8d
Author: Bastien Dejean <nihilhill@gmail.com>
Date:   Fri, 22 Mar 2013 16:43:48 +0100

Support events replay

A new special keysym prefix character is introduced: ':'.
It allows clients to receive the events we grab.

Diffstat:
MREADME.md | 2++
Mhotkeys.c | 24+++++++++++++++---------
Mhotkeys.h | 7++++---
Msxhkd.1 | 4++++
Msxhkd.c | 28+++++++++++++++++++++++++---
Msxhkd.h | 1+
6 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/README.md b/README.md @@ -33,6 +33,8 @@ If `@` is added at the beginning of the keysym, the command will be run on key r If `!` is added at the beginning of the keysym, the command will be run on motion notify events and must contain two integer conversion specifications which will be replaced by the *x* and *y* coordinates of the pointer relative to the root window referential (the only valid button keysyms for this type of hotkeys are: `button1`, ..., `button5`). +If `:` is added at the beginning of the keysym, the captured event will be replayed for the other clients. + The keysym names are those your will get from `xev`. Mouse hotkeys can be defined by using one of the following special keysym names: `button1`, `button2`, `button3`, ..., `button24`. diff --git a/hotkeys.c b/hotkeys.c @@ -2380,9 +2380,9 @@ void grab_key_button_checked(xcb_keycode_t keycode, xcb_button_t button, uint16_ { xcb_generic_error_t *err; if (button == XCB_NONE) - err = xcb_request_check(dpy, xcb_grab_key_checked(dpy, false, root, modfield, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC)); + err = xcb_request_check(dpy, xcb_grab_key_checked(dpy, true, root, modfield, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC)); else - err = xcb_request_check(dpy, xcb_grab_button_checked(dpy, false, root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, button, modfield)); + err = xcb_request_check(dpy, xcb_grab_button_checked(dpy, true, root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, button, modfield)); unsigned int value = (button == XCB_NONE ? keycode : button); char *type = (button == XCB_NONE ? "key" : "button"); if (err != NULL) { @@ -2462,7 +2462,7 @@ xcb_keycode_t *keycodes_from_keysym(xcb_keysym_t keysym) return result; } -bool parse_hotkey(char *string, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield, uint8_t *event_type) { +bool parse_hotkey(char *string, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield, uint8_t *event_type, bool *replay_event) { char backup[MAXLEN]; strncpy(backup, string, sizeof(backup)); backup[strlen(string)] = '\0'; @@ -2473,6 +2473,9 @@ bool parse_hotkey(char *string, xcb_keysym_t *keysym, xcb_button_t *button, uint } else if (name[0] == MOTION_PREFIX) { *event_type = XCB_MOTION_NOTIFY; name++; + } else if (name[0] == REPLAY_PREFIX) { + *replay_event = true; + name++; } if (!parse_modifier(name, modfield) && !parse_keysym(name, keysym) && !parse_button(name, button)) { warn("Unrecognized key name: '%s'.\n", name); @@ -2626,6 +2629,7 @@ void unfold_hotkeys(char *folded_hotkey, char *folded_command) xcb_button_t button = XCB_NONE; uint16_t modfield = 0; uint8_t event_type = XCB_KEY_PRESS; + bool replay_event = false; char *hk_ptr, *cmd_ptr; char hk_a = 1, hk_z = 0, cmd_a = 1, cmd_z = 0; char *hk_item = strtok_r(hotkey_sequence, SEQ_SEP, &hk_ptr); @@ -2643,13 +2647,14 @@ void unfold_hotkeys(char *folded_hotkey, char *folded_command) PREGEN(cmd_item, cmd_a, cmd_z, command_prefix, command_suffix, unfolded_command) #undef PREGEN - if (parse_hotkey(unfolded_hotkey, &keysym, &button, &modfield, &event_type)) - generate_hotkeys(keysym, button, modfield, event_type, unfolded_command); + if (parse_hotkey(unfolded_hotkey, &keysym, &button, &modfield, &event_type, &replay_event)) + generate_hotkeys(keysym, button, modfield, event_type, replay_event, unfolded_command); keysym = XCB_NO_SYMBOL; button = XCB_NONE; modfield = 0; event_type = XCB_KEY_PRESS; + replay_event = false; #define POSTGEN(elt, ra, rz, ptr) \ if (ra >= rz) \ @@ -2662,7 +2667,7 @@ void unfold_hotkeys(char *folded_hotkey, char *folded_command) } } -void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, char *command) +void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, char *command) { if (button == XCB_NONE) { xcb_keycode_t *keycodes = keycodes_from_keysym(keysym); @@ -2674,7 +2679,7 @@ void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel if (ks == keysym) { uint16_t implicit_modfield = (col & 1 ? XCB_MOD_MASK_SHIFT : 0) | (col & 2 ? modfield_from_keysym(Mode_switch) : 0); uint16_t explicit_modfield = modfield | implicit_modfield; - hotkey_t *hk = make_hotkey(natural_keysym, button, explicit_modfield, event_type, command); + hotkey_t *hk = make_hotkey(natural_keysym, button, explicit_modfield, event_type, replay_event, command); add_hotkey(hk); break; } @@ -2682,12 +2687,12 @@ void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel } free(keycodes); } else { - hotkey_t *hk = make_hotkey(keysym, button, modfield, event_type, command); + hotkey_t *hk = make_hotkey(keysym, button, modfield, event_type, replay_event, command); add_hotkey(hk); } } -hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, char *command) +hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, char *command) { PRINTF("hotkey %u %u %u %u %s\n", keysym, button, modfield, event_type, command); hotkey_t *hk = malloc(sizeof(hotkey_t)); @@ -2698,6 +2703,7 @@ hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel hk->event_type = key_to_button(event_type); else hk->event_type = event_type; + hk->replay_event = replay_event; strncpy(hk->command, command, sizeof(hk->command)); hk->next = NULL; return hk; diff --git a/hotkeys.h b/hotkeys.h @@ -9,6 +9,7 @@ #define SEQ_MIN_LEN 3 #define RELEASE_PREFIX '@' #define MOTION_PREFIX '!' +#define REPLAY_PREFIX ':' #define START_COMMENT '#' #define TOK_SEP "+ \n" #define SEQ_SEP "," @@ -24,7 +25,7 @@ void grab_key_button_checked(xcb_keycode_t, xcb_button_t, uint16_t); void ungrab(void); int16_t modfield_from_keysym(xcb_keysym_t); xcb_keycode_t *keycodes_from_keysym(xcb_keysym_t); -bool parse_hotkey(char *, xcb_keysym_t *, xcb_button_t *, uint16_t *, uint8_t *); +bool parse_hotkey(char *, xcb_keysym_t *, xcb_button_t *, uint16_t *, uint8_t *, bool *); bool parse_keysym(char *, xcb_keysym_t *); bool parse_button(char *, xcb_button_t *); bool parse_modifier(char *, uint16_t *); @@ -33,8 +34,8 @@ uint8_t key_to_button(uint8_t); void get_standard_keysyms(void); void get_lock_fields(void); void unfold_hotkeys(char *, char *); -void generate_hotkeys(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, char *); -hotkey_t *make_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, char *); +void generate_hotkeys(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool, char *); +hotkey_t *make_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool, char *); hotkey_t *find_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t); void add_hotkey(hotkey_t *); diff --git a/sxhkd.1 b/sxhkd.1 @@ -57,6 +57,10 @@ is added at the beginning of the keysym, the command will be run on motion notif coordinates of the pointer relative to the root window referential (the only valid button keysyms for this type of hotkeys are: .BR button1 ",…, " button5 ). .PP +If +.I : +is added at the beginning of the keysym, the captured event will be replayed for the other clients. +.PP The keysym names are those your will get from .BR xev (1). .PP diff --git a/sxhkd.c b/sxhkd.c @@ -75,6 +75,7 @@ void load_config(char *config_file) xcb_button_t button = XCB_NONE; uint16_t modfield = 0; uint8_t event_type = XCB_KEY_PRESS; + bool replay_event = false; char folded_hotkey[MAXLEN] = {'\0'}; while (fgets(line, sizeof(line), cfg) != NULL) { @@ -92,7 +93,7 @@ void load_config(char *config_file) if (i < strlen(line)) { char *command = line + i; if (strlen(folded_hotkey) == 0) - generate_hotkeys(keysym, button, modfield, event_type, command); + generate_hotkeys(keysym, button, modfield, event_type, replay_event, command); else unfold_hotkeys(folded_hotkey, command); } @@ -100,13 +101,14 @@ void load_config(char *config_file) button = XCB_NONE; modfield = 0; event_type = XCB_KEY_PRESS; + replay_event = false; folded_hotkey[0] = '\0'; } else { unsigned int i = strlen(line) - 1; while (i > 0 && isspace(line[i])) line[i--] = '\0'; if (!parse_fold(line, folded_hotkey)) - parse_hotkey(line, &keysym, &button, &modfield, &event_type); + parse_hotkey(line, &keysym, &button, &modfield, &event_type, &replay_event); } } @@ -118,6 +120,7 @@ void key_button_event(xcb_generic_event_t *evt, uint8_t event_type) xcb_keysym_t keysym = XCB_NO_SYMBOL; xcb_keycode_t keycode = XCB_NONE; xcb_button_t button = XCB_NONE; + bool replay_event = false; uint16_t modfield = 0; uint16_t lockfield = num_lock | caps_lock | scroll_lock; if (event_type == XCB_KEY_PRESS) { @@ -146,9 +149,28 @@ void key_button_event(xcb_generic_event_t *evt, uint8_t event_type) modfield &= ~lockfield & MOD_STATE_FIELD; if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) { hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type); - if (hk != NULL) + if (hk != NULL) { run(hk->command); + replay_event = hk->replay_event; + } + } + switch (event_type) { + case XCB_BUTTON_PRESS: + case XCB_BUTTON_RELEASE: + if (replay_event) + xcb_allow_events(dpy, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME); + else + xcb_allow_events(dpy, XCB_ALLOW_ASYNC_POINTER, XCB_CURRENT_TIME); + break; + case XCB_KEY_PRESS: + case XCB_KEY_RELEASE: + if (replay_event) + xcb_allow_events(dpy, XCB_ALLOW_REPLAY_KEYBOARD, XCB_CURRENT_TIME); + else + xcb_allow_events(dpy, XCB_ALLOW_ASYNC_KEYBOARD, XCB_CURRENT_TIME); + break; } + xcb_flush(dpy); } void motion_notify(xcb_generic_event_t *evt, uint8_t event_type) diff --git a/sxhkd.h b/sxhkd.h @@ -19,6 +19,7 @@ struct hotkey_t { xcb_button_t button; uint16_t modfield; uint8_t event_type; + bool replay_event; char command[MAXLEN]; hotkey_t *next; };