sxhkd-rc

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

commit 23dc78d4203fd15653d5f9037d8711f7e1b675cb
parent 0722eceaa6f1bbce45013dc536d374a1829f4893
Author: Bastien Dejean <nihilhill@gmail.com>
Date:   Sat, 22 Mar 2014 17:12:45 +0100

Add root keysym prefix

Diffstat:
MMakefile | 3+++
Mdoc/sxhkd.1 | 38++++++++++++++++++++++++++++++--------
Mdoc/sxhkd.1.txt | 16++++++++++++----
Mparse.c | 13+++++++++++--
Mparse.h | 3++-
Msxhkd.c | 13+++++++------
Mtypes.c | 16+++++++++-------
Mtypes.h | 7++++---
8 files changed, 78 insertions(+), 31 deletions(-)

diff --git a/Makefile b/Makefile @@ -41,6 +41,9 @@ uninstall: rm -f "$(DESTDIR)$(BINPREFIX)"/$(NAME) rm -f "$(DESTDIR)$(MANPREFIX)"/man1/$(NAME).1 +deps: + $(CC) -MM *.c > Sourcedeps + doc: a2x -v -d manpage -f manpage -a revnumber=$(VERSION) doc/$(NAME).1.txt diff --git a/doc/sxhkd.1 b/doc/sxhkd.1 @@ -2,12 +2,12 @@ .\" Title: sxhkd .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> -.\" Date: 12/27/2013 +.\" Date: 03/22/2014 .\" Manual: Sxhkd Manual .\" Source: Sxhkd 0.5.3 .\" Language: English .\" -.TH "SXHKD" "1" "12/27/2013" "Sxhkd 0\&.5\&.3" "Sxhkd Manual" +.TH "SXHKD" "1" "03/22/2014" "Sxhkd 0\&.5\&.3" "Sxhkd Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -124,7 +124,7 @@ HOTKEY COMMAND HOTKEY := CHORD_1 ; CHORD_2 ; \&... ; CHORD_n -CHORD_i := [MODIFIER_i][@|!|~]KEYSYM_i +CHORD_i := [MODIFIER_i][@|!|~|/]KEYSYM_i MODIFIER_i := MODIFIER_i1 + MODIFIER_i2 + \&... + MODIFIER_ik .fi .if n \{\ @@ -141,11 +141,33 @@ When multiple chords are separated by semicolons, the hotkey is a chord chain: t .sp The colon character can be used instead of the semicolon to indicate that the chord chain shall not be aborted when the chain tail is reached\&. In which case, the \fIEscape\fR key can be used to manually abort the chain\&. .sp -If \fB@\fR is added at the beginning of the keysym, the command will be run on key release events, otherwise on key press events\&. -.sp -If \fB!\fR 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 \fIx\fR and \fIy\fR coordinates of the pointer relative to the root window referential (the only valid button keysyms for this type of hotkeys are: \fIbutton1\fR, \&..., \fIbutton5\fR)\&. -.sp -If \fB~\fR is added at the beginning of the keysym, the captured event will be replayed for the other clients\&. +The previously mentioned keysym prefixes have the following effects: +.PP +\fB@\fR +.RS 4 +The command will be run on key release events\&. +.RE +.PP +\fB!\fR +.RS 4 +The command will be run on motion notify events and must contain two integer conversion specifications which will be replaced by the +\fIx\fR +and +\fIy\fR +coordinates of the pointer relative to the root window referential (the only valid button keysyms for this type of hotkeys are: +\fIbutton1\fR, \&..., +\fIbutton5\fR)\&. +.RE +.PP +\fB~\fR +.RS 4 +The captured event will be replayed for the other clients\&. +.RE +.PP +\fB/\fR +.RS 4 +The command will only be executed if the pointer is above the root window\&. +.RE .sp Mouse hotkeys can be defined by using one of the following special keysym names: \fIbutton1\fR, \fIbutton2\fR, \fIbutton3\fR, \&..., \fIbutton24\fR\&. .sp diff --git a/doc/sxhkd.1.txt b/doc/sxhkd.1.txt @@ -64,7 +64,7 @@ HOTKEY COMMAND HOTKEY := CHORD_1 ; CHORD_2 ; … ; CHORD_n -CHORD_i := [MODIFIER_i][@|!|~]KEYSYM_i +CHORD_i := [MODIFIER_i][@|!|~|/]KEYSYM_i MODIFIER_i := MODIFIER_i1 + MODIFIER_i2 + … + MODIFIER_ik ---- @@ -78,11 +78,19 @@ When multiple chords are separated by semicolons, the hotkey is a chord chain: t The colon character can be used instead of the semicolon to indicate that the chord chain shall not be aborted when the chain tail is reached. In which case, the _Escape_ key can be used to manually abort the chain. -If *@* is added at the beginning of the keysym, the command will be run on key release events, otherwise on key press events. +The previously mentioned keysym prefixes have the following effects: -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 only valid button keysyms for this type of hotkeys are: _button1_, …, _button5_). +*@*:: + The command will be run on key release events. -If *~* is added at the beginning of the keysym, the captured event will be replayed for the other clients. +*!*:: + 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 only valid button keysyms for this type of hotkeys are: _button1_, …, _button5_). + +*~*:: + The captured event will be replayed for the other clients. + +*/*:: + The command will only be executed if the pointer is above the root window. Mouse hotkeys can be defined by using one of the following special keysym names: _button1_, _button2_, _button3_, …, _button24_. diff --git a/parse.c b/parse.c @@ -2413,27 +2413,31 @@ void load_config(const char *config_file) fclose(cfg); } -void parse_event(xcb_generic_event_t *evt, uint8_t event_type, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield) +void parse_event(xcb_generic_event_t *evt, uint8_t event_type, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield, bool *from_root) { if (event_type == XCB_KEY_PRESS) { xcb_key_press_event_t *e = (xcb_key_press_event_t *) evt; + *from_root = (e->child == XCB_NONE); xcb_keycode_t 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_type == XCB_KEY_RELEASE) { xcb_key_release_event_t *e = (xcb_key_release_event_t *) evt; + *from_root = (e->child == XCB_NONE); xcb_keycode_t keycode = e->detail; *modfield = e->state & ~modfield_from_keycode(keycode); *keysym = xcb_key_symbols_get_keysym(symbols, keycode, 0); PRINTF("key release %u %u\n", keycode, *modfield); } else if (event_type == XCB_BUTTON_PRESS) { xcb_button_press_event_t *e = (xcb_button_press_event_t *) evt; + *from_root = (e->child == XCB_NONE); *button = e->detail; *modfield = e->state; PRINTF("button press %u %u\n", *button, *modfield); } else if (event_type == XCB_BUTTON_RELEASE) { xcb_button_release_event_t *e = (xcb_button_release_event_t *) evt; + *from_root = (e->child == XCB_NONE); *button = e->detail; *modfield = e->state; PRINTF("button release %u %u\n", *button, *modfield); @@ -2655,6 +2659,7 @@ bool parse_chain(char *string, chain_t *chain) uint8_t event_type = XCB_KEY_PRESS; bool replay_event = false; bool lock_chain = false; + bool from_root = false; char *outer_advance; char *inner_advance; for (outer_advance = get_token(chord, ignored, string, LNK_SEP); chord[0] != '\0'; outer_advance = get_token(chord, ignored, outer_advance, LNK_SEP)) { @@ -2669,6 +2674,9 @@ bool parse_chain(char *string, chain_t *chain) } else if (name[0] == REPLAY_PREFIX) { replay_event = true; offset++; + } else if (name[0] == ROOT_PREFIX) { + from_root = true; + offset++; } char *nm = name + offset; if (!parse_modifier(nm, &modfield) && !parse_keysym(nm, &keysym) && !parse_button(nm, &button)) { @@ -2680,7 +2688,7 @@ bool parse_chain(char *string, chain_t *chain) lock_chain = true; if (button != XCB_NONE) event_type = key_to_button(event_type); - chord_t *c = make_chord(keysym, button, modfield, event_type, replay_event, lock_chain); + chord_t *c = make_chord(keysym, button, modfield, event_type, replay_event, lock_chain, from_root); add_chord(chain, c); if (status_fifo != NULL) snprintf(c->repr, sizeof(c->repr), "%s", chord); @@ -2690,6 +2698,7 @@ bool parse_chain(char *string, chain_t *chain) event_type = XCB_KEY_PRESS; replay_event = false; lock_chain = false; + from_root = false; } return true; } diff --git a/parse.h b/parse.h @@ -34,6 +34,7 @@ #define RELEASE_PREFIX '@' #define MOTION_PREFIX '!' #define REPLAY_PREFIX '~' +#define ROOT_PREFIX '/' #define START_COMMENT '#' #define MAGIC_INHIBIT '\\' #define PARTIAL_LINE '\\' @@ -60,7 +61,7 @@ xcb_keysym_t Alt_L, Alt_R, Super_L, Super_R, Hyper_L, Hyper_R, Meta_L, Meta_R, Mode_switch, Num_Lock, Scroll_Lock; void load_config(const char *config_file); -void parse_event(xcb_generic_event_t *evt, uint8_t event_type, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield); +void parse_event(xcb_generic_event_t *evt, uint8_t event_type, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield, bool *from_root); void process_hotkey(char *hotkey_string, char *command_string); char *get_token(char *dst, char *ign, char *src, char *sep); void render_next(chunk_t *chunks, char *dest); diff --git a/sxhkd.c b/sxhkd.c @@ -29,7 +29,6 @@ #include <xcb/xcb_event.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/select.h> @@ -119,7 +118,7 @@ int main(int argc, char *argv[]) setup(); get_standard_keysyms(); get_lock_fields(); - escape_chord = make_chord(ESCAPE_KEYSYM, XCB_NONE, 0, XCB_KEY_PRESS, false, false); + escape_chord = make_chord(ESCAPE_KEYSYM, XCB_NONE, 0, XCB_KEY_PRESS, false, false, false); load_config(config_file); for (int i = 0; i < num_extra_confs; i++) load_config(extra_confs[i]); @@ -200,12 +199,14 @@ void key_button_event(xcb_generic_event_t *evt, uint8_t event_type) xcb_keysym_t keysym = XCB_NO_SYMBOL; xcb_button_t button = XCB_NONE; bool replay_event = false; + bool from_root = false; uint16_t modfield = 0; uint16_t lockfield = num_lock | caps_lock | scroll_lock; - parse_event(evt, event_type, &keysym, &button, &modfield); + parse_event(evt, event_type, &keysym, &button, &modfield, &from_root); + PRINTF("from root: %u\n", from_root); modfield &= ~lockfield & MOD_STATE_FIELD; if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) { - hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type, &replay_event); + hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type, &replay_event, from_root); if (hk != NULL) { run(hk->command); if (status_fifo != NULL) @@ -246,7 +247,7 @@ void motion_notify(xcb_generic_event_t *evt, uint8_t event_type) buttonfield = buttonfield >> 1; button++; } - hotkey_t *hk = find_hotkey(XCB_NO_SYMBOL, button, modfield, event_type, NULL); + hotkey_t *hk = find_hotkey(XCB_NO_SYMBOL, button, modfield, event_type, NULL, false); if (hk != NULL) { char command[2 * MAXLEN]; snprintf(command, sizeof(command), hk->command, e->root_x, e->root_y); @@ -267,7 +268,7 @@ void mapping_notify(xcb_generic_event_t *evt) destroy_chord(escape_chord); get_lock_fields(); reload_cmd(); - escape_chord = make_chord(ESCAPE_KEYSYM, XCB_NONE, 0, XCB_KEY_PRESS, false, false); + escape_chord = make_chord(ESCAPE_KEYSYM, XCB_NONE, 0, XCB_KEY_PRESS, false, false, false); } } diff --git a/types.c b/types.c @@ -34,7 +34,7 @@ #include "grab.h" #include "types.h" -hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool *replay_event) +hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool *replay_event, bool from_root) { int num_active = 0; hotkey_t *result = NULL; @@ -43,7 +43,7 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel chain_t *c = hk->chain; if (chained && c->state == c->head) continue; - if (match_chord(c->state, event_type, keysym, button, modfield)) { + if (match_chord(c->state, event_type, keysym, button, modfield, from_root)) { if (status_fifo != NULL && num_active == 0) { if (!chained) { snprintf(progress, sizeof(progress), "%s", c->state->repr); @@ -91,9 +91,9 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel if (!chained) { if (num_active > 0) chained = true; - } else if (num_active == 0 || (locked && match_chord(escape_chord, event_type, keysym, button, modfield))) { + } else if (num_active == 0 || (locked && match_chord(escape_chord, event_type, keysym, button, modfield, from_root))) { abort_chain(); - return find_hotkey(keysym, button, modfield, event_type, replay_event); + return find_hotkey(keysym, button, modfield, event_type, replay_event, from_root); } if (chained && !locked && timeout > 0) alarm(timeout); @@ -102,15 +102,15 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel return NULL; } -bool match_chord(chord_t *chord, uint8_t event_type, xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield) +bool match_chord(chord_t *chord, uint8_t event_type, xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, bool from_root) { for (chord_t *c = chord; c != NULL; c = c->more) - if (c->event_type == event_type && c->keysym == keysym && c->button == button && c->modfield == modfield) + if (c->event_type == event_type && c->keysym == keysym && c->button == button && c->modfield == modfield && (!c->from_root || from_root)) return true; return false; } -chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, bool lock_chain) +chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, bool lock_chain, bool from_root) { chord_t *chord; if (button == XCB_NONE) { @@ -141,6 +141,7 @@ chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, chord->event_type = event_type; chord->replay_event = replay_event; chord->lock_chain = lock_chain; + chord->from_root = from_root; if (prev != NULL) prev->more = chord; else @@ -161,6 +162,7 @@ chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, chord->event_type = event_type; chord->replay_event = replay_event; chord->lock_chain = lock_chain; + chord->from_root = from_root; chord->next = chord->more = NULL; PRINTF("button chord %u %u\n", button, modfield); } diff --git a/types.h b/types.h @@ -46,6 +46,7 @@ struct chord_t { uint8_t event_type; bool replay_event; bool lock_chain; + bool from_root; chord_t *next; chord_t *more; }; @@ -78,9 +79,9 @@ typedef struct { xcb_keysym_t Alt_L, Alt_R, Super_L, Super_R, Hyper_L, Hyper_R, Meta_L, Meta_R, Mode_switch, Num_Lock, Scroll_Lock; -hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool *replay_event); -bool match_chord(chord_t *chord, uint8_t event_type, xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield); -chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, bool lock_chain); +hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool *replay_event, bool from_root); +bool match_chord(chord_t *chord, uint8_t event_type, xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, bool from_root); +chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, bool lock_chain, bool from_root); void add_chord(chain_t *chain, chord_t *chord); chain_t *make_chain(void); cycle_t *make_cycle(int delay, int period);