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:
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 *);