Keep shortcut repeat through unrelated releases
0a5f86f13dc4bd6c574f216a5850b705168fa632
1 parent
1ebc9753
swm.c
+21 -9
| 252 | 252 | /* Physical or virtual keyboard group. */ |
|
| 253 | 253 | typedef struct { |
|
| 254 | 254 | struct wlr_keyboard_group *wlr_group; |
|
| 255 | 255 | bool is_virtual; |
|
| 256 | 256 | int nsyms; |
|
| 257 | - | const xkb_keysym_t *keysyms; /* Valid only when nsyms is nonzero. */ |
|
| 258 | - | uint32_t mods; /* Valid only when nsyms is nonzero. */ |
|
| 257 | + | uint32_t repeat_keycode; /* Valid only when nsyms is nonzero. */ |
|
| 258 | + | const xkb_keysym_t *keysyms; /* Valid only when nsyms is nonzero. */ |
|
| 259 | + | uint32_t mods; /* Valid only when nsyms is nonzero. */ |
|
| 259 | 260 | struct wl_event_source *key_repeat_source; |
|
| 260 | 261 | uint32_t handled_keys[(KEY_CNT + 31) / 32]; |
|
| 261 | 262 | struct wl_listener modifiers; |
|
| 262 | 263 | struct wl_listener key; |
|
| 263 | 264 | struct wl_listener destroy; |
| 3844 | 3845 | } |
|
| 3845 | 3846 | return true; |
|
| 3846 | 3847 | } |
|
| 3847 | 3848 | /* Arm shortcut repeat after a repeatable compositor binding is pressed. */ |
|
| 3848 | 3849 | static void key_repeat_begin( |
|
| 3849 | - | keyboard_group_t *group, const xkb_keysym_t *syms, int nsyms, uint32_t mods |
|
| 3850 | + | keyboard_group_t *group, const xkb_keysym_t *syms, int nsyms, uint32_t mods, uint32_t keycode |
|
| 3850 | 3851 | ) { |
|
| 3851 | - | group->nsyms = nsyms; |
|
| 3852 | - | group->keysyms = syms; |
|
| 3853 | - | group->mods = mods; |
|
| 3852 | + | group->nsyms = nsyms; |
|
| 3853 | + | group->keysyms = syms; |
|
| 3854 | + | group->mods = mods; |
|
| 3855 | + | group->repeat_keycode = keycode; |
|
| 3854 | 3856 | wl_event_source_timer_update( |
|
| 3855 | 3857 | group->key_repeat_source, group->wlr_group->keyboard.repeat_info.delay |
|
| 3856 | 3858 | ); |
|
| 3857 | 3859 | } |
|
| 3858 | 3860 | ||
| 3861 | + | /* Return whether this event supersedes the active shortcut repeat. */ |
|
| 3862 | + | static bool key_repeat_should_stop( |
|
| 3863 | + | keyboard_group_t *group, const struct wlr_keyboard_key_event *event |
|
| 3864 | + | ) { |
|
| 3865 | + | if (!group->nsyms) |
|
| 3866 | + | return false; |
|
| 3867 | + | return event->state == WL_KEYBOARD_KEY_STATE_PRESSED || event->keycode == group->repeat_keycode; |
|
| 3868 | + | } |
|
| 3869 | + | ||
| 3859 | 3870 | /* Handle shortcuts and forward unhandled key events to the focused application. */ |
|
| 3860 | 3871 | void key_press(struct wl_listener *listener, void *data) { |
|
| 3861 | 3872 | int i; |
|
| 3862 | 3873 | ||
| 3863 | 3874 | /* This event is raised when a key is pressed or released. */ |
| 3879 | 3890 | if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { |
|
| 3880 | 3891 | for (i = 0; i < nsyms; i++) |
|
| 3881 | 3892 | handled |= key_binding(mods, syms[i], 0); |
|
| 3882 | 3893 | } |
|
| 3883 | 3894 | if ((handled & 2) && group->wlr_group->keyboard.repeat_info.delay > 0) |
|
| 3884 | - | key_repeat_begin(group, syms, nsyms, mods); |
|
| 3885 | - | else { |
|
| 3886 | - | group->nsyms = 0; |
|
| 3895 | + | key_repeat_begin(group, syms, nsyms, mods, event->keycode); |
|
| 3896 | + | else if (key_repeat_should_stop(group, event)) { |
|
| 3897 | + | group->nsyms = 0; |
|
| 3898 | + | group->repeat_keycode = 0; |
|
| 3887 | 3899 | wl_event_source_timer_update(group->key_repeat_source, 0); |
|
| 3888 | 3900 | } |
|
| 3889 | 3901 | if (!key_event_should_forward(group, event->keycode, event->state, handled)) |
|
| 3890 | 3902 | return; |
|
| 3891 | 3903 |
test/unit.c
+9 -1
| 1115 | 1115 | group.wlr_group = &keyboard_group; |
|
| 1116 | 1116 | keyboard_group.keyboard.repeat_info.rate = 25; |
|
| 1117 | 1117 | keyboard_group.keyboard.repeat_info.delay = 300; |
|
| 1118 | 1118 | group.key_repeat_source = wl_event_loop_add_timer(loop, key_repeat, &group); |
|
| 1119 | 1119 | assert(group.key_repeat_source); |
|
| 1120 | - | key_repeat_begin(&group, &symbol, 1, MOD); |
|
| 1120 | + | key_repeat_begin(&group, &symbol, 1, MOD, KEY_J); |
|
| 1121 | 1121 | assert(group.nsyms == 1); |
|
| 1122 | 1122 | assert(group.keysyms == &symbol); |
|
| 1123 | 1123 | assert(group.mods == MOD); |
|
| 1124 | + | assert(group.repeat_keycode == KEY_J); |
|
| 1125 | + | assert(!key_repeat_should_stop( |
|
| 1126 | + | &group, |
|
| 1127 | + | &(struct wlr_keyboard_key_event){ |
|
| 1128 | + | .keycode = KEY_K, |
|
| 1129 | + | .state = WL_KEYBOARD_KEY_STATE_RELEASED, |
|
| 1130 | + | } |
|
| 1131 | + | )); |
|
| 1124 | 1132 | assert(key_repeat(&group) == 0); |
|
| 1125 | 1133 | wl_event_source_remove(group.key_repeat_source); |
|
| 1126 | 1134 | wl_event_loop_destroy(loop); |
|
| 1127 | 1135 | } |
|
| 1128 | 1136 |