diff --git a/include/rootston/input.h b/include/rootston/input.h index b9af5028..5cd7509e 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -16,6 +16,7 @@ struct roots_keyboard { struct roots_input *input; struct wlr_input_device *device; struct wl_listener key; + struct wl_listener modifiers; struct wl_list link; xkb_keysym_t pressed_keysyms[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index f5d5c357..d241175b 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -14,7 +14,6 @@ struct wlr_seat_handle { struct wl_resource *wl_resource; struct wlr_seat *wlr_seat; - struct wlr_seat_keyboard *seat_keyboard; struct wl_resource *pointer; struct wl_resource *keyboard; @@ -87,21 +86,16 @@ struct wlr_seat_pointer_state { struct wl_listener resource_destroy; }; -struct wlr_seat_keyboard { - struct wlr_seat *seat; - struct wlr_keyboard *keyboard; - struct wl_listener key; - struct wl_listener modifiers; - struct wl_listener keymap; - struct wl_listener destroy; - struct wl_list link; -}; - struct wlr_seat_keyboard_state { struct wlr_seat *wlr_seat; + struct wlr_keyboard *keyboard; + struct wlr_seat_handle *focused_handle; struct wlr_surface *focused_surface; + struct wl_listener keyboard_destroy; + struct wl_listener keyboard_keymap; + struct wl_listener surface_destroy; struct wl_listener resource_destroy; @@ -113,7 +107,6 @@ struct wlr_seat { struct wl_global *wl_global; struct wl_display *display; struct wl_list handles; - struct wl_list keyboards; char *name; uint32_t capabilities; @@ -266,18 +259,9 @@ void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, enum wlr_axis_orientation orientation, double value); /** - * Attaches this keyboard to the seat. Key events from this keyboard will be - * propegated to the focused client. + * Set this keyboard as the active keyboard for the seat. */ -void wlr_seat_attach_keyboard(struct wlr_seat *seat, - struct wlr_input_device *dev); - -/** - * Detaches this keyboard from the seat. This is done automatically when the - * keyboard is destroyed; you only need to use this if you want to remove it for - * some other reason. - */ -void wlr_seat_detach_keyboard(struct wlr_seat *seat, struct wlr_keyboard *kb); +void wlr_seat_set_keyboard(struct wlr_seat *seat, struct wlr_input_device *dev); /** * Start a grab of the keyboard of this seat. The grabber is responsible for @@ -294,19 +278,34 @@ void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat); /** * Send the keyboard key to focused keyboard resources. Compositors should use - * `wlr_seat_attach_keyboard()` to automatically handle keyboard events. + * `wlr_seat_notify_key()` to respect keyboard grabs. */ void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time, uint32_t key, uint32_t state); +/** + * Notify the seat that a key has been pressed on the keyboard. Defers to any + * keyboard grabs. + */ +void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time, + uint32_t key, uint32_t state); + /** * Send the modifier state to focused keyboard resources. Compositors should use - * `wlr_seat_attach_keyboard()` to automatically handle keyboard events. + * `wlr_seat_keyboard_notify_modifiers()` to respect any keyboard grabs. */ void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); +/** + * Notify the seat that the modifiers for the keyboard have changed. Defers to + * any keyboard grabs. + */ +void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group); + /** * Notify the seat that the keyboard focus has changed and request it to be the * focused surface for this keyboard. Defers to any current grab of the seat's diff --git a/rootston/keyboard.c b/rootston/keyboard.c index c91c326b..a0601d05 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -55,7 +55,13 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } } -static void keyboard_keysym_press(struct roots_keyboard *keyboard, +/** + * Process a keypress from the keyboard. + * + * Returns true if the keysym was handled by a binding and false if the event + * should be propagated to clients. + */ +static bool keyboard_keysym_press(struct roots_keyboard *keyboard, xkb_keysym_t keysym) { ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym); if (i < 0) { @@ -76,7 +82,7 @@ static void keyboard_keysym_press(struct roots_keyboard *keyboard, wlr_session_change_vt(session, vt); } } - return; + return true; } uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); @@ -98,8 +104,11 @@ static void keyboard_keysym_press(struct roots_keyboard *keyboard, if (ok) { keyboard_binding_execute(keyboard, bc->command); + return true; } } + + return false; } static void keyboard_keysym_release(struct roots_keyboard *keyboard, @@ -118,13 +127,36 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) { const xkb_keysym_t *syms; int syms_len = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, keycode, &syms); + + bool handled = false; for (int i = 0; i < syms_len; i++) { if (event->state == WLR_KEY_PRESSED) { - keyboard_keysym_press(keyboard, syms[i]); + bool keysym_handled = keyboard_keysym_press(keyboard, syms[i]); + handled = handled || keysym_handled; } else { // WLR_KEY_RELEASED keyboard_keysym_release(keyboard, syms[i]); } } + + if (!handled) { + wlr_seat_set_keyboard(keyboard->input->wl_seat, keyboard->device); + wlr_seat_keyboard_notify_key(keyboard->input->wl_seat, + (uint32_t)(event->time_usec / 1000), event->keycode, event->state); + } +} + +static void keyboard_modifiers_notify(struct wl_listener *listener, void *data) { + struct roots_keyboard *r_keyboard = + wl_container_of(listener, r_keyboard, modifiers); + struct wlr_seat *seat = r_keyboard->input->wl_seat; + struct wlr_keyboard *keyboard = r_keyboard->device->keyboard; + wlr_seat_set_keyboard(seat, r_keyboard->device); + wlr_seat_keyboard_notify_modifiers(seat, + keyboard->modifiers.depressed, + keyboard->modifiers.latched, + keyboard->modifiers.locked, + keyboard->modifiers.group); + } static void keyboard_config_merge(struct keyboard_config *config, @@ -157,8 +189,13 @@ void keyboard_add(struct wlr_input_device *device, struct roots_input *input) { device->data = keyboard; keyboard->device = device; keyboard->input = input; + keyboard->key.notify = keyboard_key_notify; wl_signal_add(&device->keyboard->events.key, &keyboard->key); + + keyboard->modifiers.notify = keyboard_modifiers_notify; + wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); + wl_list_insert(&input->keyboards, &keyboard->link); struct keyboard_config config; @@ -190,14 +227,12 @@ void keyboard_add(struct wlr_input_device *device, struct roots_input *input) { wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); xkb_context_unref(context); - - wlr_seat_attach_keyboard(input->wl_seat, device); } void keyboard_remove(struct wlr_input_device *device, struct roots_input *input) { struct roots_keyboard *keyboard = device->data; - wlr_seat_detach_keyboard(input->wl_seat, device->keyboard); wl_list_remove(&keyboard->key.link); + wl_list_remove(&keyboard->modifiers.link); wl_list_remove(&keyboard->link); free(keyboard); } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 5f64bac1..a825a37f 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -92,6 +92,23 @@ static void wl_keyboard_destroy(struct wl_resource *resource) { } } +static void seat_handle_send_keymap(struct wlr_seat_handle *handle, + struct wlr_keyboard *keyboard) { + if (!keyboard || !handle->keyboard) { + return; + } + // TODO: We should probably lift all of the keys set by the other + // keyboard + wl_keyboard_send_keymap(handle->keyboard, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd, + keyboard->keymap_size); + + if (wl_resource_get_version(handle->keyboard) >= + WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { + wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); + } +} + static void wl_seat_get_keyboard(struct wl_client *client, struct wl_resource *_handle, uint32_t id) { struct wlr_seat_handle *handle = wl_resource_get_user_data(_handle); @@ -108,6 +125,11 @@ static void wl_seat_get_keyboard(struct wl_client *client, wl_resource_get_version(_handle), id); wl_resource_set_implementation(handle->keyboard, &wl_keyboard_impl, handle, &wl_keyboard_destroy); + + seat_handle_send_keymap(handle, handle->wlr_seat->keyboard_state.keyboard); + + // TODO possibly handle the case where this keyboard needs an enter + // right away } static const struct wl_touch_interface wl_touch_impl = { @@ -300,7 +322,6 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wlr_seat->display = display; wlr_seat->name = strdup(name); wl_list_init(&wlr_seat->handles); - wl_list_init(&wlr_seat->keyboards); wl_signal_init(&wlr_seat->events.client_bound); wl_signal_init(&wlr_seat->events.client_unbound); @@ -559,26 +580,6 @@ void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, grab->interface->axis(grab, time, orientation, value); } -static void keyboard_switch_seat_keyboard(struct wlr_seat_handle *handle, - struct wlr_seat_keyboard *seat_kb) { - if (handle->seat_keyboard == seat_kb) { - return; - } - - // TODO: We should probably lift all of the keys set by the other - // keyboard - wl_keyboard_send_keymap(handle->keyboard, - WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, seat_kb->keyboard->keymap_fd, - seat_kb->keyboard->keymap_size); - - if (wl_resource_get_version(handle->keyboard) >= - WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { - // TODO: Make this better - wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); - } - handle->seat_keyboard = seat_kb; -} - void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, uint32_t key, uint32_t state) { struct wlr_seat_handle *handle = wlr_seat->keyboard_state.focused_handle; @@ -591,89 +592,52 @@ void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, time, key, state); } -static void keyboard_key_notify(struct wl_listener *listener, void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of(listener, seat_kb, key); - struct wlr_seat *seat = seat_kb->seat; - struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle; - if (!handle || !handle->keyboard) { +static void handle_keyboard_keymap(struct wl_listener *listener, void *data) { + struct wlr_seat_keyboard_state *state = + wl_container_of(listener, state, keyboard_keymap); + struct wlr_seat_handle *handle; + wl_list_for_each(handle, &state->wlr_seat->handles, link) { + seat_handle_send_keymap(handle, state->keyboard); + } +} + +static void handle_keyboard_destroy(struct wl_listener *listener, void *data) { + struct wlr_seat_keyboard_state *state = + wl_container_of(listener, state, keyboard_destroy); + state->keyboard = NULL; +} + +void wlr_seat_set_keyboard(struct wlr_seat *seat, + struct wlr_input_device *device) { + // TODO call this on device key event before the event reaches the + // compositor and set a pending keyboard and then send the new keyboard + // state on the next keyboard notify event. + if (seat->keyboard_state.keyboard == device->keyboard) { return; } - keyboard_switch_seat_keyboard(handle, seat_kb); - - struct wlr_event_keyboard_key *event = data; - enum wlr_key_state key_state = event->state; - - struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; - grab->interface->key(grab, (uint32_t)(event->time_usec / 1000), - event->keycode, key_state); -} - -static void keyboard_modifiers_notify(struct wl_listener *listener, - void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of(listener, seat_kb, - modifiers); - struct wlr_seat *seat = seat_kb->seat; - struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle; - if (!handle || !handle->keyboard) { - return; + if (seat->keyboard_state.keyboard) { + wl_list_remove(&seat->keyboard_state.keyboard_destroy.link); + wl_list_remove(&seat->keyboard_state.keyboard_keymap.link); + seat->keyboard_state.keyboard = NULL; } - keyboard_switch_seat_keyboard(handle, seat_kb); + if (device) { + assert(device->type == WLR_INPUT_DEVICE_KEYBOARD); + wl_signal_add(&device->events.destroy, + &seat->keyboard_state.keyboard_destroy); + seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy; - struct wlr_keyboard *keyboard = seat_kb->keyboard; + wl_signal_add(&device->keyboard->events.keymap, + &seat->keyboard_state.keyboard_keymap); + seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap; - struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; - - grab->interface->modifiers(grab, - keyboard->modifiers.depressed, keyboard->modifiers.latched, - keyboard->modifiers.locked, keyboard->modifiers.group); -} - -static void keyboard_keymap_notify(struct wl_listener *listener, void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of( - listener, seat_kb, keymap); - wlr_log(L_DEBUG, "Keymap event for %p", seat_kb); -} - -static void keyboard_destroy_notify(struct wl_listener *listener, void *data) { - struct wlr_seat_keyboard *seat_kb = wl_container_of( - listener, seat_kb, destroy); - wlr_seat_detach_keyboard(seat_kb->seat, seat_kb->keyboard); -} - -void wlr_seat_attach_keyboard(struct wlr_seat *seat, - struct wlr_input_device *dev) { - assert(seat && dev && dev->type == WLR_INPUT_DEVICE_KEYBOARD); - struct wlr_keyboard *kb = dev->keyboard; - struct wlr_seat_keyboard *seat_kb = - calloc(1, sizeof(struct wlr_seat_keyboard)); - seat_kb->keyboard = kb; - seat_kb->seat = seat; - seat_kb->key.notify = keyboard_key_notify; - wl_signal_add(&kb->events.key, &seat_kb->key); - seat_kb->modifiers.notify = keyboard_modifiers_notify; - wl_signal_add(&kb->events.modifiers, &seat_kb->modifiers); - seat_kb->keymap.notify = keyboard_keymap_notify; - wl_signal_add(&kb->events.keymap, &seat_kb->keymap); - // TODO: update keymap as necessary - seat_kb->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&dev->events.destroy, &seat_kb->destroy); - wl_list_insert(&seat->keyboards, &seat_kb->link); -} - -void wlr_seat_detach_keyboard(struct wlr_seat *seat, struct wlr_keyboard *kb) { - struct wlr_seat_keyboard *seat_kb, *_tmp; - wl_list_for_each_safe(seat_kb, _tmp, &seat->keyboards, link) { - if (seat_kb->keyboard == kb) { - wl_list_remove(&seat_kb->link); - wl_list_remove(&seat_kb->key.link); - wl_list_remove(&seat_kb->modifiers.link); - wl_list_remove(&seat_kb->keymap.link); - wl_list_remove(&seat_kb->destroy.link); - free(seat_kb); - break; + struct wlr_seat_handle *handle; + wl_list_for_each(handle, &seat->handles, link) { + seat_handle_send_keymap(handle, device->keyboard); } + + seat->keyboard_state.keyboard = device->keyboard; } } @@ -757,7 +721,8 @@ void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, // enter the current surface if (handle && handle->keyboard) { - // TODO: handle keys properly + // TODO: read the currently pressed keys out of the active keyboard and + // put them in this array struct wl_array keys; wl_array_init(&keys); uint32_t serial = wl_display_next_serial(wlr_seat->display); @@ -797,3 +762,17 @@ void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat) { wl_array_init(&keys); wlr_seat_keyboard_enter(wlr_seat, NULL); } + +void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) { + struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; + grab->interface->modifiers(grab, + mods_depressed, mods_latched, mods_locked, group); +} + +void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time, + uint32_t key, uint32_t state) { + struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; + grab->interface->key(grab, time, key, state); +}