[PATCH xf86-input-libinput] Handle capability events after adding a device

Peter Hutterer peter.hutterer at who-t.net
Thu Jan 29 21:31:40 PST 2015


Needs a temporary libinput context to get all capability events without
events from other devices interfering.

This doesn't yet handle true capability changes, only the initial burst of
events after the DEVICE_ADDED event.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
That's based on a patchset scheduled for libinput 0.10 

 src/libinput.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 61 insertions(+), 7 deletions(-)

diff --git a/src/libinput.c b/src/libinput.c
index a24cbff..29a624c 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -51,6 +51,8 @@
 #define TOUCH_MAX_SLOTS 15
 #define XORG_KEYCODE_OFFSET 8
 
+#define AS_MASK(v) (1 << v)
+
 /*
    libinput does not provide axis information for absolute devices, instead
    it scales into the screen dimensions provided. So we set up the axes with
@@ -70,6 +72,7 @@ static struct xf86libinput_driver driver_context;
 struct xf86libinput {
 	char *path;
 	struct libinput_device *device;
+	unsigned int capabilities;
 
 	int scroll_vdist;
 	int scroll_hdist;
@@ -600,15 +603,15 @@ xf86libinput_init(DeviceIntPtr dev)
 
 	dev->public.on = FALSE;
 
-	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
+	if (driver_data->capabilities & AS_MASK(LIBINPUT_DEVICE_CAP_KEYBOARD))
 		xf86libinput_init_keyboard(pInfo);
-	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) {
+	if (driver_data->capabilities & AS_MASK(LIBINPUT_DEVICE_CAP_POINTER)) {
 		if (libinput_device_config_calibration_has_matrix(device))
 			xf86libinput_init_pointer_absolute(pInfo);
 		else
 			xf86libinput_init_pointer(pInfo);
 	}
-	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH))
+	if (driver_data->capabilities & AS_MASK(LIBINPUT_DEVICE_CAP_TOUCH))
 		xf86libinput_init_touch(pInfo);
 
 	/* unref the device now, because we'll get a new ref during
@@ -815,6 +818,8 @@ xf86libinput_handle_event(struct libinput_event *event)
 		case LIBINPUT_EVENT_NONE:
 		case LIBINPUT_EVENT_DEVICE_ADDED:
 		case LIBINPUT_EVENT_DEVICE_REMOVED:
+		case LIBINPUT_EVENT_DEVICE_CAPABILITY_ADDED:
+		case LIBINPUT_EVENT_DEVICE_CAPABILITY_REMOVED:
 			break;
 		case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
 			xf86libinput_handle_absmotion(pInfo,
@@ -1117,6 +1122,49 @@ xf86libinput_parse_options(InputInfoPtr pInfo,
 
 }
 
+/* libinput sends capabilities as events after opening the device. In X we
+   need the capabilities to be done when we get to DEVICE_INIT.
+   The capability events may be intermixed with real events from other
+   devices, making handling device init a lot more complicated than it needs
+   to be. To avoid this, we create a temporary libinput context, pull the
+   capability events off the context, then ignore them in the main context.
+ */
+static int
+get_capabilities(const char *path)
+{
+	int rc = -1;
+	struct libinput *libinput = NULL;
+	struct libinput_device *device;
+	struct libinput_event *event;
+	struct libinput_event_device_capability *cap;
+
+	libinput = libinput_path_create_context(&interface,
+						&driver_context);
+	if (!libinput)
+		goto out;
+
+
+	device = libinput_path_add_device(libinput, path);
+	if (!device)
+		goto out;
+
+	libinput_dispatch(libinput);
+
+	rc = 0;
+	while ((event = libinput_get_event(libinput))) {
+		if (libinput_event_get_type(event) == LIBINPUT_EVENT_DEVICE_CAPABILITY_ADDED) {
+			cap = libinput_event_get_device_capability_event(event);
+			rc |= AS_MASK(libinput_event_device_capability_get_capability(cap));
+		}
+		libinput_event_destroy(event);
+	}
+
+out:
+	libinput_unref(libinput);
+
+	return rc;
+}
+
 static int
 xf86libinput_pre_init(InputDriverPtr drv,
 		      InputInfoPtr pInfo,
@@ -1125,6 +1173,7 @@ xf86libinput_pre_init(InputDriverPtr drv,
 	struct xf86libinput *driver_data = NULL;
         struct libinput *libinput = NULL;
 	struct libinput_device *device;
+	int capabilities;
 	char *path;
 
 	pInfo->type_name = 0;
@@ -1170,6 +1219,12 @@ xf86libinput_pre_init(InputDriverPtr drv,
 	if (use_server_fd(pInfo))
 		fd_push(&driver_context, pInfo->fd, path);
 
+	capabilities = get_capabilities(path);
+	if (capabilities == -1) {
+		xf86IDrvMsg(pInfo, X_ERROR, "Failed to create a device for %s\n", path);
+		goto fail;
+	}
+
 	device = libinput_path_add_device(libinput, path);
 	if (!device) {
 		xf86IDrvMsg(pInfo, X_ERROR, "Failed to create a device for %s\n", path);
@@ -1187,6 +1242,7 @@ xf86libinput_pre_init(InputDriverPtr drv,
 	pInfo->private = driver_data;
 	driver_data->path = path;
 	driver_data->device = device;
+	driver_data->capabilities = (unsigned int)capabilities;
 
 	/* Disable acceleration in the server, libinput does it for us */
 	pInfo->options = xf86ReplaceIntOption(pInfo->options, "AccelerationProfile", -1);
@@ -1197,11 +1253,9 @@ xf86libinput_pre_init(InputDriverPtr drv,
 	/* now pick an actual type */
 	if (libinput_device_config_tap_get_finger_count(device) > 0)
 		pInfo->type_name = XI_TOUCHPAD;
-	else if (libinput_device_has_capability(device,
-						LIBINPUT_DEVICE_CAP_TOUCH))
+	else if (capabilities & AS_MASK(LIBINPUT_DEVICE_CAP_TOUCH))
 		pInfo->type_name = XI_TOUCHSCREEN;
-	else if (libinput_device_has_capability(device,
-						LIBINPUT_DEVICE_CAP_POINTER))
+	else if (capabilities & AS_MASK(LIBINPUT_DEVICE_CAP_POINTER))
 		pInfo->type_name = XI_MOUSE;
 	else
 		pInfo->type_name = XI_KEYBOARD;
-- 
2.1.0



More information about the xorg-devel mailing list