[RFC PATCH libinput 2/2] evdev: hook up keysym API

Peter Hutterer peter.hutterer at who-t.net
Sun Dec 7 22:05:57 PST 2014


The kernel doesn't do real keysym handling through evdev, so this patch is a
basic proof-of-concept and incomplete.
It emulates a keysym-sending event by waiting for EV_KEY/KEY_MAX-1, then
waiting for the next EV_MSC/MSC_SCAN and parsing event->value as a 4-byte UTF8
sequence.

No checking is done for proper key releasing, etc.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
Cc: Samuel Thibault <samuel.thibault at ens-lyon.org>
---
 src/evdev.c                   | 48 +++++++++++++++++++++++++++++
 src/evdev.h                   |  5 +++
 test/Makefile.am              |  1 +
 test/keyboard.c               | 71 +++++++++++++++++++++++++++++++++++++++++++
 test/litest-keyboard-string.c | 59 +++++++++++++++++++++++++++++++++++
 test/litest.c                 |  2 ++
 test/litest.h                 |  2 ++
 7 files changed, 188 insertions(+)
 create mode 100644 test/litest-keyboard-string.c

diff --git a/src/evdev.c b/src/evdev.c
index fbfbcd3..afc54ee 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -46,6 +46,7 @@
 enum evdev_key_type {
 	EVDEV_KEY_TYPE_NONE,
 	EVDEV_KEY_TYPE_KEY,
+	EVDEV_KEY_TYPE_STRING,
 	EVDEV_KEY_TYPE_BUTTON,
 };
 
@@ -365,6 +366,8 @@ get_key_type(uint16_t code)
 	if (code == BTN_TOUCH)
 		return EVDEV_KEY_TYPE_NONE;
 
+	if (code == KEY_MAX - 1)
+		return EVDEV_KEY_TYPE_STRING;
 	if (code >= KEY_ESC && code <= KEY_MICMUTE)
 		return EVDEV_KEY_TYPE_KEY;
 	if (code >= BTN_MISC && code <= BTN_GEAR_UP)
