diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox
index bee36598..68a45af0 100644
--- a/doc/device-configuration-via-udev.dox
+++ b/doc/device-configuration-via-udev.dox
@@ -12,6 +12,11 @@ The following udev properties are supported:
Sets the calibration matrix, see
libinput_device_config_calibration_get_default_matrix(). If unset,
defaults to the identity matrix.
+LIBINPUT_DEVICE_GROUP
+A string identifying the @ref libinput_device_group for this device. Two
+devices with the same property value are grouped into the same device group,
+the value itself is irrelevant otherwise.
+
ID_SEAT
Assigns the physical seat for this device. See
libinput_seat_get_physical_name(). Defaults to "seat0".
diff --git a/src/evdev.c b/src/evdev.c
index 525d5d7c..11fa89ba 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1579,6 +1579,42 @@ out:
return rc;
}
+static int
+evdev_set_device_group(struct evdev_device *device,
+ struct udev_device *udev_device)
+{
+ struct libinput_device_group *group = NULL;
+ const char *udev_group;
+
+ udev_group = udev_device_get_property_value(udev_device,
+ "LIBINPUT_DEVICE_GROUP");
+ if (udev_group) {
+ struct libinput_device *d;
+
+ list_for_each(d, &device->base.seat->devices_list, link) {
+ const char *identifier = d->group->identifier;
+
+ if (identifier &&
+ strcmp(identifier, udev_group) == 0) {
+ group = d->group;
+ break;
+ }
+ }
+ }
+
+ if (!group) {
+ group = libinput_device_group_create(udev_group);
+ if (!group)
+ return 1;
+ libinput_device_set_device_group(&device->base, group);
+ libinput_device_group_unref(group);
+ } else {
+ libinput_device_set_device_group(&device->base, group);
+ }
+
+ return 0;
+}
+
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
struct udev_device *udev_device)
@@ -1589,7 +1625,6 @@ evdev_device_create(struct libinput_seat *seat,
int fd;
int unhandled_device = 0;
const char *devnode = udev_device_get_devnode(udev_device);
- struct libinput_device_group *group;
/* Use non-blocking mode so that we can loop on read on
* evdev_device_data() until all events on the fd are
@@ -1660,11 +1695,8 @@ evdev_device_create(struct libinput_seat *seat,
if (!device->source)
goto err;
- group = libinput_device_group_create();
- if (!group)
+ if (evdev_set_device_group(device, udev_device))
goto err;
- libinput_device_set_device_group(&device->base, group);
- libinput_device_group_unref(group);
list_insert(seat->devices_list.prev, &device->base.link);
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 23f66e40..14f5d674 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -168,6 +168,7 @@ struct libinput_device_config {
struct libinput_device_group {
int refcount;
void *user_data;
+ char *identifier; /* unique identifier or NULL for singletons */
};
struct libinput_device {
@@ -247,7 +248,7 @@ libinput_device_init(struct libinput_device *device,
struct libinput_seat *seat);
struct libinput_device_group *
-libinput_device_group_create(void);
+libinput_device_group_create(const char *identifier);
void
libinput_device_set_device_group(struct libinput_device *device,
diff --git a/src/libinput.c b/src/libinput.c
index b903caa6..bb0595e6 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -1407,13 +1407,23 @@ libinput_device_group_ref(struct libinput_device_group *group)
}
struct libinput_device_group *
-libinput_device_group_create(void)
+libinput_device_group_create(const char *identifier)
{
struct libinput_device_group *group;
group = zalloc(sizeof *group);
- if (group)
- group->refcount = 1;
+ if (!group)
+ return NULL;
+
+ group->refcount = 1;
+ if (identifier) {
+ group->identifier = strdup(identifier);
+ if (!group->identifier) {
+ free(group);
+ group = NULL;
+ }
+ }
+
return group;
}
@@ -1428,6 +1438,7 @@ libinput_device_set_device_group(struct libinput_device *device,
static void
libinput_device_group_destroy(struct libinput_device_group *group)
{
+ free(group->identifier);
free(group);
}
diff --git a/src/libinput.h b/src/libinput.h
index 0fdca7b7..09503a29 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -1471,6 +1471,9 @@ libinput_device_get_context(struct libinput_device *device);
* libinput_device_group_unref() to continue using the handle outside of the
* immediate scope.
*
+ * Device groups are assigned based on the LIBINPUT_DEVICE_GROUP udev
+ * property, see @ref udev_config.
+ *
* @return The device group this device belongs to
*/
struct libinput_device_group *