[PATCH weston 4/4] input: Detect keyboard capabilities

Jonas Ã…dahl jadahl at gmail.com
Wed May 20 03:04:52 PDT 2015


On Tue, May 05, 2015 at 03:01:54PM -0500, Derek Foreman wrote:
> Some devices (power buttons, acpi video bus driver) are considered
> keyboards but you can't type with them.
> 
> As of libinput 0.15 we can query a keyboard to see which key events it
> can generate.  We use this to detect if a keyboard can type letters or
> digits.
> 
> The wayland protocol doesn't propagate these capabilites, so
> weston_seat_send_dirty_caps() will differentiate between dirty keyboards
> (which generate the weston signal) and dirty seats (which generate a
> wayland event) and only send the appropriate updates.
> 
> Functions are provided for backends that don't use libinput to force these
> capabilities to a sensible state.
> 
> Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
> ---
>  configure.ac              |  2 +-
>  src/compositor-headless.c |  1 +
>  src/compositor-rdp.c      |  1 +
>  src/compositor-wayland.c  |  1 +
>  src/compositor-x11.c      |  1 +
>  src/compositor.h          |  8 ++++++++
>  src/input.c               | 29 +++++++++++++++++++++++++++--
>  src/libinput-device.c     | 32 +++++++++++++++++++++++++++++++-
>  src/libinput-device.h     |  4 +++-
>  src/libinput-seat.c       | 27 +++++++++++++++++++++++++++
>  src/screen-share.c        |  1 +
>  11 files changed, 102 insertions(+), 5 deletions(-)
> 
> diff --git a/configure.ac b/configure.ac
> index d9d8d8f..4e9ae20 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -155,7 +155,7 @@ if test x$enable_drm_compositor = xyes; then
>  fi
>  
>  
> -PKG_CHECK_MODULES(LIBINPUT_BACKEND, [libinput >= 0.8.0])
> +PKG_CHECK_MODULES(LIBINPUT_BACKEND, [libinput >= 0.15.0])
>  PKG_CHECK_MODULES(COMPOSITOR, [$COMPOSITOR_MODULES])
>  
>  AC_ARG_ENABLE(wayland-compositor, [  --enable-wayland-compositor],,
> diff --git a/src/compositor-headless.c b/src/compositor-headless.c
> index 0ddb26e..0b461c6 100644
> --- a/src/compositor-headless.c
> +++ b/src/compositor-headless.c
> @@ -184,6 +184,7 @@ headless_input_create(struct headless_compositor *c)
>  	if (weston_seat_init_keyboard(&c->fake_seat, NULL) < 0)
>  		return -1;
>  
> +	weston_seat_override_keyboard_caps(&c->fake_seat, true, true);
>  	weston_seat_send_dirty_caps(&c->fake_seat);
>  
>  	return 0;
> diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
> index 5b50382..b6e3876 100644
> --- a/src/compositor-rdp.c
> +++ b/src/compositor-rdp.c
> @@ -842,6 +842,7 @@ xf_peer_post_connect(freerdp_peer* client)
>  	}
>  	weston_seat_init_keyboard(&peerCtx->item.seat, keymap);
>  	weston_seat_init_pointer(&peerCtx->item.seat);
> +	weston_seat_override_keyboard_caps(&peerCtx->item.seat, true, true);
>  	weston_seat_send_dirty_caps(&peerCtx->item.seat);
>  
>  	peerCtx->item.flags |= RDP_PEER_ACTIVATED;
> diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
> index 53159c4..1e33697 100644
> --- a/src/compositor-wayland.c
> +++ b/src/compositor-wayland.c
> @@ -1463,6 +1463,7 @@ input_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
>  	else
>  		weston_seat_init_keyboard(&input->base, keymap);
>  
> +	weston_seat_override_keyboard_caps(&input->base, true, true);
>  	weston_seat_send_dirty_caps(&input->base);
>  
>  	xkb_keymap_unref(keymap);
> diff --git a/src/compositor-x11.c b/src/compositor-x11.c
> index 4a3b10e..69e3a14 100644
> --- a/src/compositor-x11.c
> +++ b/src/compositor-x11.c
> @@ -336,6 +336,7 @@ x11_input_create(struct x11_compositor *c, int no_input)
>  		return -1;
>  	xkb_keymap_unref(keymap);
>  
> +	weston_seat_override_keyboard_caps(&c->core_seat, true, true);
>  	weston_seat_send_dirty_caps(&c->core_seat);
>  
>  	x11_compositor_setup_xkb(c);
> diff --git a/src/compositor.h b/src/compositor.h
> index e05b262..da6d126 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -451,6 +451,10 @@ weston_touch_start_drag(struct weston_touch *touch,
>  			struct wl_client *client);
>  void
>  weston_seat_send_dirty_caps(struct weston_seat *seat);
> +void
> +weston_seat_override_keyboard_caps(struct weston_seat *seat,
> +				   bool has_letters,
> +				   bool has_digits);
>  
>  struct weston_xkb_info {
>  	struct xkb_keymap *keymap;
> @@ -505,6 +509,10 @@ struct weston_keyboard {
>  		enum weston_led leds;
>  	} xkb_state;
>  	struct xkb_keymap *pending_keymap;
> +
> +	bool has_digits;
> +	bool has_letters;
> +	bool caps_dirty;
>  };
>  
>  struct weston_seat {
> diff --git a/src/input.c b/src/input.c
> index c37bd20..3a0adc3 100644
> --- a/src/input.c
> +++ b/src/input.c
> @@ -601,14 +601,16 @@ weston_touch_destroy(struct weston_touch *touch)
>  
>  /* Send seat capability updates if necessary
>   *
> - * Checks if the seat capabilities (WL_SEAT_CAPABILITY_*) have changed
> - * and propagates updates appropriately.
> + * Checks if the seat capabilities (WL_SEAT_CAPABILITY_*) or the keyboard
> + * capabilities (has_digits, has_letters) have changed and propagates
> + * updates appropriately.
>   *
>   * \param seat These seat to send capabilities changes for
>   */
>  WL_EXPORT void
>  weston_seat_send_dirty_caps(struct weston_seat *seat)
>  {
> +	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
>  	enum wl_seat_capability caps = 0;
>  	struct wl_resource *resource;
>  
> @@ -622,8 +624,15 @@ weston_seat_send_dirty_caps(struct weston_seat *seat)
>  
>  		wl_resource_for_each(resource, &seat->base_resource_list)
>  			wl_seat_send_capabilities(resource, caps);
> +	}
> +
> +	if (seat->caps_dirty || (keyboard && keyboard->caps_dirty)) {
>  		wl_signal_emit(&seat->updated_caps_signal, seat);
>  	}
> +
> +	if (keyboard)
> +		keyboard->caps_dirty = false;
> +
>  	seat->caps_dirty = false;
>  }
>  
> @@ -2230,6 +2239,22 @@ weston_seat_release_keyboard(struct weston_seat *seat)
>  	}
>  }
>  
> +void
> +weston_seat_override_keyboard_caps(struct weston_seat *seat,
> +				   bool has_letters,
> +				   bool has_digits)
> +{
> +	struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
> +
> +	if (!keyboard)
> +		return;
> +
> +	keyboard->caps_dirty = has_digits ^ keyboard->has_digits ||
> +			       has_letters ^ keyboard->has_letters;
> +	keyboard->has_digits = has_digits;
> +	keyboard->has_letters = has_letters;
> +}
> +
>  WL_EXPORT void
>  weston_seat_init_pointer(struct weston_seat *seat)
>  {
> diff --git a/src/libinput-device.c b/src/libinput-device.c
> index 3fb507f..983665c 100644
> --- a/src/libinput-device.c
> +++ b/src/libinput-device.c
> @@ -480,6 +480,36 @@ configure_device(struct evdev_device *device)
>  	evdev_device_set_calibration(device);
>  }
>  
> +static enum evdev_device_seat_capability
> +keyboard_caps(struct libinput_device *dev)
> +{
> +	bool letters = true, digits = true;
> +	uint32_t alpha_keys[] = {
> +		KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F,
> +		KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
> +		KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R,
> +		KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X,
> +		KEY_Y, KEY_Z, KEY_RESERVED
> +	};
> +	uint32_t digit_keys[] = {
> +		KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,
> +		KEY_7, KEY_8, KEY_9, KEY_0, KEY_RESERVED
> +	};
> +	int i;
> +
> +	for (i = 0; letters && alpha_keys[i] != KEY_RESERVED; i++)
> +		letters &= libinput_device_keyboard_has_key(dev,
> +							    alpha_keys[i]);
> +
> +	for (i = 0; digits && digit_keys[i] != KEY_RESERVED; i++)
> +		digits &= libinput_device_keyboard_has_key(dev,
> +							   digit_keys[i]);
> +
> +	return EVDEV_SEAT_KEYBOARD |
> +	       (letters ? EVDEV_SEAT_KEYBOARD_LETTERS : 0) |
> +	       (digits ? EVDEV_SEAT_KEYBOARD_DIGITS : 0);
> +}
> +
>  struct evdev_device *
>  evdev_device_create(struct libinput_device *libinput_device,
>  		    struct weston_seat *seat)
> @@ -497,7 +527,7 @@ evdev_device_create(struct libinput_device *libinput_device,
>  	if (libinput_device_has_capability(libinput_device,
>  					   LIBINPUT_DEVICE_CAP_KEYBOARD)) {
>  		weston_seat_init_keyboard(seat, NULL);
> -		device->seat_caps |= EVDEV_SEAT_KEYBOARD;
> +		device->seat_caps |= keyboard_caps(libinput_device);

If we don't want keyboards with neither numbers nor letters be
advertised as keyboards, can't we just simply not set
EVDEV_SEAT_KEYBOARD here? That way we'd need nothing of the extra API or
the extra calls.

On a related note, doing something like this would mean that key events
would still be sent by libinput-device.c. As far as I can tell, this
means that if the only keyboard provided by libinput doesn't have digit
or letter keys, we'd never set seat->keyboard, but still call
notify_key, meaning a NULL pointer dereference in notify_key().

If, in libinput-device.c we'd ignore key events when we never set the
EVDEV_SEAT_KEYBOARD bit, this would mean that even if a client has a
wl_keyboard, it wouldn't ever get key events from non-keyboard keys.

I feels like the scope of wl_keyboard needs to be clarified before doing
this type of change, so that it is clear what type of events can be
relied on.


Jonas


>  	}
>  	if (libinput_device_has_capability(libinput_device,
>  					   LIBINPUT_DEVICE_CAP_POINTER)) {
> diff --git a/src/libinput-device.h b/src/libinput-device.h
> index 0775743..70591c2 100644
> --- a/src/libinput-device.h
> +++ b/src/libinput-device.h
> @@ -34,7 +34,9 @@
>  enum evdev_device_seat_capability {
>  	EVDEV_SEAT_POINTER = (1 << 0),
>  	EVDEV_SEAT_KEYBOARD = (1 << 1),
> -	EVDEV_SEAT_TOUCH = (1 << 2)
> +	EVDEV_SEAT_TOUCH = (1 << 2),
> +	EVDEV_SEAT_KEYBOARD_DIGITS = (1 << 3),
> +	EVDEV_SEAT_KEYBOARD_LETTERS = (1 << 4)
>  };
>  
>  struct evdev_device {
> diff --git a/src/libinput-seat.c b/src/libinput-seat.c
> index f0fcd51..af695a6 100644
> --- a/src/libinput-seat.c
> +++ b/src/libinput-seat.c
> @@ -45,6 +45,30 @@ udev_seat_create(struct udev_input *input, const char *seat_name);
>  static void
>  udev_seat_destroy(struct udev_seat *seat);
>  
> +static void
> +seat_rescan_keyboard_caps(struct udev_seat *udev_seat)
> +{
> +	struct evdev_device *dev;
> +	struct weston_seat *weston_seat = &udev_seat->base;
> +	struct weston_keyboard *keyboard = weston_seat->keyboard_resource;
> +	bool has_letters = false, has_digits = false;
> +
> +	keyboard = weston_seat_get_keyboard(weston_seat);
> +	if (!keyboard)
> +		return;
> +
> +	wl_list_for_each(dev, &udev_seat->devices_list, link) {
> +		has_letters = has_letters || (dev->seat_caps & EVDEV_SEAT_KEYBOARD_LETTERS);
> +		has_digits = has_digits || (dev->seat_caps & EVDEV_SEAT_KEYBOARD_DIGITS);
> +	}
> +
> +	if (has_letters != keyboard->has_letters || has_digits != keyboard->has_digits) {
> +		keyboard->has_letters = has_letters;
> +		keyboard->has_digits = has_digits;
> +		keyboard->caps_dirty = true;
> +	}
> +}
> +
>  static struct udev_seat *
>  get_udev_seat(struct udev_input *input, struct libinput_device *device)
>  {
> @@ -81,6 +105,8 @@ device_added(struct udev_input *input, struct libinput_device *libinput_device)
>  	udev_seat = (struct udev_seat *) seat;
>  	wl_list_insert(udev_seat->devices_list.prev, &device->link);
>  
> +	seat_rescan_keyboard_caps(udev_seat);
> +
>  	pointer = weston_seat_get_pointer(seat);
>  	if (seat->output && pointer)
>  		weston_pointer_clamp(pointer,
> @@ -117,6 +143,7 @@ device_removed(struct udev_input *input, struct libinput_device *libinput_device
>  
>  	device = libinput_device_get_user_data(libinput_device);
>  	evdev_device_destroy(device);
> +	seat_rescan_keyboard_caps(udev_seat);
>  	weston_seat_send_dirty_caps(&udev_seat->base);
>  }
>  
> diff --git a/src/screen-share.c b/src/screen-share.c
> index 597ad9b..3e92d61 100644
> --- a/src/screen-share.c
> +++ b/src/screen-share.c
> @@ -214,6 +214,7 @@ ss_seat_handle_keymap(void *data, struct wl_keyboard *keyboard,
>  	else
>  		weston_seat_init_keyboard(&seat->base, keymap);
>  
> +	weston_seat_override_keyboard_caps(&seat->base, true, true);
>  	weston_seat_send_dirty_caps(&seat->base);
>  
>  	xkb_keymap_unref(keymap);
> -- 
> 2.1.4
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list