diff --git a/include/key-state.h b/include/key-state.h new file mode 100644 index 00000000..1e7e5410 --- /dev/null +++ b/include/key-state.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LABWC_KEY_STATE_H +#define __LABWC_KEY_STATE_H + +void key_state_set_pressed(uint32_t keycode, bool ispressed); +void key_state_store_pressed_keys_as_bound(void); +bool key_state_corresponding_press_event_was_bound(uint32_t keycode); +void key_state_bound_key_remove(uint32_t keycode); + +#endif /* __LABWC_KEY_STATE_H */ diff --git a/src/key-state.c b/src/key-state.c new file mode 100644 index 00000000..9b50f33e --- /dev/null +++ b/src/key-state.c @@ -0,0 +1,69 @@ +#include +#include +#include + +#define MAX_PRESSED_KEYS (16) + +struct key_array { + uint32_t keys[MAX_PRESSED_KEYS]; + int nr_keys; +}; + +static struct key_array pressed, bound; + +static void +remove_key(struct key_array *array, uint32_t keycode) +{ + bool shifting = false; + + for (int i = 0; i < MAX_PRESSED_KEYS; ++i) { + if (array->keys[i] == keycode) { + --array->nr_keys; + shifting = true; + } + if (shifting) { + array->keys[i] = i < MAX_PRESSED_KEYS - 1 + ? array->keys[i + 1] : 0; + } + } +} + +static void +add_key(struct key_array *array, uint32_t keycode) +{ + array->keys[array->nr_keys++] = keycode; +} + +void +key_state_set_pressed(uint32_t keycode, bool ispressed) +{ + if (ispressed) { + add_key(&pressed, keycode); + } else { + remove_key(&pressed, keycode); + } +} + +void +key_state_store_pressed_keys_as_bound(void) +{ + memcpy(bound.keys, pressed.keys, MAX_PRESSED_KEYS * sizeof(uint32_t)); + bound.nr_keys = pressed.nr_keys; +} + +bool +key_state_corresponding_press_event_was_bound(uint32_t keycode) +{ + for (int i = 0; i < bound.nr_keys; ++i) { + if (bound.keys[i] == keycode) { + return true; + } + } + return false; +} + +void +key_state_bound_key_remove(uint32_t keycode) +{ + remove_key(&bound, keycode); +} diff --git a/src/keyboard.c b/src/keyboard.c index 2e6873bc..5508f872 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include +#include "key-state.h" #include "labwc.h" static void @@ -101,6 +102,19 @@ handle_compositor_keybindings(struct wl_listener *listener, bool handled = false; + key_state_set_pressed(keycode, + event->state == WL_KEYBOARD_KEY_STATE_PRESSED); + + /* + * If a press event was handled by a compositor binding, then do not + * forward the corresponding release event to clients + */ + if (key_state_corresponding_press_event_was_bound(keycode) + && event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { + key_state_bound_key_remove(keycode); + return true; + } + uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); @@ -152,6 +166,11 @@ handle_compositor_keybindings(struct wl_listener *listener, handled |= handle_keybinding(server, modifiers, syms[i]); } } + + if (handled) { + key_state_store_pressed_keys_as_bound(); + } + return handled; } diff --git a/src/meson.build b/src/meson.build index 947f80e0..cb761362 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,6 +6,7 @@ labwc_sources = files( 'foreign.c', 'interactive.c', 'keyboard.c', + 'key-state.c', 'layers.c', 'main.c', 'osd.c',