sxhkd-rc

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

commit bc1b768d391923290410d420f1045c799345f365
parent b464641cec963be7869fead5c73ebec53ce195c5
Author: Bastien Dejean <nihilhill@gmail.com>
Date:   Sat,  5 Jan 2013 16:43:41 +0100

Add sequences keysyms

Diffstat:
MMakefile | 4++--
MREADME.md | 2++
Mexamples/sxhkdrc | 3+++
Mkeys.c | 35++++++++++++++++++++++++++++++++++-
Mkeys.h | 9+++++++++
Msxhkd.c | 18+++++++++++-------
6 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,7 +2,7 @@ VERSION = 0.1 CC = gcc LIBS = -lm -lxcb -lxcb-keysyms -CFLAGS = -std=c99 -pedantic -Wall -Wextra -DVERSION=\"$(VERSION)\" +CFLAGS = -std=c99 -pedantic -Wall -Wextra -D_POSIX_SOURCE -DVERSION=\"$(VERSION)\" LDFLAGS = $(LIBS) PREFIX ?= /usr/local @@ -28,7 +28,7 @@ options: .c.o: @echo "CC $<" - @$(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -c -o $@ $< + @$(CC) $(CFLAGS) -c -o $@ $< sxhkd: $(OBJ) @echo CC -o $@ diff --git a/README.md b/README.md @@ -34,6 +34,8 @@ 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`. +`KEYSYM` can also be a sequence of the form `{KEYSYM_1,KEYSYM_2,...,KEYSYM_N}`, in which case, `COMMAND` must also contain a sequence with *N* elements: the pairing of the two sequences generates *N* hotkeys. + What is actually executed is `/bin/sh -c COMMAND`, which means you can use environment variables in `COMMAND`. If *sxhkd* receives a `SIGUSR1` signal, it will reload its configuration file. diff --git a/examples/sxhkdrc b/examples/sxhkdrc @@ -22,4 +22,7 @@ super + shift + equal button8 bspc toggle_visibility +super + {h,j,k,l} + bspc focus {left,down,up,right} + # vim: set ft=conf: diff --git a/keys.c b/keys.c @@ -2535,6 +2535,36 @@ void get_lock_fields(void) PRINTF("lock fields %u %u %u\n", num_lock, caps_lock, scroll_lock); } +void unfold_hotkeys(char *keysym_seq, uint16_t modfield, xcb_event_mask_t event_mask, char *command) +{ + char *begin = strchr(command, SEQ_BEGIN[0]); + char *end = strrchr(command, SEQ_END[0]); + if (begin == NULL || end == NULL || ((end - begin - 1) < SEQ_MIN_LEN)) { + warn("Invalid sequence for command '%s'.\n", command); + return; + } + char *ks_ptr, *cmd_ptr; + char unfolded_command[MAXLEN]; + char command_seq[MAXLEN]; + char command_prefix[MAXLEN]; + char command_suffix[MAXLEN]; + strncpy(command_seq, begin + 1, end - begin - 1); + strncpy(command_prefix, command, begin - command); + strncpy(command_suffix, end + 1, strlen(command) - (1 + end - command)); + command_seq[end - begin - 1] = '\0'; + command_prefix[begin - command] = '\0'; + command_suffix[strlen(command) - (1 + end - command)] = '\0'; + xcb_keysym_t keysym = XCB_NO_SYMBOL; + xcb_button_t button = XCB_NONE; + for (char *ks_item = strtok_r(keysym_seq, SEQ_SEP, &ks_ptr), *cmd_item = strtok_r(command_seq, SEQ_SEP, &cmd_ptr); ks_item != NULL && cmd_item != NULL; ks_item = strtok_r(NULL, SEQ_SEP, &ks_ptr), cmd_item = strtok_r(NULL, SEQ_SEP, &cmd_ptr)) { + snprintf(unfolded_command, sizeof(unfolded_command), "%s%s%s", command_prefix, cmd_item, command_suffix); + if (parse_key(ks_item, &keysym) || parse_button(ks_item, &button)) + generate_hotkeys(keysym, button, modfield, event_mask, unfolded_command); + else + warn("Unknown sequence keysym: '%s'.\n", ks_item); + } +} + void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, xcb_event_mask_t event_mask, char *command) { if (button == XCB_NONE) { @@ -2567,7 +2597,10 @@ hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel hk->keysym = keysym; hk->button = button; hk->modfield = modfield; - hk->event_mask = event_mask; + if (button != XCB_NONE) + hk->event_mask = key_to_mouse(event_mask); + else + hk->event_mask = event_mask; strncpy(hk->command, command, sizeof(hk->command)); hk->next = NULL; return hk; diff --git a/keys.h b/keys.h @@ -4,6 +4,14 @@ #include "sxhkd.h" #define KEYSYMS_PER_KEYCODE 4 +#define NUM_MOD 8 +#define SEQ_MIN_LEN 3 +#define RELEASE_PREFIX '@' +#define START_COMMENT '#' +#define TOK_SEP "+ \n" +#define SEQ_SEP "," +#define SEQ_BEGIN "{" +#define SEQ_END "}" void grab(void); void grab_key_button(xcb_keycode_t, xcb_button_t, uint16_t); @@ -16,6 +24,7 @@ bool parse_button(char *, xcb_button_t *); bool parse_modifier(char *, uint16_t *); xcb_event_mask_t key_to_mouse(xcb_event_mask_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); diff --git a/sxhkd.c b/sxhkd.c @@ -73,15 +73,14 @@ void load_config(void) xcb_button_t button = XCB_NONE; uint16_t modfield = 0; xcb_event_mask_t event_mask = XCB_KEY_PRESS; + char keysym_seq[MAXLEN] = {'\0'}; while (fgets(line, sizeof(line), cfg) != NULL) { - if (strlen(line) < 2 || line[0] == '#') { + if (strlen(line) < 2 || line[0] == START_COMMENT) { continue; } else if (isspace(line[0])) { - if (keysym == XCB_NO_SYMBOL && button == XCB_NONE) + if (keysym == XCB_NO_SYMBOL && button == XCB_NONE && strlen(keysym_seq) == 0) continue; - if (button != XCB_NONE) - event_mask = key_to_mouse(event_mask); unsigned int i = strlen(line) - 1; while (i > 0 && isspace(line[i])) line[i--] = '\0'; @@ -90,23 +89,28 @@ void load_config(void) i++; if (i < strlen(line)) { char *command = line + i; - generate_hotkeys(keysym, button, modfield, event_mask, command); + if (strlen(keysym_seq) == 0) + generate_hotkeys(keysym, button, modfield, event_mask, command); + else + unfold_hotkeys(keysym_seq, modfield, event_mask, command); } keysym = XCB_NO_SYMBOL; button = XCB_NONE; modfield = 0; event_mask = XCB_KEY_PRESS; + keysym_seq[0] = '\0'; } else { char *name = strtok(line, TOK_SEP); if (name == NULL) continue; do { - if (name[0] == '@') { + if (name[0] == RELEASE_PREFIX) { event_mask = XCB_KEY_RELEASE; name++; } - if (!parse_modifier(name, &modfield) && !parse_key(name, &keysym) && !parse_button(name, &button)) + if (!parse_modifier(name, &modfield) && !parse_key(name, &keysym) && !parse_button(name, &button) && !(sscanf(name, SEQ_BEGIN"%s"SEQ_END, keysym_seq) == 1)) { warn("Unrecognized key name: '%s'.\n", name); + } } while ((name = strtok(NULL, TOK_SEP)) != NULL); } }