[RFC PATCH libinput 1/2] Add a string-based input API

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


Some devices don't rely on keycodes + xkb layout but rather send a specific
keysym (or multiple) in response to physical button presses. This is the case
for chorded keyboards for example.

This adds a new type of key event that provides UTF8 strings. The
press/release pair applies to this type as well, the exact behavior of when
the release event is sent is implementation dependent.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
Cc: Samuel Thibault <samuel.thibault at ens-lyon.org>
---
Not intending to merge this yet, this is supposed to spark some discussion.
We don't have real support for this in the kernel and I don't have access to
any device that really generates keysysms. PoC is in Patch 2, but in the
real world the device will likely be hooked up through some other means than
evdev.

Until we have reliable testing and know what the details need to be for
device support, this remains an RFC (but now archived on the list instead of
just locally).

 src/libinput-private.h |  6 ++++++
 src/libinput.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/libinput.h         | 34 ++++++++++++++++++++++++++++++++++
 tools/event-debug.c    | 22 ++++++++++++++++++++++
 tools/event-gui.c      |  2 ++
 5 files changed, 112 insertions(+)

diff --git a/src/libinput-private.h b/src/libinput-private.h
index b36dc95..41852e0 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -256,6 +256,12 @@ keyboard_notify_key(struct libinput_device *device,
 		    enum libinput_key_state state);
 
 void
