commit 3b80a888a4a54dd74671810925c7d871794d3234
parent 6f0985b4ec47db93b4bfce63f2ac87c305da2465
Author: Bastien Dejean <nihilhill@gmail.com>
Date: Tue, 8 Jan 2013 12:57:04 +0100
Add motion notify hotkeys
Diffstat:
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