Ignore KeyRelease events without KeyPress
Patch status: rejected
Patch by Ari Edelkind
Long description:
When switching modes, i3 completely reconfigures the key bindings.
There's a bug, such that if a mode is set up with the likes of:
mode "new" {
bindsym --release $mykey mode "busted"
}
bindsym $mykey mode "new"
then i3 would switch to mode "new" when $mykey is pressed, and then to
"busted" when $mykey is released.
This patch fixes the bug by ensuring that, before a KeyRelease event
will be acknowledged, a key has been pressed since the key bindings have
been reconfigured.
To apply this patch, use:
curl http://cr.i3wm.org/patch/530/raw.patch | git am
b/src/bindings.c
| 27 |
@@ -15,6 +15,12 @@ |
| 28 |
const char *DEFAULT_BINDING_MODE = "default"; |
| 29 |
|
| 30 |
/* |
| 31 |
+ * Whether a key has been pressed since reconfiguring keybindings |
| 32 |
+ * |
| 33 |
+ */ |
| 34 |
+static bool key_pressed_in_bind_config; |
| 35 |
+ |
| 36 |
+/* |
| 37 |
* Returns the mode specified by `name` or creates a new mode and adds it to |
| 38 |
* the list of modes. |
| 39 |
* |
| 40 |
@@ -104,6 +110,7 @@ static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint |
| 41 |
*/ |
| 42 |
void grab_all_keys(xcb_connection_t *conn, bool bind_mode_switch) {
|
| 43 |
Binding *bind; |
| 44 |
+ key_pressed_in_bind_config = 0; |
| 45 |
TAILQ_FOREACH(bind, bindings, bindings) {
|
| 46 |
if (bind->input_type != B_KEYBOARD || |
| 47 |
(bind_mode_switch && (bind->mods & BIND_MODE_SWITCH) == 0) || |
| 48 |
@@ -131,6 +138,7 @@ Binding *get_keyboard_binding(uint16_t modifiers, bool key_release, xcb_keycode_ |
| 49 |
Binding *bind; |
| 50 |
|
| 51 |
if (!key_release) {
|
| 52 |
+ key_pressed_in_bind_config = 1; |
| 53 |
/* On a KeyPress event, we first reset all |
| 54 |
* B_UPON_KEYRELEASE_IGNORE_MODS bindings back to B_UPON_KEYRELEASE */ |
| 55 |
TAILQ_FOREACH(bind, bindings, bindings) {
|
| 56 |
@@ -181,7 +189,21 @@ Binding *get_keyboard_binding(uint16_t modifiers, bool key_release, xcb_keycode_ |
| 57 |
break; |
| 58 |
} |
| 59 |
|
| 60 |
- return (bind == TAILQ_END(bindings) ? NULL : bind); |
| 61 |
+ if (bind == TAILQ_END(bindings)) |
| 62 |
+ return NULL; |
| 63 |
+ |
| 64 |
+ if (key_release) {
|
| 65 |
+ /* If we see a KeyRelease event without a KeyPress event, that means |
| 66 |
+ * we've reconfigured our keybindings (e.g. switched modes), and a new |
| 67 |
+ * keybinding was created with the same key combination as the one that |
| 68 |
+ * triggered the change. */ |
| 69 |
+ if (!key_pressed_in_bind_config) {
|
| 70 |
+ DLOG("Ignored KeyRelease for key not pressed in this binding configuration\n");
|
| 71 |
+ return NULL; |
| 72 |
+ } |
| 73 |
+ } |
| 74 |
+ |
| 75 |
+ return bind; |
| 76 |
} |
| 77 |
|
| 78 |
/* |