diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c index cde7658a..5b6a8f4d 100644 --- a/src/compositor-wayland.c +++ b/src/compositor-wayland.c @@ -640,7 +640,9 @@ input_handle_keyboard_enter(void *data, struct wayland_input *input = data; struct wayland_compositor *c = input->compositor; - notify_keyboard_focus(&c->base.seat->seat, keys); + /* XXX: Need to wait for modifier event and send with state then. */ + notify_keyboard_focus_in(&c->base.seat->seat, keys, + STATE_UPDATE_AUTOMATIC); } static void @@ -652,7 +654,7 @@ input_handle_keyboard_leave(void *data, struct wayland_input *input = data; struct wayland_compositor *c = input->compositor; - notify_keyboard_focus(&c->base.seat->seat, NULL); + notify_keyboard_focus_out(&c->base.seat->seat); } static void diff --git a/src/compositor-x11.c b/src/compositor-x11.c index 8cff73ed..d50261dc 100644 --- a/src/compositor-x11.c +++ b/src/compositor-x11.c @@ -679,7 +679,12 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data) } output = x11_compositor_find_output(c, focus_in->event); - notify_keyboard_focus(&c->base.seat->seat, &c->keys); + /* Unfortunately the state only comes with the enter + * event, rather than with the focus event. I'm not + * sure of the exact semantics around it and whether + * we can ensure that we get both? */ + notify_keyboard_focus_in(&c->base.seat->seat, &c->keys, + STATE_UPDATE_AUTOMATIC); free(prev); prev = NULL; @@ -763,7 +768,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data) if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED || focus_in->mode == XCB_NOTIFY_MODE_UNGRAB) break; - notify_keyboard_focus(&c->base.seat->seat, NULL); + notify_keyboard_focus_out(&c->base.seat->seat); break; default: diff --git a/src/compositor.c b/src/compositor.c index af7b3e24..9d4d4675 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1767,17 +1767,13 @@ notify_axis(struct wl_seat *seat, uint32_t time, uint32_t axis, } static int -update_modifier_state(struct weston_seat *seat, uint32_t key, uint32_t state) +modifier_state_changed(struct weston_seat *seat) { uint32_t mods_depressed, mods_latched, mods_locked, group; uint32_t mods_lookup; enum weston_led leds = 0; int ret = 0; - /* First update the XKB state object with the keypress. */ - xkb_state_update_key(seat->xkb_state.state, key + 8, - state ? XKB_KEY_DOWN : XKB_KEY_UP); - /* Serialize and update our internal state, checking to see if it's * different to the previous state. */ mods_depressed = xkb_state_serialize_mods(seat->xkb_state.state, @@ -1827,6 +1823,24 @@ update_modifier_state(struct weston_seat *seat, uint32_t key, uint32_t state) return ret; } +static int +update_modifier_state(struct weston_seat *seat, uint32_t key, + enum wl_keyboard_key_state state) +{ + enum xkb_key_direction direction; + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) + direction = XKB_KEY_DOWN; + else + direction = XKB_KEY_UP; + + /* Offset the keycode by 8, as the evdev XKB rules reflect X's + * broken keycode system, which starts at 8. */ + xkb_state_update_key(seat->xkb_state.state, key + 8, direction); + + return modifier_state_changed(seat); +} + WL_EXPORT void notify_key(struct wl_seat *seat, uint32_t time, uint32_t key, enum wl_keyboard_key_state state) @@ -1913,59 +1927,68 @@ destroy_device_saved_kbd_focus(struct wl_listener *listener, void *data) } WL_EXPORT void -notify_keyboard_focus(struct wl_seat *seat, struct wl_array *keys) +notify_keyboard_focus_in(struct wl_seat *seat, struct wl_array *keys, + enum weston_key_state_update update_state) { struct weston_seat *ws = (struct weston_seat *) seat; struct weston_compositor *compositor = ws->compositor; struct wl_surface *surface; uint32_t *k; - if (keys) { - wl_array_copy(&seat->keyboard->keys, keys); - ws->modifier_state = 0; - wl_array_for_each(k, &seat->keyboard->keys) { - weston_compositor_idle_inhibit(compositor); - update_modifier_state(ws, *k, 1); - } - - surface = ws->saved_kbd_focus; + wl_array_copy(&seat->keyboard->keys, keys); + wl_array_for_each(k, &seat->keyboard->keys) { + weston_compositor_idle_inhibit(compositor); + if (update_state == STATE_UPDATE_AUTOMATIC) + update_modifier_state(ws, *k, + WL_KEYBOARD_KEY_STATE_PRESSED); + } - if (surface) { - wl_list_remove(&ws->saved_kbd_focus_listener.link); - wl_keyboard_set_focus(ws->seat.keyboard, surface); + surface = ws->saved_kbd_focus; - if (seat->keyboard->focus_resource) { - wl_keyboard_send_modifiers(seat->keyboard->focus_resource, - wl_display_next_serial(compositor->wl_display), - ws->xkb_state.mods_depressed, - ws->xkb_state.mods_latched, - ws->xkb_state.mods_locked, - ws->xkb_state.group); - } - ws->saved_kbd_focus = NULL; + if (surface) { + wl_list_remove(&ws->saved_kbd_focus_listener.link); + wl_keyboard_set_focus(ws->seat.keyboard, surface); + + if (seat->keyboard->focus_resource) { + wl_keyboard_send_modifiers(seat->keyboard->focus_resource, + wl_display_next_serial(compositor->wl_display), + ws->xkb_state.mods_depressed, + ws->xkb_state.mods_latched, + ws->xkb_state.mods_locked, + ws->xkb_state.group); } - } else { - wl_array_for_each(k, &seat->keyboard->keys) - weston_compositor_idle_release(compositor); + ws->saved_kbd_focus = NULL; + } +} - ws->modifier_state = 0; +WL_EXPORT void +notify_keyboard_focus_out(struct wl_seat *seat) +{ + struct weston_seat *ws = (struct weston_seat *) seat; + struct weston_compositor *compositor = ws->compositor; + struct wl_surface *surface; + uint32_t *k; + + wl_array_for_each(k, &seat->keyboard->keys) + weston_compositor_idle_release(compositor); - surface = ws->seat.keyboard->focus; + ws->modifier_state = 0; - if (surface) { - ws->saved_kbd_focus = surface; - ws->saved_kbd_focus_listener.notify = - destroy_device_saved_kbd_focus; - wl_signal_add(&surface->resource.destroy_signal, - &ws->saved_kbd_focus_listener); - } + surface = ws->seat.keyboard->focus; - wl_keyboard_set_focus(ws->seat.keyboard, NULL); - /* FIXME: We really need keyboard grab cancel here to - * let the grab shut down properly. As it is we leak - * the grab data. */ - wl_keyboard_end_grab(ws->seat.keyboard); + if (surface) { + ws->saved_kbd_focus = surface; + ws->saved_kbd_focus_listener.notify = + destroy_device_saved_kbd_focus; + wl_signal_add(&surface->resource.destroy_signal, + &ws->saved_kbd_focus_listener); } + + wl_keyboard_set_focus(ws->seat.keyboard, NULL); + /* FIXME: We really need keyboard grab cancel here to + * let the grab shut down properly. As it is we leak + * the grab data. */ + wl_keyboard_end_grab(ws->seat.keyboard); } static void diff --git a/src/compositor.h b/src/compositor.h index 8331faa9..2066a562 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -458,6 +458,11 @@ struct weston_surface { void *private; }; +enum weston_key_state_update { + STATE_UPDATE_AUTOMATIC, + STATE_UPDATE_NONE, +}; + void weston_surface_update_transform(struct weston_surface *surface); @@ -510,7 +515,10 @@ notify_pointer_focus(struct wl_seat *seat, struct weston_output *output, wl_fixed_t x, wl_fixed_t y); void -notify_keyboard_focus(struct wl_seat *seat, struct wl_array *keys); +notify_keyboard_focus_in(struct wl_seat *seat, struct wl_array *keys, + enum weston_key_state_update update_state); +void +notify_keyboard_focus_out(struct wl_seat *seat); void notify_touch(struct wl_seat *seat, uint32_t time, int touch_id, diff --git a/src/evdev.c b/src/evdev.c index 9660996f..05d1ebe6 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -593,7 +593,8 @@ evdev_notify_keyboard_focus(struct evdev_seat *seat) } } - notify_keyboard_focus(&seat->base.seat, &keys); + notify_keyboard_focus_in(&seat->base.seat, &keys, + STATE_UPDATE_AUTOMATIC); wl_array_release(&keys); } @@ -761,7 +762,7 @@ evdev_remove_devices(struct weston_seat *seat_base) wl_list_for_each_safe(device, next, &seat->devices_list, link) device_removed(device); - notify_keyboard_focus(&seat->base.seat, NULL); + notify_keyboard_focus_out(&seat->base.seat); } void