diff --git a/include/types/wlr_keyboard.h b/include/types/wlr_keyboard.h new file mode 100644 index 00000000..e28462b5 --- /dev/null +++ b/include/types/wlr_keyboard.h @@ -0,0 +1,8 @@ +#include "wlr/types/wlr_keyboard.h" + +void keyboard_key_update(struct wlr_keyboard *keyboard, + struct wlr_event_keyboard_key *event); + +bool keyboard_modifier_update(struct wlr_keyboard *keyboard); + +void keyboard_led_update(struct wlr_keyboard *keyboard); diff --git a/include/wlr/types/wlr_keyboard_group.h b/include/wlr/types/wlr_keyboard_group.h index 023887f3..0b3df226 100644 --- a/include/wlr/types/wlr_keyboard_group.h +++ b/include/wlr/types/wlr_keyboard_group.h @@ -18,6 +18,30 @@ struct wlr_keyboard_group { struct wlr_input_device *input_device; struct wl_list devices; // keyboard_group_device::link struct wl_list keys; // keyboard_group_key::link + + struct { + /* + * Sent when a keyboard has entered the group with keys currently + * pressed that are not pressed by any other keyboard in the group. The + * data for this signal will be a wl_array containing the key codes. + * This should be used to update the compositor's internal state. + * Bindings should not be triggered based off of these key codes and + * they should also not notify any surfaces of the key press. + */ + struct wl_signal enter; + + /* + * Sent when a keyboard has left the group with keys currently pressed + * that are not pressed by any other keyboard in the group. The data for + * this signal will be a wl_array containing the key codes. This should + * be used to update the compositor's internal state. Bindings should + * not be triggered based off of these key codes. Additionally, surfaces + * should only be notified if they received a corresponding key press + * for the key code. + */ + struct wl_signal leave; + } events; + void *data; }; diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index 72b8eab5..50363fed 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -6,9 +6,10 @@ #include #include #include +#include "types/wlr_keyboard.h" #include "util/signal.h" -static void keyboard_led_update(struct wlr_keyboard *keyboard) { +void keyboard_led_update(struct wlr_keyboard *keyboard) { if (keyboard->xkb_state == NULL) { return; } @@ -27,7 +28,7 @@ static void keyboard_led_update(struct wlr_keyboard *keyboard) { * Update the modifier state of the wlr-keyboard. Returns true if the modifier * state changed. */ -static bool keyboard_modifier_update(struct wlr_keyboard *keyboard) { +bool keyboard_modifier_update(struct wlr_keyboard *keyboard) { if (keyboard->xkb_state == NULL) { return false; } @@ -55,7 +56,7 @@ static bool keyboard_modifier_update(struct wlr_keyboard *keyboard) { return true; } -static void keyboard_key_update(struct wlr_keyboard *keyboard, +void keyboard_key_update(struct wlr_keyboard *keyboard, struct wlr_event_keyboard_key *event) { if (event->state == WLR_KEY_PRESSED) { set_add(keyboard->keycodes, &keyboard->num_keycodes, diff --git a/types/wlr_keyboard_group.c b/types/wlr_keyboard_group.c index 059a4767..ace1fcd2 100644 --- a/types/wlr_keyboard_group.c +++ b/types/wlr_keyboard_group.c @@ -5,6 +5,8 @@ #include #include #include +#include "types/wlr_keyboard.h" +#include "util/signal.h" #include "wlr/interfaces/wlr_keyboard.h" #include "wlr/types/wlr_keyboard.h" #include "wlr/types/wlr_keyboard_group.h" @@ -70,6 +72,9 @@ struct wlr_keyboard_group *wlr_keyboard_group_create(void) { wl_list_init(&group->devices); wl_list_init(&group->keys); + wl_signal_init(&group->events.enter); + wl_signal_init(&group->events.leave); + return group; } @@ -81,11 +86,9 @@ struct wlr_keyboard_group *wlr_keyboard_group_from_wlr_keyboard( return (struct wlr_keyboard_group *)keyboard; } -static void handle_keyboard_key(struct wl_listener *listener, void *data) { - struct keyboard_group_device *group_device = - wl_container_of(listener, group_device, key); +static bool process_key(struct keyboard_group_device *group_device, + struct wlr_event_keyboard_key *event) { struct wlr_keyboard_group *group = group_device->keyboard->group; - struct wlr_event_keyboard_key *event = data; struct keyboard_group_key *key, *tmp; wl_list_for_each_safe(key, tmp, &group->keys, link) { @@ -94,12 +97,12 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { } if (event->state == WLR_KEY_PRESSED) { key->count++; - return; + return false; } if (event->state == WLR_KEY_RELEASED) { key->count--; if (key->count > 0) { - return; + return false; } wl_list_remove(&key->link); free(key); @@ -112,14 +115,22 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { calloc(1, sizeof(struct keyboard_group_key)); if (!key) { wlr_log(WLR_ERROR, "Failed to allocate keyboard_group_key"); - return; + return false; } key->keycode = event->keycode; key->count = 1; wl_list_insert(&group->keys, &key->link); } - wlr_keyboard_notify_key(&group_device->keyboard->group->keyboard, data); + return true; +} + +static void handle_keyboard_key(struct wl_listener *listener, void *data) { + struct keyboard_group_device *group_device = + wl_container_of(listener, group_device, key); + if (process_key(group_device, data)) { + wlr_keyboard_notify_key(&group_device->keyboard->group->keyboard, data); + } } static void handle_keyboard_modifiers(struct wl_listener *listener, @@ -189,6 +200,9 @@ static void handle_keyboard_repeat_info(struct wl_listener *listener, static void refresh_state(struct keyboard_group_device *device, enum wlr_key_state state) { + struct wl_array keys; + wl_array_init(&keys); + for (size_t i = 0; i < device->keyboard->num_keycodes; i++) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -198,8 +212,31 @@ static void refresh_state(struct keyboard_group_device *device, .update_state = true, .state = state }; - handle_keyboard_key(&device->key, &event); + + // Update the group's key state and determine whether this is a unique + // key that needs to be passed on to the compositor + if (process_key(device, &event)) { + // Update state for wlr_keyboard_group's keyboard + keyboard_key_update(&device->keyboard->group->keyboard, &event); + keyboard_modifier_update(&device->keyboard->group->keyboard); + keyboard_led_update(&device->keyboard->group->keyboard); + + // Add the key to the array + uint32_t *key = wl_array_add(&keys, sizeof(uint32_t)); + *key = event.keycode; + } } + + // If there are any unique keys, emit the enter/leave event + if (keys.size > 0) { + if (state == WLR_KEY_PRESSED) { + wlr_signal_emit_safe(&device->keyboard->group->events.enter, &keys); + } else { + wlr_signal_emit_safe(&device->keyboard->group->events.leave, &keys); + } + } + + wl_array_release(&keys); } static void remove_keyboard_group_device(struct keyboard_group_device *device) { @@ -298,6 +335,8 @@ void wlr_keyboard_group_destroy(struct wlr_keyboard_group *group) { } wlr_keyboard_destroy(&group->keyboard); wl_list_remove(&group->input_device->events.destroy.listener_list); + wl_list_remove(&group->events.enter.listener_list); + wl_list_remove(&group->events.leave.listener_list); free(group->input_device); free(group); }