sxhkd-rc

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

commit 6f195e7a9953ddb8f4c5127031c310cf132ff543
parent 3d70f57823b06944a8e2d4b51b685b6b7de74b40
Author: Bastien Dejean <nihilhill@gmail.com>
Date:   Sat, 21 Sep 2013 17:46:46 +0200

Implement command cycles

The following binding:
    x
        echo {a-c}

will now generate the following output when *x* is pressed 4 times:
    a
    b
    c
    a

Diffstat:
Mgrab.c | 2+-
Mparse.c | 14++++++++++++++
Msxhkd.c | 11++++++-----
Msxhkd.h | 2+-
Mtypes.c | 31++++++++++++++++++++++++++-----
Mtypes.h | 8++++++++
6 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/grab.c b/grab.c @@ -4,7 +4,7 @@ void grab(void) { - for (hotkey_t *hk = hotkeys; hk != NULL; hk = hk->next) + for (hotkey_t *hk = hotkeys_head; hk != NULL; hk = hk->next) grab_chord(hk->chain->head); } diff --git a/parse.c b/parse.c @@ -2414,6 +2414,8 @@ void process_hotkey(char *hotkey_string, char *command_string) { char hotkey[MAXLEN] = {0}; char command[MAXLEN] = {0}; + char last_hotkey[MAXLEN] = {0}; + unsigned char num_same = 0; chunk_t *hk_chunks = extract_chunks(hotkey_string); chunk_t *cm_chunks = extract_chunks(command_string); if (hk_chunks == NULL) @@ -2430,6 +2432,8 @@ void process_hotkey(char *hotkey_string, char *command_string) if (parse_chain(hotkey, chain)) { hotkey_t *hk = make_hotkey(chain, command); add_hotkey(hk); + if (strcmp(hotkey, last_hotkey) == 0) + num_same++; } else { free(chain); } @@ -2437,9 +2441,19 @@ void process_hotkey(char *hotkey_string, char *command_string) if (hk_chunks == NULL && cm_chunks == NULL) break; + snprintf(last_hotkey, sizeof(last_hotkey), "%s", hotkey); + render_next(hk_chunks, hotkey); render_next(cm_chunks, command); } + + if (num_same > 0) { + int period = num_same + 1; + int delay = num_same; + for (hotkey_t *hk = hotkeys_tail; hk != NULL && delay >= 0; hk = hk->prev, delay--) + hk->cycle = make_cycle(delay, period); + } + if (hk_chunks != NULL) destroy_chunks(hk_chunks); if (cm_chunks != NULL) diff --git a/sxhkd.c b/sxhkd.c @@ -239,21 +239,22 @@ void setup(void) if ((shell = getenv(SXHKD_SHELL_ENV)) == NULL && (shell = getenv(SHELL_ENV)) == NULL) err("The '%s' environment variable is not defined.\n", SHELL_ENV); symbols = xcb_key_symbols_alloc(dpy); - hotkeys = hotkeys_tail = NULL; + hotkeys_head = hotkeys_tail = NULL; progress[0] = '\0'; } void cleanup(void) { PUTS("cleanup"); - hotkey_t *hk = hotkeys; + hotkey_t *hk = hotkeys_head; while (hk != NULL) { - hotkey_t *tmp = hk->next; + hotkey_t *next = hk->next; destroy_chain(hk->chain); + free(hk->cycle); free(hk); - hk = tmp; + hk = next; } - hotkeys = hotkeys_tail = NULL; + hotkeys_head = hotkeys_tail = NULL; } void reload_cmd(void) diff --git a/sxhkd.h b/sxhkd.h @@ -31,7 +31,7 @@ char progress[MAXLEN]; bool ignore_mapping; int timeout; -hotkey_t *hotkeys, *hotkeys_tail; +hotkey_t *hotkeys_head, *hotkeys_tail; bool running, reload, bell, chained, locked; chord_t *escape_chord; diff --git a/types.c b/types.c @@ -9,8 +9,9 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool *replay_event) { int num_active = 0; + hotkey_t *result = NULL; - for (hotkey_t *hk = hotkeys; hk != NULL; hk = hk->next) { + for (hotkey_t *hk = hotkeys_head; hk != NULL; hk = hk->next) { chain_t *c = hk->chain; if (chained && c->state == c->head) continue; @@ -31,6 +32,13 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel grab_chord(escape_chord); } if (c->state == c->tail) { + if (hk->cycle != NULL) { + unsigned char delay = hk->cycle->delay; + hk->cycle->delay = (delay == 0 ? hk->cycle->period - 1 : delay - 1); + if (delay == 0) + result = hk; + continue; + } if (chained && !locked) abort_chain(); return hk; @@ -47,6 +55,9 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel } } + if (result != NULL) + return result; + if (!chained) { if (num_active > 0) chained = true; @@ -142,21 +153,31 @@ chain_t *make_chain(void) return chain; } +cycle_t *make_cycle(int delay, int period) +{ + cycle_t *cycle = malloc(sizeof(cycle_t)); + cycle->delay = delay; + cycle->period = period; + return cycle; +} + hotkey_t *make_hotkey(chain_t *chain, char *command) { hotkey_t *hk = malloc(sizeof(hotkey_t)); hk->chain = chain; snprintf(hk->command, sizeof(hk->command), "%s", command); - hk->next = NULL; + hk->cycle = NULL; + hk->next = hk->prev = NULL; return hk; } void add_hotkey(hotkey_t *hk) { - if (hotkeys == NULL) { - hotkeys = hotkeys_tail = hk; + if (hotkeys_head == NULL) { + hotkeys_head = hotkeys_tail = hk; } else { hotkeys_tail->next = hk; + hk->prev = hotkeys_tail; hotkeys_tail = hk; } } @@ -164,7 +185,7 @@ void add_hotkey(hotkey_t *hk) void abort_chain(void) { PUTS("abort chain"); - for (hotkey_t *hk = hotkeys; hk != NULL; hk = hk->next) + for (hotkey_t *hk = hotkeys_head; hk != NULL; hk = hk->next) hk->chain->state = hk->chain->head; chained = false; locked = false; diff --git a/types.h b/types.h @@ -28,11 +28,18 @@ typedef struct { chord_t *state; } chain_t; +typedef struct { + int period; + int delay; +} cycle_t; + typedef struct hotkey_t hotkey_t; struct hotkey_t { chain_t *chain; char command[MAXLEN]; + cycle_t *cycle; hotkey_t *next; + hotkey_t *prev; }; typedef struct { @@ -45,6 +52,7 @@ xcb_keysym_t Alt_L, Alt_R, Super_L, Super_R, Hyper_L, Hyper_R, chord_t *make_chord(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool, bool); chain_t *make_chain(void); +cycle_t *make_cycle(int, int); void add_chord(chain_t *, chord_t *); bool match_chord(chord_t *, uint8_t, xcb_keysym_t, xcb_button_t, uint16_t); hotkey_t *find_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool *);