ignore modifiers for KeyRelease bindings

For the following binding:

    # Simulate ctrl+v upon pressing $mod+x
    bindsym --release $mod+x exec --no-startup-id xdotool key --clearmodifiers ctrl+v

you can now use either:
1. press $mod, press x, release x, release $mod
2. press $mod, press x, release $mod, release x

fixes #485
This commit is contained in:
Michael Stapelberg 2012-09-06 17:24:30 +02:00
parent c6c6d3a952
commit 548d74015c
3 changed files with 38 additions and 6 deletions

View File

@ -202,7 +202,17 @@ struct regex {
struct Binding { struct Binding {
/** If true, the binding should be executed upon a KeyRelease event, not a /** If true, the binding should be executed upon a KeyRelease event, not a
* KeyPress (the default). */ * KeyPress (the default). */
bool release; enum {
/* This binding will only be executed upon KeyPress events */
B_UPON_KEYPRESS = 0,
/* This binding will be executed either upon a KeyRelease event, or… */
B_UPON_KEYRELEASE = 1,
/* …upon a KeyRelease event, even if the modifiers dont match. This
* state is triggered from get_binding() when the corresponding
* KeyPress (!) happens, so that users can release the modifier keys
* before releasing the actual key. */
B_UPON_KEYRELEASE_IGNORE_MODS = 2,
} release;
/** Symbol the user specified in configfile, if any. This needs to be /** Symbol the user specified in configfile, if any. This needs to be
* stored with the binding to be able to re-convert it into a keycode * stored with the binding to be able to re-convert it into a keycode

View File

@ -913,8 +913,8 @@ bindsym:
; ;
optional_release: optional_release:
/* empty */ { $$ = false; } /* empty */ { $$ = B_UPON_KEYPRESS; }
| TOK_RELEASE { $$ = true; } | TOK_RELEASE { $$ = B_UPON_KEYRELEASE; }
; ;
for_window: for_window:

View File

@ -57,13 +57,35 @@ static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint
Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode) { Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode) {
Binding *bind; Binding *bind;
if (!key_release) {
/* On a KeyPress event, we first reset all
* B_UPON_KEYRELEASE_IGNORE_MODS bindings back to B_UPON_KEYRELEASE */
TAILQ_FOREACH(bind, bindings, bindings) {
if (bind->release == B_UPON_KEYRELEASE_IGNORE_MODS)
bind->release = B_UPON_KEYRELEASE;
}
/* Then we transition the KeyRelease bindings into a state where the
* modifiers no longer matter for the KeyRelease event so that users
* can release the modifier key before releasing the actual key. */
TAILQ_FOREACH(bind, bindings, bindings) {
if (bind->release == B_UPON_KEYRELEASE && !key_release)
bind->release = B_UPON_KEYRELEASE_IGNORE_MODS;
}
}
TAILQ_FOREACH(bind, bindings, bindings) { TAILQ_FOREACH(bind, bindings, bindings) {
/* First compare the modifiers */ /* First compare the modifiers (unless this is a
if (bind->mods != modifiers) * B_UPON_KEYRELEASE_IGNORE_MODS binding and this is a KeyRelease
* event) */
if (bind->mods != modifiers &&
(bind->release != B_UPON_KEYRELEASE_IGNORE_MODS ||
!key_release))
continue; continue;
/* Check if the binding is for a KeyPress or a KeyRelease event */ /* Check if the binding is for a KeyPress or a KeyRelease event */
if (bind->release != key_release) if ((bind->release == B_UPON_KEYPRESS && key_release) ||
(bind->release >= B_UPON_KEYRELEASE && !key_release))
continue; continue;
/* If a symbol was specified by the user, we need to look in /* If a symbol was specified by the user, we need to look in