Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Support events replay

A new special keysym prefix character is introduced: ':'.
It allows clients to receive the events we grab.
  • Loading branch information...
commit 2f00b6836f2e7b9ce5c51a7ddd778f1ab58afb29 1 parent 278d76e
@baskerville authored
View
2  README.md
@@ -33,6 +33,8 @@ If `@` is added at the beginning of the keysym, the command will be run on key r
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`).
+If `:` is added at the beginning of the keysym, the captured event will be replayed for the other clients.
+
The keysym names are those your will get from `xev`.
Mouse hotkeys can be defined by using one of the following special keysym names: `button1`, `button2`, `button3`, ..., `button24`.
View
24 hotkeys.c
@@ -2380,9 +2380,9 @@ void grab_key_button_checked(xcb_keycode_t keycode, xcb_button_t button, uint16_
{
xcb_generic_error_t *err;
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));
+ err = xcb_request_check(dpy, xcb_grab_key_checked(dpy, true, root, modfield, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC));
else
- 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));
+ err = xcb_request_check(dpy, xcb_grab_button_checked(dpy, true, root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION, XCB_GRAB_MODE_SYNC, 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) {
@@ -2462,7 +2462,7 @@ xcb_keycode_t *keycodes_from_keysym(xcb_keysym_t keysym)
return result;
}
-bool parse_hotkey(char *string, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield, uint8_t *event_type) {
+bool parse_hotkey(char *string, xcb_keysym_t *keysym, xcb_button_t *button, uint16_t *modfield, uint8_t *event_type, bool *replay_event) {
char backup[MAXLEN];
strncpy(backup, string, sizeof(backup));
backup[strlen(string)] = '\0';
@@ -2473,6 +2473,9 @@ bool parse_hotkey(char *string, xcb_keysym_t *keysym, xcb_button_t *button, uint
} else if (name[0] == MOTION_PREFIX) {
*event_type = XCB_MOTION_NOTIFY;
name++;
+ } else if (name[0] == REPLAY_PREFIX) {
+ *replay_event = true;
+ name++;
}
if (!parse_modifier(name, modfield) && !parse_keysym(name, keysym) && !parse_button(name, button)) {
warn("Unrecognized key name: '%s'.\n", name);
@@ -2626,6 +2629,7 @@ void unfold_hotkeys(char *folded_hotkey, char *folded_command)
xcb_button_t button = XCB_NONE;
uint16_t modfield = 0;
uint8_t event_type = XCB_KEY_PRESS;
+ bool replay_event = false;
char *hk_ptr, *cmd_ptr;
char hk_a = 1, hk_z = 0, cmd_a = 1, cmd_z = 0;
char *hk_item = strtok_r(hotkey_sequence, SEQ_SEP, &hk_ptr);
@@ -2643,13 +2647,14 @@ void unfold_hotkeys(char *folded_hotkey, char *folded_command)
PREGEN(cmd_item, cmd_a, cmd_z, command_prefix, command_suffix, unfolded_command)
#undef PREGEN
- if (parse_hotkey(unfolded_hotkey, &keysym, &button, &modfield, &event_type))
- generate_hotkeys(keysym, button, modfield, event_type, unfolded_command);
+ if (parse_hotkey(unfolded_hotkey, &keysym, &button, &modfield, &event_type, &replay_event))
+ generate_hotkeys(keysym, button, modfield, event_type, replay_event, unfolded_command);
keysym = XCB_NO_SYMBOL;
button = XCB_NONE;
modfield = 0;
event_type = XCB_KEY_PRESS;
+ replay_event = false;
#define POSTGEN(elt, ra, rz, ptr) \
if (ra >= rz) \
@@ -2662,7 +2667,7 @@ void unfold_hotkeys(char *folded_hotkey, char *folded_command)
}
}
-void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, char *command)
+void generate_hotkeys(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, char *command)
{
if (button == XCB_NONE) {
xcb_keycode_t *keycodes = keycodes_from_keysym(keysym);
@@ -2674,7 +2679,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(Mode_switch) : 0);
uint16_t explicit_modfield = modfield | implicit_modfield;
- hotkey_t *hk = make_hotkey(natural_keysym, button, explicit_modfield, event_type, command);
+ hotkey_t *hk = make_hotkey(natural_keysym, button, explicit_modfield, event_type, replay_event, command);
add_hotkey(hk);
break;
}
@@ -2682,12 +2687,12 @@ 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_type, command);
+ hotkey_t *hk = make_hotkey(keysym, button, modfield, event_type, replay_event, command);
add_hotkey(hk);
}
}
-hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, char *command)
+hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, char *command)
{
PRINTF("hotkey %u %u %u %u %s\n", keysym, button, modfield, event_type, command);
hotkey_t *hk = malloc(sizeof(hotkey_t));
@@ -2698,6 +2703,7 @@ hotkey_t *make_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel
hk->event_type = key_to_button(event_type);
else
hk->event_type = event_type;
+ hk->replay_event = replay_event;
strncpy(hk->command, command, sizeof(hk->command));
hk->next = NULL;
return hk;
View
7 hotkeys.h
@@ -9,6 +9,7 @@
#define SEQ_MIN_LEN 3
#define RELEASE_PREFIX '@'
#define MOTION_PREFIX '!'
+#define REPLAY_PREFIX ':'
#define START_COMMENT '#'
#define TOK_SEP "+ \n"
#define SEQ_SEP ","
@@ -24,7 +25,7 @@ void grab_key_button_checked(xcb_keycode_t, xcb_button_t, uint16_t);
void ungrab(void);
int16_t modfield_from_keysym(xcb_keysym_t);
xcb_keycode_t *keycodes_from_keysym(xcb_keysym_t);
-bool parse_hotkey(char *, xcb_keysym_t *, xcb_button_t *, uint16_t *, uint8_t *);
+bool parse_hotkey(char *, xcb_keysym_t *, xcb_button_t *, uint16_t *, uint8_t *, bool *);
bool parse_keysym(char *, xcb_keysym_t *);
bool parse_button(char *, xcb_button_t *);
bool parse_modifier(char *, uint16_t *);
@@ -33,8 +34,8 @@ uint8_t key_to_button(uint8_t);
void get_standard_keysyms(void);
void get_lock_fields(void);
void unfold_hotkeys(char *, 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 *);
+void generate_hotkeys(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool, char *);
+hotkey_t *make_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t, bool, char *);
hotkey_t *find_hotkey(xcb_keysym_t, xcb_button_t, uint16_t, uint8_t);
void add_hotkey(hotkey_t *);
View
4 sxhkd.1
@@ -57,6 +57,10 @@ is added at the beginning of the keysym, the command will be run on motion notif
coordinates of the pointer relative to the root window referential (the only valid button keysyms for this type of hotkeys are:
.BR button1 ",…, " button5 ).
.PP
+If
+.I :
+is added at the beginning of the keysym, the captured event will be replayed for the other clients.
+.PP
The keysym names are those your will get from
.BR xev (1).
.PP
View
28 sxhkd.c
@@ -75,6 +75,7 @@ void load_config(char *config_file)
xcb_button_t button = XCB_NONE;
uint16_t modfield = 0;
uint8_t event_type = XCB_KEY_PRESS;
+ bool replay_event = false;
char folded_hotkey[MAXLEN] = {'\0'};
while (fgets(line, sizeof(line), cfg) != NULL) {
@@ -92,7 +93,7 @@ void load_config(char *config_file)
if (i < strlen(line)) {
char *command = line + i;
if (strlen(folded_hotkey) == 0)
- generate_hotkeys(keysym, button, modfield, event_type, command);
+ generate_hotkeys(keysym, button, modfield, event_type, replay_event, command);
else
unfold_hotkeys(folded_hotkey, command);
}
@@ -100,13 +101,14 @@ void load_config(char *config_file)
button = XCB_NONE;
modfield = 0;
event_type = XCB_KEY_PRESS;
+ replay_event = false;
folded_hotkey[0] = '\0';
} else {
unsigned int i = strlen(line) - 1;
while (i > 0 && isspace(line[i]))
line[i--] = '\0';
if (!parse_fold(line, folded_hotkey))
- parse_hotkey(line, &keysym, &button, &modfield, &event_type);
+ parse_hotkey(line, &keysym, &button, &modfield, &event_type, &replay_event);
}
}
@@ -118,6 +120,7 @@ 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;
+ bool replay_event = false;
uint16_t modfield = 0;
uint16_t lockfield = num_lock | caps_lock | scroll_lock;
if (event_type == XCB_KEY_PRESS) {
@@ -146,9 +149,28 @@ void key_button_event(xcb_generic_event_t *evt, uint8_t event_type)
modfield &= ~lockfield & MOD_STATE_FIELD;
if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) {
hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type);
- if (hk != NULL)
+ if (hk != NULL) {
run(hk->command);
+ replay_event = hk->replay_event;
+ }
+ }
+ switch (event_type) {
+ case XCB_BUTTON_PRESS:
+ case XCB_BUTTON_RELEASE:
+ if (replay_event)
+ xcb_allow_events(dpy, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
+ else
+ xcb_allow_events(dpy, XCB_ALLOW_ASYNC_POINTER, XCB_CURRENT_TIME);
+ break;
+ case XCB_KEY_PRESS:
+ case XCB_KEY_RELEASE:
+ if (replay_event)
+ xcb_allow_events(dpy, XCB_ALLOW_REPLAY_KEYBOARD, XCB_CURRENT_TIME);
+ else
+ xcb_allow_events(dpy, XCB_ALLOW_ASYNC_KEYBOARD, XCB_CURRENT_TIME);
+ break;
}
+ xcb_flush(dpy);
}
void motion_notify(xcb_generic_event_t *evt, uint8_t event_type)
View
1  sxhkd.h
@@ -19,6 +19,7 @@ struct hotkey_t {
xcb_button_t button;
uint16_t modfield;
uint8_t event_type;
+ bool replay_event;
char command[MAXLEN];
hotkey_t *next;
};
Please sign in to comment.
Something went wrong with that request. Please try again.