]> git.sur5r.net Git - i3/i3/commitdiff
ignore modifiers for KeyRelease bindings
authorMichael Stapelberg <michael@stapelberg.de>
Thu, 6 Sep 2012 15:24:30 +0000 (17:24 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Thu, 6 Sep 2012 15:24:30 +0000 (17:24 +0200)
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

include/data.h
src/cfgparse.y
src/config.c

index 4b886ae8cfd3bae1c0be0bc1f8e8d7ee4c2c72b8..e8df78c7e65f5bc2d36aab4b36525f7d45a9c805 100644 (file)
@@ -202,7 +202,17 @@ struct regex {
 struct Binding {
     /** If true, the binding should be executed upon a KeyRelease event, not a
      * 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 don’t 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
      * stored with the binding to be able to re-convert it into a keycode
index 5c1667784cd44aacdb80e64313150f12d5f67a09..f175c720e5b96bf36e85de7c38380f58e9d769fe 100644 (file)
@@ -913,8 +913,8 @@ bindsym:
     ;
 
 optional_release:
-    /* empty */ { $$ = false; }
-    | TOK_RELEASE  { $$ = true; }
+    /* empty */ { $$ = B_UPON_KEYPRESS; }
+    | TOK_RELEASE  { $$ = B_UPON_KEYRELEASE; }
     ;
 
 for_window:
index 41491d8676aede6759cd296083a2040ada9f9d9d..fcf3841ed3be21387a334deef437e974d4c82171 100644 (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 *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) {
-        /* First compare the modifiers */
-        if (bind->mods != modifiers)
+        /* First compare the modifiers (unless this is a
+         * 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;
 
         /* 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;
 
         /* If a symbol was specified by the user, we need to look in