@@ -447,6 +450,7 @@ evdev_process_key(struct evdev_device *device,
 	if (e->value == 0) {
 		switch (type) {
 		case EVDEV_KEY_TYPE_NONE:
+		case EVDEV_KEY_TYPE_STRING:
 			break;
 		case EVDEV_KEY_TYPE_KEY:
 		case EVDEV_KEY_TYPE_BUTTON:
@@ -460,6 +464,11 @@ evdev_process_key(struct evdev_device *device,
 	switch (type) {
 	case EVDEV_KEY_TYPE_NONE:
 		break;
+	case EVDEV_KEY_TYPE_STRING:
+		device->string.pending = true;
+		device->string.state = e->value ? LIBINPUT_KEY_STATE_PRESSED :
+						  LIBINPUT_KEY_STATE_RELEASED;
+		break;
 	case EVDEV_KEY_TYPE_KEY:
 		evdev_keyboard_notify_key(
 			device,
@@ -654,6 +663,36 @@ evdev_tag_trackpoint(struct evdev_device *device,
 }
 
 static void
+evdev_process_msc(struct evdev_device *device,
+		  struct input_event *e, uint64_t time)
+{
+	char utf8[5];
+	char *string;
+
+	if (!device->string.pending)
+		return;
+
+	/* Until evdev has real keysym handling, simply interpret e->value
+	 * as a four-byte string sequence */
+	utf8[0] = (e->value & 0xff000000) >> 24;
+	utf8[1] = (e->value & 0x00ff0000) >> 16;
+	utf8[2] = (e->value & 0x0000ff00) >> 8;
+	utf8[3] = (e->value & 0x000000ff);
+	utf8[4] = 0;
+
+	string = utf8;
+	while (*string == '\0' && string < &utf8[4])
+		string++;
+
+	keyboard_notify_string(&device->base,
+			       time,
+			       string,
+			       device->string.state);
+
+	device->string.pending = false;
+}
+
+static void
 fallback_process(struct evdev_dispatch *dispatch,
 		 struct evdev_device *device,
 		 struct input_event *event,
@@ -671,11 +710,16 @@ fallback_process(struct evdev_dispatch *dispatch,
 	case EV_KEY:
 		evdev_process_key(device, event, time);
 		break;
+	case EV_MSC:
+		evdev_process_msc(device, event, time);
+		break;
 	case EV_SYN:
 		need_frame = evdev_need_touch_frame(device);
 		evdev_flush_pending_event(device, time);
 		if (need_frame)
 			touch_notify_frame(&device->base, time);
+
+		device->string.pending = false;
 		break;
 	}
 }
@@ -1406,6 +1450,7 @@ evdev_configure_device(struct evdev_device *device)
 				case EVDEV_KEY_TYPE_NONE:
 					break;
 				case EVDEV_KEY_TYPE_KEY:
+				case EVDEV_KEY_TYPE_STRING:
 					has_keyboard = 1;
 					break;
 				case EVDEV_KEY_TYPE_BUTTON:
@@ -1894,6 +1939,9 @@ release_pressed_keys(struct evdev_device *device)
 			switch (get_key_type(code)) {
 			case EVDEV_KEY_TYPE_NONE:
 				break;
+			case EVDEV_KEY_TYPE_STRING:
+				/* FIXME: */
+				break;
 			case EVDEV_KEY_TYPE_KEY:
 				evdev_keyboard_notify_key(
 					device,
diff --git a/src/evdev.h b/src/evdev.h
index 033d455..b9084f0 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -141,6 +141,11 @@ struct evdev_device {
 	uint8_t key_count[KEY_CNT];
 
 	struct {
+		bool pending;
+		enum libinput_key_state state;
+	} string;
+
+	struct {
 		struct libinput_device_config_left_handed config_left_handed;
 		/* left-handed currently enabled */
 		bool left_handed;
diff --git a/test/Makefile.am b/test/Makefile.am
index 2c36e3f..fda7538 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -17,6 +17,7 @@ liblitest_la_SOURCES = \
 	litest-bcm5974.c \
 	litest-generic-singletouch.c \
 	litest-keyboard.c \
+	litest-keyboard-string.c \
 	litest-mouse.c \
 	litest-ms-surface-cover.c \
 	litest-qemu-usb-tablet.c \
diff --git a/test/keyboard.c b/test/keyboard.c
index 4563ce6..573daf3 100644
--- a/test/keyboard.c
+++ b/test/keyboard.c
@@ -290,6 +290,75 @@ START_TEST(keyboard_key_auto_release)
 }
 END_TEST
 
+static void
+assert_string_event(struct libinput *li,
+		    const char *string,
+		    enum libinput_key_state state)
+{
+	struct libinput_event *event;
+	struct libinput_event_keyboard *kevent;
+
+	event = libinput_get_event(li);
+	ck_assert_int_eq(libinput_event_get_type(event),
+			 LIBINPUT_EVENT_KEYBOARD_STRING);
+
+	kevent = libinput_event_get_keyboard_event(event);
+	ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent),
+			 state);
+
+	ck_assert_str_eq(libinput_event_keyboard_get_string(kevent),
+			 string);
+
+	libinput_event_destroy(event);
+}
+
+START_TEST(keyboard_string_events)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+
+	litest_drain_events(dev->libinput);
+
+	litest_event(dev, EV_KEY, KEY_MAX - 1, 1);
+	litest_event(dev, EV_MSC, MSC_SCAN, 'a');
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	libinput_dispatch(li);
+	assert_string_event(li, "a", LIBINPUT_KEY_STATE_PRESSED);
+
+	litest_event(dev, EV_KEY, KEY_MAX - 1, 0);
+	litest_event(dev, EV_MSC, MSC_SCAN, 'a');
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	libinput_dispatch(li);
+	assert_string_event(li, "a", LIBINPUT_KEY_STATE_RELEASED);
+
+	litest_event(dev, EV_KEY, KEY_MAX - 1, 1);
+	litest_event(dev, EV_MSC, MSC_SCAN, 'a' << 16 | 'b' << 8 | 'c');
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	litest_event(dev, EV_KEY, KEY_MAX - 1, 0);
+	litest_event(dev, EV_MSC, MSC_SCAN, 'a' << 16| 'b' << 8 | 'c');
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	libinput_dispatch(li);
+	assert_string_event(li, "abc", LIBINPUT_KEY_STATE_PRESSED);
+	assert_string_event(li, "abc", LIBINPUT_KEY_STATE_RELEASED);
+
+	litest_event(dev, EV_KEY, KEY_MAX - 1, 1);
+	litest_event(dev, EV_MSC, MSC_SCAN, 0xE282AC); /* euro sign */
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	litest_event(dev, EV_KEY, KEY_MAX - 1, 0);
+	litest_event(dev, EV_MSC, MSC_SCAN, 0xE282AC); /* euro sign */
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+	libinput_dispatch(li);
+	assert_string_event(li, "€", LIBINPUT_KEY_STATE_PRESSED);
+	assert_string_event(li, "€", LIBINPUT_KEY_STATE_RELEASED);
+}
+END_TEST
+
 int
 main(int argc, char **argv)
 {
@@ -297,5 +366,7 @@ main(int argc, char **argv)
 	litest_add_no_device("keyboard:key counting", keyboard_ignore_no_pressed_release);
 	litest_add_no_device("keyboard:key counting", keyboard_key_auto_release);
 
+	litest_add("keyboards:strings", keyboard_string_events, LITEST_STRINGS, LITEST_ANY);
+
 	return litest_run(argc, argv);
 }
diff --git a/test/litest-keyboard-string.c b/test/litest-keyboard-string.c
new file mode 100644
index 0000000..8f85ffe
--- /dev/null
+++ b/test/litest-keyboard-string.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2014 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "litest.h"
+#include "litest-int.h"
+
+static void litest_keyboard_string_setup(void)
+{
+	struct litest_device *d = litest_create_device(LITEST_KEYBOARD_STRING);
+	litest_set_current_device(d);
+}
+
+static struct input_id input_id = {
+	.bustype = 0x11,
+	.vendor = 0x1,
+	.product = 0x1,
+};
+
+static int events[] = {
+	EV_KEY, KEY_MAX - 1,
+	EV_MSC, MSC_SCAN,
+	-1, -1,
+};
+
+struct litest_test_device litest_keyboard_string_device = {
+	.type = LITEST_KEYBOARD_STRING,
+	.features = LITEST_STRINGS,
+	.shortname = "default keyboard_string",
+	.setup = litest_keyboard_string_setup,
+	.interface = NULL,
+
+	.name = "Fake string keyboard",
+	.id = &input_id,
+	.events = events,
+	.absinfo = NULL,
+};
diff --git a/test/litest.c b/test/litest.c
index 2ab802b..c93f096 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -90,6 +90,7 @@ extern struct litest_test_device litest_generic_singletouch_device;
 extern struct litest_test_device litest_qemu_tablet_device;
 extern struct litest_test_device litest_xen_virtual_pointer_device;
 extern struct litest_test_device litest_vmware_virtmouse_device;
+extern struct litest_test_device litest_keyboard_string_device;
 
 struct litest_test_device* devices[] = {
 	&litest_synaptics_clickpad_device,
@@ -105,6 +106,7 @@ struct litest_test_device* devices[] = {
 	&litest_qemu_tablet_device,
 	&litest_xen_virtual_pointer_device,
 	&litest_vmware_virtmouse_device,
+	&litest_keyboard_string_device,
 	NULL,
 };
 
diff --git a/test/litest.h b/test/litest.h
index 99c6ae3..1e68c85 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -49,6 +49,7 @@ enum litest_device_type {
 	LITEST_QEMU_TABLET = -13,
 	LITEST_XEN_VIRTUAL_POINTER = -14,
 	LITEST_VMWARE_VIRTMOUSE = -15,
+	LITEST_KEYBOARD_STRING = -16,
 };
 
 enum litest_device_feature {
@@ -68,6 +69,7 @@ enum litest_device_feature {
 	LITEST_POINTINGSTICK = 1 << 11,
 	LITEST_FAKE_MT = 1 << 12,
 	LITEST_ABSOLUTE = 1 << 13,
+	LITEST_STRINGS = 1 << 14,
 };
 
 struct litest_device {
-- 
2.1.0



More information about the wayland-devel mailing list