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

Derek Foreman derekf at osg.samsung.com
Tue May 5 13:01:54 PDT 2015


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 (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



More information about the wayland-devel mailing list