+keyboard_notify_string(struct libinput_device *device,
+		       uint64_t time,
+		       const char *utf8,
+		       enum libinput_key_state state);
+
+void
 pointer_notify_motion(struct libinput_device *device,
 		      uint64_t time,
 		      double dx,
diff --git a/src/libinput.c b/src/libinput.c
index 279cce0..a1d9cd8 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -52,6 +52,7 @@ struct libinput_event_keyboard {
 	uint32_t key;
 	uint32_t seat_key_count;
 	enum libinput_key_state state;
+	char *utf8;
 };
 
 struct libinput_event_pointer {
@@ -169,6 +170,7 @@ libinput_event_get_pointer_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_DEVICE_ADDED:
 	case LIBINPUT_EVENT_DEVICE_REMOVED:
 	case LIBINPUT_EVENT_KEYBOARD_KEY:
+	case LIBINPUT_EVENT_KEYBOARD_STRING:
 		break;
 	case LIBINPUT_EVENT_POINTER_MOTION:
 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
@@ -196,6 +198,7 @@ libinput_event_get_keyboard_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_DEVICE_REMOVED:
 		break;
 	case LIBINPUT_EVENT_KEYBOARD_KEY:
+	case LIBINPUT_EVENT_KEYBOARD_STRING:
 		return (struct libinput_event_keyboard *) event;
 	case LIBINPUT_EVENT_POINTER_MOTION:
 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
@@ -221,6 +224,7 @@ libinput_event_get_touch_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_DEVICE_ADDED:
 	case LIBINPUT_EVENT_DEVICE_REMOVED:
 	case LIBINPUT_EVENT_KEYBOARD_KEY:
+	case LIBINPUT_EVENT_KEYBOARD_STRING:
 	case LIBINPUT_EVENT_POINTER_MOTION:
 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
 	case LIBINPUT_EVENT_POINTER_BUTTON:
@@ -247,6 +251,7 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_DEVICE_REMOVED:
 		return (struct libinput_event_device_notify *) event;
 	case LIBINPUT_EVENT_KEYBOARD_KEY:
+	case LIBINPUT_EVENT_KEYBOARD_STRING:
 	case LIBINPUT_EVENT_POINTER_MOTION:
 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
 	case LIBINPUT_EVENT_POINTER_BUTTON:
@@ -274,6 +279,12 @@ libinput_event_keyboard_get_key(struct libinput_event_keyboard *event)
 	return event->key;
 }
 
+LIBINPUT_EXPORT const char *
+libinput_event_keyboard_get_string(struct libinput_event_keyboard *event)
+{
+	return event->utf8;
+}
+
 LIBINPUT_EXPORT enum libinput_key_state
 libinput_event_keyboard_get_key_state(struct libinput_event_keyboard *event)
 {
@@ -589,6 +600,12 @@ libinput_event_destroy(struct libinput_event *event)
 	if (event == NULL)
 		return;
 
+	if (event->type == LIBINPUT_EVENT_KEYBOARD_STRING) {
+		struct libinput_event_keyboard *k =
+			libinput_event_get_keyboard_event(event);
+		free(k->utf8);
+	}
+
 	if (event->device)
 		libinput_device_unref(event->device);
 
@@ -904,6 +921,37 @@ keyboard_notify_key(struct libinput_device *device,
 }
 
 void
+keyboard_notify_string(struct libinput_device *device,
+		       uint64_t time,
+		       const char *utf8,
+		       enum libinput_key_state state)
+{
+	struct libinput_event_keyboard *key_event;
+	char *string;
+
+	string = strdup(utf8);
+
+	if (!string)
+		return;
+
+	key_event = zalloc(sizeof *key_event);
+	if (!key_event)
+		return;
+
+	*key_event = (struct libinput_event_keyboard) {
+		.time = time,
+		.utf8 = string,
+		.state = state,
+		.seat_key_count = 0,
+	};
+
+	post_device_event(device, time,
+			  LIBINPUT_EVENT_KEYBOARD_STRING,
+			  &key_event->base);
+}
+
+
+void
 pointer_notify_motion(struct libinput_device *device,
 		      uint64_t time,
 		      double dx,
diff --git a/src/libinput.h b/src/libinput.h
index 0e2ba6b..49a0041 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -291,8 +291,18 @@ enum libinput_event_type {
 	 */
 	LIBINPUT_EVENT_DEVICE_REMOVED,
 
+	/**
+	 * The event contains a keycode describing a HW key position. Use
+	 * a keyboard layout to get to the keysym.
+	 */
 	LIBINPUT_EVENT_KEYBOARD_KEY = 300,
 
+	/**
+	 * The event contains a layout-independent string generated by a key
+	 * event.
+	 */
+	LIBINPUT_EVENT_KEYBOARD_STRING,
+
 	LIBINPUT_EVENT_POINTER_MOTION = 400,
 	LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
 	LIBINPUT_EVENT_POINTER_BUTTON,
@@ -460,6 +470,9 @@ libinput_event_keyboard_get_time(struct libinput_event_keyboard *event);
 /**
  * @ingroup event_keyboard
  *
+ * @note It is an application bug to call this function for events other than
+ * LIBINPUT_EVENT_KEYBOARD_KEY. For other events, this function returns 0.
+ *
  * @return The keycode that triggered this key event
  */
 uint32_t
@@ -468,6 +481,27 @@ libinput_event_keyboard_get_key(struct libinput_event_keyboard *event);
 /**
  * @ingroup event_keyboard
  *
+ * Return the UTF-8 encoded string generated by one or more physical key
+ * events. The mapping between physical key presses and keysyms is N:M, i.e.
+ * any number of physical presses may generate any string length. If
+ * multiple physical events are required to generate one string, only one
+ * press/release pair of LIBINPUT_EVENT_KEYBOARD_STRING event is passed to
+ * the caller.
+ *
+ * The lifetime of the returned string is that of the struct libinput_event.
+ *
+ * @note It is an application bug to call this function for events other than
+ * LIBINPUT_EVENT_KEYBOARD_STRING. For other events, this function returns
+ * NULL.
+ *
+ * @return A null-terminated UTF-8 encoded string triggered by this key event.
+ */
+const char *
+libinput_event_keyboard_get_string(struct libinput_event_keyboard *event);
+
+/**
+ * @ingroup event_keyboard
+ *
  * @return The state change of the key
  */
 enum libinput_key_state
diff --git a/tools/event-debug.c b/tools/event-debug.c
index 2a48e2d..4d969f3 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -213,6 +213,9 @@ print_event_header(struct libinput_event *ev)
 	case LIBINPUT_EVENT_KEYBOARD_KEY:
 		type = "KEYBOARD_KEY";
 		break;
+	case LIBINPUT_EVENT_KEYBOARD_STRING:
+		type = "KEYBOARD_STRING";
+		break;
 	case LIBINPUT_EVENT_POINTER_MOTION:
 		type = "POINTER_MOTION";
 		break;
@@ -305,6 +308,22 @@ print_key_event(struct libinput_event *ev)
 }
 
 static void
+print_key_string_event(struct libinput_event *ev)
+{
+	struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
+	enum libinput_key_state state;
+	const char *utf8;
+
+	print_event_time(libinput_event_keyboard_get_time(k));
+	state = libinput_event_keyboard_get_key_state(k);
+	utf8 = libinput_event_keyboard_get_string(k);
+
+	printf("%s %s\n",
+	       utf8,
+	       state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released");
+}
+
+static void
 print_motion_event(struct libinput_event *ev)
 {
 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
@@ -415,6 +434,9 @@ handle_and_print_events(struct libinput *li)
 		case LIBINPUT_EVENT_KEYBOARD_KEY:
 			print_key_event(ev);
 			break;
+		case LIBINPUT_EVENT_KEYBOARD_STRING:
+			print_key_string_event(ev);
+			break;
 		case LIBINPUT_EVENT_POINTER_MOTION:
 			print_motion_event(ev);
 			break;
diff --git a/tools/event-gui.c b/tools/event-gui.c
index b6d21b6..70c9352 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -471,6 +471,8 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
 				return FALSE;
 			}
 			break;
+		case LIBINPUT_EVENT_KEYBOARD_STRING:
+			break;
 		}
 
 		libinput_event_destroy(ev);
-- 
2.1.0



More information about the wayland-devel mailing list