sxhkd-rc

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

commit 3b80a888a4a54dd74671810925c7d871794d3234
parent 6f0985b4ec47db93b4bfce63f2ac87c305da2465
Author: Bastien Dejean <nihilhill@gmail.com>
Date:   Tue,  8 Jan 2013 12:57:04 +0100

Add motion notify hotkeys

Diffstat:
MREADME.md | 4+++-
Mhelpers.c | 6++++++
Mhelpers.h | 1+
Mkeys.c | 32++++++++++++++++----------------
Mkeys.h | 11++++++-----
Msxhkd.1 | 8+++++++-
Msxhkd.c | 62+++++++++++++++++++++++++++++++++++++++++++-------------------
Msxhkd.h | 5+++--
8 files changed, 85 insertions(+), 44 deletions(-)

diff --git a/README.md b/README.md @@ -23,13 +23,15 @@ Each line of the configuration file is interpreted as so: General syntax: - [MODIFIER + ]*[@]KEYSYM + [MODIFIER + ]*[@|!]KEYSYM COMMAND Where `MODIFIER` is one of the following names: `super`, `hyper`, `meta`, `alt`, `control`, `ctrl`, `shift`, `mode_switch`, `lock`, `mod1`, `mod2`, `mod3`, `mod4`, `mod5`. If `@` is added at the beginning of the keysym, the command will be run on key release events, otherwise on key press events. +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 keysym names are those your will get from `xev` (minus the prefix if any). Mouse hotkeys can be defined by using one of the following special keysym names: `button1`, `button2`, `button3`, ..., `button24`. diff --git a/helpers.c b/helpers.c @@ -40,3 +40,9 @@ void spawn(char *cmd[]) } wait(NULL); } + +void run(char *command) +{ + char *cmd[] = {shell, "-c", command, NULL}; + spawn(cmd); +} diff --git a/helpers.h b/helpers.h @@ -16,5 +16,6 @@ void warn(char *, ...); __attribute__((noreturn)) void err(char *, ...); void spawn(char *[]); +void run(char *); #endif diff --git a/keys.c b/keys.c @@ -2374,7 +2374,7 @@ void grab_key_button_checked(xcb_keycode_t keycode, xcb_button_t button, uint16_ 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)); else - err = xcb_request_check(dpy, xcb_grab_button_checked(dpy, false, root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, button, modfield)); + 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)); unsigned int value = (button == XCB_NONE ? keycode : button); char *type = (button == XCB_NONE ? "key" : "button"); if (err != NULL) { @@ -2527,13 +2527,13 @@ bool parse_fold(char *name, char *folded_keysym) return false; } -xcb_event_mask_t key_to_mouse(xcb_event_mask_t event_mask) +uint8_t key_to_button(uint8_t event_type) { - if (event_mask == XCB_KEY_PRESS) + if (event_type == XCB_KEY_PRESS) return XCB_BUTTON_PRESS; - else if (event_mask == XCB_KEY_RELEASE) + else if (event_type == XCB_KEY_RELEASE) return XCB_BUTTON_RELEASE; - return event_mask; + return event_type; } void get_lock_fields(void) @@ -2559,7 +2559,7 @@ bool extract_sequence(char *string, char *prefix, char *sequence, char *suffix) return true; } -void unfold_hotkeys(char *folded_keysym, uint16_t modfield, xcb_event_mask_t event_mask, char *folded_command) +void unfold_hotkeys(char *folded_keysym, uint16_t modfield, uint8_t event_type, char *folded_command) { char keysym_sequence[MAXLEN]; char keysym_prefix[MAXLEN]; @@ -2593,7 +2593,7 @@ void unfold_hotkeys(char *folded_keysym, uint16_t modfield, xcb_event_mask_t eve else snprintf(unfolded_command, sizeof(unfolded_command), "%s%s%s", command_prefix, cmd_item, command_suffix); if (parse_key(unfolded_keysym, &keysym) || parse_button(unfolded_keysym, &button)) - generate_hotkeys(keysym, button, modfield, event_mask, unfolded_command); + generate_hotkeys(keysym, button, modfield, event_type, unfolded_command); else warn("Unknown sequence keysym: '%s'.\n", ks_item); if (ks_a >= ks_z) @@ -2607,7 +2607,7 @@ void unfold_hotkeys(char *folded_keysym, uint16_t modfield, xcb_event_mask_t eve } } -void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, xcb_event_mask_t event_mask, char *command) +void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, char *command) { if (button == XCB_NONE) { xcb_keycode_t *keycodes = keycodes_from_keysym(keysym); @@ -2619,7 +2619,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(XK_Mode_switch) : 0); uint16_t explicit_modfield = modfield | implicit_modfield; - hotkey_t *hk = make_hotkey(natural_keysym, button, explicit_modfield, event_mask, command); + hotkey_t *hk = make_hotkey(natural_keysym, button, explicit_modfield, event_type, command); add_hotkey(hk); break; } @@ -2627,31 +2627,31 @@ 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_mask, command); + hotkey_t *hk = make_hotkey(keysym, button, modfield, event_type, command); add_hotkey(hk); } } -hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, xcb_event_mask_t event_mask, char *command) +hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, char *command) { - PRINTF("hotkey %u %u %u %u %s\n", keysym, button, modfield, event_mask, command); + PRINTF("hotkey %u %u %u %u %s\n", keysym, button, modfield, event_type, command); hotkey_t *hk = malloc(sizeof(hotkey_t)); hk->keysym = keysym; hk->button = button; hk->modfield = modfield; if (button != XCB_NONE) - hk->event_mask = key_to_mouse(event_mask); + hk->event_type = key_to_button(event_type); else - hk->event_mask = event_mask; + hk->event_type = event_type; strncpy(hk->command, command, sizeof(hk->command)); hk->next = NULL; return hk; } -hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, xcb_event_mask_t event_mask) +hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type) { for (hotkey_t *hk = hotkeys; hk != NULL; hk = hk->next) - if (hk->keysym == keysym && hk->button == button && hk->modfield == modfield && hk->event_mask == event_mask) + if (hk->keysym == keysym && hk->button == button && hk->modfield == modfield && hk->event_type == event_type) return hk; return NULL; } diff --git a/keys.h b/keys.h @@ -8,6 +8,7 @@ #define NUM_MOD 8 #define SEQ_MIN_LEN 3 #define RELEASE_PREFIX '@' +#define MOTION_PREFIX '!' #define START_COMMENT '#' #define TOK_SEP "+ \n" #define SEQ_SEP "," @@ -24,12 +25,12 @@ bool parse_key(char *, xcb_keysym_t *); bool parse_button(char *, xcb_button_t *); bool parse_modifier(char *, uint16_t *); bool parse_fold(char *, char *); -xcb_event_mask_t key_to_mouse(xcb_event_mask_t); +uint8_t key_to_button(uint8_t); void get_lock_fields(void); -void unfold_hotkeys(char *, uint16_t, xcb_event_mask_t, char *); -void generate_hotkeys(xcb_keysym_t, xcb_button_t, uint16_t, xcb_event_mask_t, char *); -hotkey_t *make_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, xcb_event_mask_t, char *); -hotkey_t *find_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, xcb_event_mask_t); +void unfold_hotkeys(char *, uint16_t, uint8_t, 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 *); +hotkey_t *find_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t); void add_hotkey(hotkey_t *); #endif diff --git a/sxhkd.1 b/sxhkd.1 @@ -34,7 +34,7 @@ characters. .PP General Syntax: .EX - [MODIFIER + ]*[@]KEYSYM + [MODIFIER + ]*[@|!]KEYSYM COMMAND .EE .PP @@ -47,6 +47,12 @@ If .I @ is added at the beginning of the keysym, the command will be run on key release events, otherwise on key press events. .PP +If +.I ! +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 +.BR x " and " y +coordinates of the pointer relative to the root window referential. +.PP The keysym names are those your will get from .BR xev (1) (minus the prefix if any). diff --git a/sxhkd.c b/sxhkd.c @@ -79,7 +79,7 @@ void load_config(char *config_file) xcb_keysym_t keysym = XCB_NO_SYMBOL; xcb_button_t button = XCB_NONE; uint16_t modfield = 0; - xcb_event_mask_t event_mask = XCB_KEY_PRESS; + uint8_t event_type = XCB_KEY_PRESS; char folded_keysym[MAXLEN] = {'\0'}; while (fgets(line, sizeof(line), cfg) != NULL) { @@ -97,14 +97,14 @@ void load_config(char *config_file) if (i < strlen(line)) { char *command = line + i; if (strlen(folded_keysym) == 0) - generate_hotkeys(keysym, button, modfield, event_mask, command); + generate_hotkeys(keysym, button, modfield, event_type, command); else - unfold_hotkeys(folded_keysym, modfield, event_mask, command); + unfold_hotkeys(folded_keysym, modfield, event_type, command); } keysym = XCB_NO_SYMBOL; button = XCB_NONE; modfield = 0; - event_mask = XCB_KEY_PRESS; + event_type = XCB_KEY_PRESS; folded_keysym[0] = '\0'; } else { char *name = strtok(line, TOK_SEP); @@ -112,7 +112,10 @@ void load_config(char *config_file) continue; do { if (name[0] == RELEASE_PREFIX) { - event_mask = XCB_KEY_RELEASE; + event_type = XCB_KEY_RELEASE; + name++; + } else if (name[0] == MOTION_PREFIX) { + event_type = XCB_MOTION_NOTIFY; name++; } if (!parse_modifier(name, &modfield) && !parse_key(name, &keysym) && !parse_button(name, &button) && !parse_fold(name, folded_keysym)) { @@ -141,31 +144,31 @@ void mapping_notify(xcb_generic_event_t *evt) } } -void key_button_event(xcb_generic_event_t *evt, xcb_event_mask_t event_mask) +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; uint16_t modfield = 0; uint16_t lockfield = num_lock | caps_lock | scroll_lock; - if (event_mask == XCB_KEY_PRESS) { + if (event_type == XCB_KEY_PRESS) { xcb_key_press_event_t *e = (xcb_key_press_event_t *) evt; keycode = e->detail; modfield = e->state; keysym = xcb_key_symbols_get_keysym(symbols, keycode, 0); PRINTF("key press %u %u\n", keycode, modfield); - } else if (event_mask == XCB_KEY_RELEASE) { + } else if (event_type == XCB_KEY_RELEASE) { xcb_key_release_event_t *e = (xcb_key_release_event_t *) evt; keycode = e->detail; modfield = e->state; keysym = xcb_key_symbols_get_keysym(symbols, keycode, 0); PRINTF("key release %u %u\n", keycode, modfield); - } else if (event_mask == XCB_BUTTON_PRESS) { + } else if (event_type == XCB_BUTTON_PRESS) { xcb_button_press_event_t *e = (xcb_button_press_event_t *) evt; button = e->detail; modfield = e->state; PRINTF("button press %u %u\n", button, modfield); - } else if (event_mask == XCB_BUTTON_RELEASE) { + } else if (event_type == XCB_BUTTON_RELEASE) { xcb_button_release_event_t *e = (xcb_button_release_event_t *) evt; button = e->detail; modfield = e->state; @@ -173,11 +176,29 @@ void key_button_event(xcb_generic_event_t *evt, xcb_event_mask_t event_mask) } modfield &= ~lockfield & MOD_STATE_FIELD; if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) { - hotkey_t *hk = find_hotkey(keysym, button, modfield, event_mask); - if (hk != NULL) { - char *cmd[] = {shell, "-c", hk->command, NULL}; - spawn(cmd); - } + hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type); + if (hk != NULL) + run(hk->command); + } +} + +void motion_notify(xcb_generic_event_t *evt, uint8_t event_type) +{ + xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt; + /* PRINTF("motion notify %X %X %u\n", e->child, e->detail, e->state); */ + uint16_t lockfield = num_lock | caps_lock | scroll_lock; + uint16_t buttonfield = e->state >> 8; + uint16_t modfield = e->state & ~lockfield & MOD_STATE_FIELD; + xcb_button_t button = 1; + while (~buttonfield & 1) { + buttonfield = buttonfield >> 1; + button++; + } + hotkey_t *hk = find_hotkey(XCB_NO_SYMBOL, button, modfield, event_type); + if (hk != NULL) { + char command[MAXLEN]; + snprintf(command, sizeof(command), hk->command, e->root_x, e->root_y); + run(command); } } @@ -243,19 +264,22 @@ int main(int argc, char *argv[]) if (select(fd + 1, &descriptors, NULL, NULL, NULL) > 0) { while ((evt = xcb_poll_for_event(dpy)) != NULL) { - uint8_t event_mask = XCB_EVENT_RESPONSE_TYPE(evt); - switch (event_mask) { + uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(evt); + switch (event_type) { case XCB_KEY_PRESS: case XCB_KEY_RELEASE: case XCB_BUTTON_PRESS: case XCB_BUTTON_RELEASE: - key_button_event(evt, event_mask); + key_button_event(evt, event_type); + break; + case XCB_MOTION_NOTIFY: + motion_notify(evt, event_type); break; case XCB_MAPPING_NOTIFY: mapping_notify(evt); break; default: - PRINTF("unknown event %u\n", event_mask); + PRINTF("unknown event %u\n", event_type); break; } free(evt); diff --git a/sxhkd.h b/sxhkd.h @@ -18,7 +18,7 @@ struct hotkey_t { xcb_keysym_t keysym; xcb_button_t button; uint16_t modfield; - xcb_event_mask_t event_mask; + uint8_t event_type; char command[MAXLEN]; hotkey_t *next; }; @@ -51,6 +51,7 @@ void cleanup(void); void reload_all(void); void load_config(char *config_file); void mapping_notify(xcb_generic_event_t *); -void key_event(xcb_generic_event_t *, xcb_event_mask_t); +void key_event(xcb_generic_event_t *, uint8_t); +void motion_notify(xcb_generic_event_t *, uint8_t); #endif