Add udev bits to assign LIBINPUT_DEVICE_GROUP
authorPeter Hutterer <peter.hutterer@who-t.net>
Tue, 10 Feb 2015 04:23:32 +0000 (14:23 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 18 Feb 2015 00:08:29 +0000 (10:08 +1000)
The easiest way to get a device group is by looking at the phys path of the
input device (which looks like usb-0000:00:14.0-1/input1) and dropping the
/inputX bit. The rest is the same for devices that belong together (except on
the Cintiq 22HD Touch).

Ideally we could just take ATTRS{phys} but we can't select substrings to drop
into ENV so we need to do it ourselves. This patch adds a callout that takes a
syspath and prints the mangled path, to be used in LIBINPUT_DEVICE_GROUP.

The rule triggers on any device that has a non-zero phys attribute, this
groups devices like tablets together but also devices like mice with multiple
interfaces.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Tested-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
Makefile.am
configure.ac
udev/.gitignore [new file with mode: 0644]
udev/80-libinput-device-groups.rules [new file with mode: 0644]
udev/Makefile.am [new file with mode: 0644]
udev/libinput-device-group.c [new file with mode: 0644]

index 05698ba5a4ddde8655c3550490786db2e3ad2f0a..fc6e6b790d2a8eb7d4b5b61e63cb91691bd8d159 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = src doc test tools
+SUBDIRS = src doc test tools udev
 
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
index 1e60e58549e85bc7a819f2693d01ce5b6a1b18f1..2ccd30d7ffa83f35389f18799d924b168a430bf5 100644 (file)
@@ -69,6 +69,19 @@ fi
 AC_SUBST(GCC_CFLAGS)
 AC_SUBST(GCC_CXXFLAGS)
 
+udev_dir_default="$libdir/udev"
+AC_ARG_WITH(udev-dir,
+            AS_HELP_STRING([--with-udev-dir=DIR],
+                           [udev base directory [[default=$udev_dir_default]]]),
+            [],
+            [with_udev_dir="yes"])
+AS_CASE($with_udev_dir,
+       [no|""], [AC_MSG_ERROR([You must define a udev base directory])],
+       [yes], [udevdir="$udev_dir_default"],
+       [udevdir="$with_udev_dir"])
+UDEV_DIR=${udevdir}
+AC_SUBST(UDEV_DIR)
+
 AC_ARG_ENABLE([documentation],
              [AC_HELP_STRING([--enable-documentation],
                              [Enable building the documentation (default=auto)])],
@@ -163,14 +176,15 @@ AC_CONFIG_FILES([Makefile
                 src/libinput.pc
                 src/libinput-version.h
                 test/Makefile
-                tools/Makefile])
+                tools/Makefile
+                udev/Makefile])
 AC_CONFIG_FILES([test/symbols-leak-test],
                [chmod +x test/symbols-leak-test])
-
 AC_OUTPUT
 
 AC_MSG_RESULT([
        Prefix                  ${prefix}
+       udev base dir           ${UDEV_DIR}
 
        Build documentation     ${build_documentation}
        Build tests             ${build_tests}
diff --git a/udev/.gitignore b/udev/.gitignore
new file mode 100644 (file)
index 0000000..d8e1456
--- /dev/null
@@ -0,0 +1 @@
+libinput-device-group
diff --git a/udev/80-libinput-device-groups.rules b/udev/80-libinput-device-groups.rules
new file mode 100644 (file)
index 0000000..f826bec
--- /dev/null
@@ -0,0 +1,8 @@
+ACTION!="add|change", GOTO="libinput_device_group_end"
+KERNEL!="event[0-9]*", GOTO="libinput_device_group_end"
+
+ATTRS{phys}=="?*", \
+       PROGRAM="libinput-device-group %S%p", \
+       ENV{LIBINPUT_DEVICE_GROUP}="%c"
+
+LABEL="libinput_device_group_end"
diff --git a/udev/Makefile.am b/udev/Makefile.am
new file mode 100644 (file)
index 0000000..3691172
--- /dev/null
@@ -0,0 +1,9 @@
+udevdir=$(UDEV_DIR)
+udev_PROGRAMS = libinput-device-group
+
+libinput_device_group_SOURCES = libinput-device-group.c
+libinput_device_group_CFLAGS = $(LIBUDEV_CFLAGS) $(GCC_CFLAGS)
+libinput_device_group_LDADD = $(LIBUDEV_LIBS)
+
+udev_rulesdir=$(UDEV_DIR)/rules.d
+dist_udev_rules_DATA = 80-libinput-device-groups.rules
diff --git a/udev/libinput-device-group.c b/udev/libinput-device-group.c
new file mode 100644 (file)
index 0000000..50bfbe0
--- /dev/null
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libudev.h>
+
+int main(int argc, char **argv)
+{
+       int rc = 1;
+       struct udev *udev = NULL;
+       struct udev_device *device = NULL;
+       const char *syspath,
+                  *phys = NULL;
+       char *group,
+            *str;
+
+       if (argc != 2)
+               return 1;
+
+       syspath = argv[1];
+
+       udev = udev_new();
+       if (!udev)
+               goto out;
+
+       device = udev_device_new_from_syspath(udev, syspath);
+       if (!device)
+               goto out;
+
+       /* Find the first parent with ATTRS{phys} set. For tablets that
+        * value looks like usb-0000:00:14.0-1/input1. Drop the /input1
+        * bit and use the remainder as device group identifier */
+       while (device != NULL) {
+               struct udev_device *parent;
+
+               phys = udev_device_get_sysattr_value(device, "phys");
+               if (phys)
+                       break;
+
+               parent = udev_device_get_parent(device);
+               udev_device_ref(parent);
+               udev_device_unref(device);
+               device = parent;
+       }
+
+       if (!phys)
+               goto out;
+
+       group = strdup(phys);
+       if (!group)
+               goto out;
+
+       str = strstr(group, "/input");
+       if (str)
+               *str = '\0';
+
+       /* Cintiq 22HD Touch has
+          usb-0000:00:14.0-6.3.1/input0 for the touch
+          usb-0000:00:14.0-6.3.0/input0 for the pen
+          Check if there's a . after the last -, if so, cut off the string
+          there.
+         */
+       str = strrchr(group, '.');
+       if (str && str > strrchr(group, '-'))
+               *str = '\0';
+
+       printf("%s\n", group);
+       free(group);
+
+       rc = 0;
+out:
+       if (device)
+               udev_device_unref(device);
+       if (udev)
+               udev_unref(udev);
+
+       return rc;
+}