commit bc1b768d391923290410d420f1045c799345f365
parent b464641cec963be7869fead5c73ebec53ce195c5
Author: Bastien Dejean <nihilhill@gmail.com>
Date: Sat, 5 Jan 2013 16:43:41 +0100
Add sequences keysyms
Diffstat:
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);
}
}