diff --git a/src/bindings.c b/src/bindings.c index 7a056adf..eec821b6 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -368,6 +368,7 @@ struct resolve { */ static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key, void *data) { const struct resolve *resolving = data; + struct xkb_state *numlock_state = resolving->xkb_state_numlock; xkb_keysym_t sym = xkb_state_key_get_one_sym(resolving->xkb_state, key); if (sym != resolving->keysym) { /* Check if Shift was specified, and try resolving the symbol without @@ -377,6 +378,11 @@ static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key, return; if (xkb_state_key_get_level(resolving->xkb_state, key, layout) > 1) return; + /* Skip the Shift fallback for keypad keys, otherwise one cannot bind + * KP_1 independent of KP_End. */ + if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_Equal) + return; + numlock_state = resolving->xkb_state_numlock_no_shift; sym = xkb_state_key_get_one_sym(resolving->xkb_state_no_shift, key); if (sym != resolving->keysym) return; @@ -403,9 +409,8 @@ static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key, * active. If so, grab the key with NumLock as well, so that users don’t * need to duplicate every key binding with an additional Mod2 specified. */ - xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(resolving->xkb_state_numlock, key); - xkb_keysym_t sym_numlock_no_shift = xkb_state_key_get_one_sym(resolving->xkb_state_numlock_no_shift, key); - if (sym_numlock == resolving->keysym || sym_numlock_no_shift == resolving->keysym) { + xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(numlock_state, key); + if (sym_numlock == resolving->keysym) { /* Also bind the key with active NumLock */ ADD_TRANSLATED_KEY(bind->event_state_mask | xcb_numlock_mask); diff --git a/testcases/t/264-keypress-numlock.t b/testcases/t/264-keypress-numlock.t index fa9caa61..45ec7e88 100644 --- a/testcases/t/264-keypress-numlock.t +++ b/testcases/t/264-keypress-numlock.t @@ -41,6 +41,9 @@ bindsym Escape nop Escape # Binding which should work with numlock and without, see issue #2418. bindsym Shift+Escape nop Shift+Escape + +# Binding which should work with numlock and without, see issue #2418. +bindsym Mod1+Shift+q nop Mod1+Shift+q EOT my $pid = launch_with_config($config); @@ -143,8 +146,39 @@ is(listen_for_binding( 'Shift+Escape', 'triggered the "Escape" keybinding'); +is(listen_for_binding( + sub { + xtest_key_press(50); # Shift_L + xtest_key_press(64); # Alt_L + xtest_key_press(24); # q + xtest_key_release(24); # q + xtest_key_release(64); # Alt_L + xtest_key_release(50); # Shift_L + }, + ), + 'Mod1+Shift+q', + 'triggered the "Mod1+Shift+q" keybinding'); + + +is(listen_for_binding( + sub { + xtest_key_press(77); # enable Num_Lock + xtest_key_release(77); # enable Num_Lock + xtest_key_press(50); # Shift_L + xtest_key_press(64); # Alt_L + xtest_key_press(24); # q + xtest_key_release(24); # q + xtest_key_release(64); # Alt_L + xtest_key_release(50); # Shift_L + xtest_key_press(77); # disable Num_Lock + xtest_key_release(77); # disable Num_Lock + }, + ), + 'Mod1+Shift+q', + 'triggered the "Mod1+Shift+q" keybinding'); + sync_with_i3; -is(scalar @i3test::XTEST::binding_events, 8, 'Received exactly 8 binding events'); +is(scalar @i3test::XTEST::binding_events, 10, 'Received exactly 10 binding events'); exit_gracefully($pid); @@ -188,7 +222,7 @@ is(listen_for_binding( # TODO: This test does not verify that i3 does _NOT_ grab keycode 87 with Mod2. sync_with_i3; -is(scalar @i3test::XTEST::binding_events, 9, 'Received exactly 9 binding events'); +is(scalar @i3test::XTEST::binding_events, 11, 'Received exactly 11 binding events'); exit_gracefully($pid);