[PATCH xf86-input-libinput] Support for rel+abs composite devices on the same node

Gergely Nagy algernon at madhouse-project.org
Sat Mar 11 11:26:38 UTC 2017


Largely based on work by Peter Hutterer, this patch makes composite relative +
absolute devices work with the driver. Such devices are anything that presents
itself as both a mouse, and - for example - a touch screen, like the Keyboardio
Model 01 (or anything that uses Nico Hood's HID library for Arduino).

If a device has both capabilities present, we split them into two separate
devices for X (see xf86libinput_pre_init()), like we do with the composite
keyboard + mouse devices. Then, we route absolute events to the absolute
subdevice (see xf86libinput_pick_device()). The rest of the patch is mostly
small updates to support the newly introduced CAP_POINTER_ABSOLUTE flag.

There's one missing thing, however: event routing for buttons. At the moment,
button routing is simply not done, but in practice, this does not seem to have
any ill side effects.

https://bugs.freedesktop.org/show_bug.cgi?id=99914

Signed-off-by: Gergely Nagy <algernon at madhouse-project.org>
---
 src/xf86libinput.c | 81 ++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 58 insertions(+), 23 deletions(-)

diff --git a/src/xf86libinput.c b/src/xf86libinput.c
index 888c8f2..a099c5b 100644
--- a/src/xf86libinput.c
+++ b/src/xf86libinput.c
@@ -87,6 +87,7 @@
 #define CAP_TABLET	0x8
 #define CAP_TABLET_TOOL	0x10
 #define CAP_TABLET_PAD	0x20
+#define CAP_POINTER_ABSOLUTE	0x40
 
 struct xf86libinput_driver {
 	struct libinput *libinput;
@@ -805,6 +806,20 @@ xf86libinput_init_pointer_absolute(InputInfoPtr pInfo)
 	Atom btnlabels[MAX_BUTTONS];
 	Atom axislabels[TOUCHPAD_NUM_AXES];
 
+	/* We always initialize rel as parent on absrel devices */
+	if (xf86libinput_is_subdevice(pInfo)) {
+		/*
+		 * FIXME: well, we can't really know which buttons belong to
+		 * which device here, but adding it to both doesn't make
+		 * sense either. Options are: assume LMR is on rel, BTN_0
+		 * and friends on absolute. That's not always correct but
+		 * that's as best as we can do.
+		 *
+		 * FIXME: event routing for buttons isn't set up correctly
+		 * yet.
+		 */
+	}
+
 	for (i = BTN_BACK; i >= BTN_SIDE; i--) {
 		if (libinput_device_pointer_has_button(device, i)) {
 			nbuttons += i - BTN_SIDE + 1;
@@ -1179,13 +1194,10 @@ xf86libinput_init(DeviceIntPtr dev)
 
 	if (driver_data->capabilities & CAP_KEYBOARD)
 		xf86libinput_init_keyboard(pInfo);
-	if (driver_data->capabilities & CAP_POINTER) {
-		if (libinput_device_config_calibration_has_matrix(device) &&
-		    !libinput_device_config_accel_is_available(device))
-			xf86libinput_init_pointer_absolute(pInfo);
-		else
-			xf86libinput_init_pointer(pInfo);
-	}
+	if (driver_data->capabilities & CAP_POINTER)
+		xf86libinput_init_pointer(pInfo);
+	if (driver_data->capabilities & CAP_POINTER_ABSOLUTE)
+		xf86libinput_init_pointer_absolute(pInfo);
 	if (driver_data->capabilities & CAP_TOUCH)
 		xf86libinput_init_touch(pInfo);
 	if (driver_data->capabilities & CAP_TABLET_TOOL)
@@ -1347,7 +1359,7 @@ xf86libinput_handle_absmotion(InputInfoPtr pInfo, struct libinput_event_pointer
 		return;
 	}
 
-	if ((driver_data->capabilities & CAP_POINTER) == 0)
+	if ((driver_data->capabilities & CAP_POINTER_ABSOLUTE) == 0)
 		return;
 
 	x = libinput_event_pointer_get_absolute_x_transformed(event, TOUCH_AXIS_MAX);
@@ -1368,7 +1380,7 @@ xf86libinput_handle_button(InputInfoPtr pInfo, struct libinput_event_pointer *ev
 	int button;
 	int is_press;
 
-	if ((driver_data->capabilities & CAP_POINTER) == 0)
+	if ((driver_data->capabilities & (CAP_POINTER|CAP_POINTER_ABSOLUTE)) == 0)
 		return;
 
 	button = btn_linux2xorg(libinput_event_pointer_get_button(event));
@@ -1493,7 +1505,7 @@ xf86libinput_handle_axis(InputInfoPtr pInfo, struct libinput_event_pointer *even
 	double value;
 	enum libinput_pointer_axis_source source;
 
-	if ((driver_data->capabilities & CAP_POINTER) == 0)
+	if ((driver_data->capabilities & (CAP_POINTER|CAP_POINTER_ABSOLUTE)) == 0)
 		return;
 
 	valuator_mask_zero(mask);
@@ -1600,6 +1612,9 @@ xf86libinput_pick_device(struct xf86libinput_device *shared_device,
 	case LIBINPUT_EVENT_TABLET_TOOL_TIP:
 		needed_cap = CAP_TABLET_TOOL;
 		break;
+	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+		needed_cap = CAP_POINTER_ABSOLUTE;
+		break;
 	default:
 		needed_cap = ~CAP_KEYBOARD;
 		break;
@@ -2940,7 +2955,7 @@ xf86libinput_get_type_name(struct libinput_device *device,
 	/* now pick an actual type */
 	if (libinput_device_config_tap_get_finger_count(device) > 0)
 		type_name = XI_TOUCHPAD;
-	else if (driver_data->capabilities & CAP_TOUCH)
+	else if (driver_data->capabilities & (CAP_TOUCH|CAP_POINTER_ABSOLUTE))
 		type_name = XI_TOUCHSCREEN;
 	else if (driver_data->capabilities & CAP_POINTER)
 		type_name = XI_MOUSE;
@@ -3054,6 +3069,8 @@ xf86libinput_create_subdevice(InputInfoPtr pInfo,
 		options = xf86ReplaceBoolOption(options, "_libinput/cap-keyboard", 1);
 	if (capabilities & CAP_POINTER)
 		options = xf86ReplaceBoolOption(options, "_libinput/cap-pointer", 1);
+	if (capabilities & CAP_POINTER_ABSOLUTE)
+		options = xf86ReplaceBoolOption(options, "_libinput/cap-pointer-absolute", 1);
 	if (capabilities & CAP_TOUCH)
 		options = xf86ReplaceBoolOption(options, "_libinput/cap-touch", 1);
 	if (capabilities & CAP_TABLET_TOOL)
@@ -3092,6 +3109,8 @@ caps_from_options(InputInfoPtr pInfo)
 		capabilities |= CAP_KEYBOARD;
 	if (xf86CheckBoolOption(pInfo->options, "_libinput/cap-pointer", 0))
 		capabilities |= CAP_POINTER;
+	if (xf86CheckBoolOption(pInfo->options, "_libinput/cap-pointer-absolute", 0))
+		capabilities |= CAP_POINTER_ABSOLUTE;
 	if (xf86CheckBoolOption(pInfo->options, "_libinput/cap-touch", 0))
 		capabilities |= CAP_TOUCH;
 	if (xf86CheckBoolOption(pInfo->options, "_libinput/cap-tablet-tool", 0))
@@ -3230,8 +3249,13 @@ xf86libinput_pre_init(InputDriverPtr drv,
 	driver_data->scroll.hdist = 15;
 
 	if (!is_subdevice) {
-		if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER))
-			driver_data->capabilities |= CAP_POINTER;
+		if (libinput_device_has_capability(device,
+						   LIBINPUT_DEVICE_CAP_POINTER)) {
+			if (libinput_device_config_calibration_has_matrix(device))
+				driver_data->capabilities |= CAP_POINTER_ABSOLUTE;
+			if (libinput_device_config_accel_is_available(device))
+				driver_data->capabilities |= CAP_POINTER;
+		}
 		if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
 			driver_data->capabilities |= CAP_KEYBOARD;
 		if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH))
@@ -3254,15 +3278,26 @@ xf86libinput_pre_init(InputDriverPtr drv,
 
 	xf86libinput_parse_options(pInfo, driver_data, device);
 
-	/* Device is both keyboard and pointer. Drop the keyboard cap from
-	 * this device, create a separate device instead */
-	if (!is_subdevice &&
-	    driver_data->capabilities & CAP_KEYBOARD &&
-	    driver_data->capabilities & (CAP_POINTER|CAP_TOUCH)) {
-		driver_data->capabilities &= ~CAP_KEYBOARD;
-		xf86libinput_create_subdevice(pInfo,
-					      CAP_KEYBOARD,
-					      NULL);
+	if (!is_subdevice) {
+		/* Device is both keyboard and pointer. Drop the keyboard cap from
+		 * this device, create a separate device instead */
+		if (driver_data->capabilities & CAP_KEYBOARD &&
+		    driver_data->capabilities & (CAP_POINTER|CAP_POINTER_ABSOLUTE|CAP_TOUCH)) {
+			driver_data->capabilities &= ~CAP_KEYBOARD;
+			xf86libinput_create_subdevice(pInfo,
+						      CAP_KEYBOARD,
+						      NULL);
+		}
+		/* Device is both relative and absolute. Drop the absolute
+		 * cap from this device, create a separate device instead */
+		if (driver_data->capabilities & CAP_POINTER &&
+		    driver_data->capabilities & CAP_POINTER_ABSOLUTE) {
+			driver_data->capabilities &= ~CAP_POINTER_ABSOLUTE;
+			xf86libinput_create_subdevice(pInfo,
+						      CAP_POINTER_ABSOLUTE,
+						      NULL);
+		}
+
 	}
 
 	pInfo->type_name = xf86libinput_get_type_name(device, driver_data);
@@ -4571,7 +4606,7 @@ LibinputInitAccelProperty(DeviceIntPtr dev,
 	BOOL profiles[2] = {FALSE};
 
 	if (!libinput_device_config_accel_is_available(device) ||
-	    driver_data->capabilities & CAP_TABLET)
+	    driver_data->capabilities & (CAP_TABLET|CAP_POINTER_ABSOLUTE))
 		return;
 
 	prop_accel = LibinputMakeProperty(dev,
-- 
2.11.0



More information about the xorg-devel mailing list