Don't treat devices with (ABS_MT_SLOT - 1) as multitouch devices
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 20 Nov 2013 01:58:08 +0000 (11:58 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Tue, 10 Dec 2013 09:39:47 +0000 (19:39 +1000)
Some devices (PS3 sixaxis controller) merely have a bunch of axes, without the
semantic information that linux/input.h requires. For those, the ABS_MT range
may be merely another axis, not the special range that we need to treat it
with.

Use a simple heuristic: if ABS_MT_SLOT - 1 is enabled, don't treat ABS_MT as
multitouch axes. The ABS_MT_SLOT - 1 axis is not used for a real axis.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
libevdev/libevdev.c
libevdev/libevdev.h
test/test-libevdev-has-event.c

index 60bbbfc..8a37204 100644 (file)
@@ -333,7 +333,12 @@ libevdev_set_fd(struct libevdev* dev, int fd)
                                goto out;
 
                        dev->abs_info[i] = abs_info;
-                       if (i == ABS_MT_SLOT) {
+
+                       /* devices with ABS_MT_SLOT - 1 aren't MT devices,
+                          see the documentation for multitouch-related
+                          functions for more details */
+                       if (i == ABS_MT_SLOT &&
+                           !libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT - 1)) {
                                dev->num_slots = abs_info.maximum + 1;
                                dev->current_slot = abs_info.value;
                        }
@@ -627,7 +632,7 @@ update_key_state(struct libevdev *dev, const struct input_event *e)
 static int
 update_mt_state(struct libevdev *dev, const struct input_event *e)
 {
-       if (e->code == ABS_MT_SLOT) {
+       if (e->code == ABS_MT_SLOT && dev->num_slots > -1) {
                int i;
                dev->current_slot = e->value;
                /* sync abs_info with the current slot values */
index 2b6f48a..44aa3a6 100644 (file)
@@ -361,6 +361,15 @@ extern "C" {
  *
  * As with @ref bits, the logical state of the device as seen by the library
  * depends on the caller using libevdev_next_event().
+ *
+ * The Linux kernel requires all axes on a device to have a semantic
+ * meaning, matching the axis names in linux/input.h. Some devices merely
+ * export a number of axes beyond the available axis list. For those
+ * devices, the multitouch information is invalid. Specfically, if a device
+ * provides the ABS_MT_SLOT axis AND also the (ABS_MT_SLOT - 1) axis, the
+ * device is not treated as multitouch device. No slot information is
+ * available and the ABS_MT axis range for these devices is treated as all
+ * other EV_ABS axes.
  */
 
 /**
index 3aca23b..8beb8c4 100644 (file)
@@ -425,6 +425,38 @@ START_TEST(test_slot_number)
 }
 END_TEST
 
+START_TEST(test_invalid_mt_device)
+{
+       struct uinput_device* uidev;
+       struct libevdev *dev;
+       int rc;
+       const int nslots = 4;
+       int value;
+       struct input_absinfo abs[] = {  { ABS_X, 0, 2 },
+               { ABS_Y, 0, 2 },
+               { ABS_MT_POSITION_X, 0, 2 },
+               { ABS_MT_POSITION_Y, 0, 2 },
+               { ABS_MT_SLOT - 1, 0, 2 },
+               { ABS_MT_SLOT, 0, nslots - 1 }};
+
+       rc = test_create_abs_device(&uidev, &dev, 6, abs,
+                       -1);
+       ck_assert_msg(rc == 0, "Failed to uinput device: %s", strerror(-rc));
+
+       ck_assert_int_eq(libevdev_get_num_slots(dev), -1);
+       ck_assert_int_eq(libevdev_get_current_slot(dev), -1);
+       ck_assert_int_eq(libevdev_set_slot_value(dev, 0, ABS_MT_POSITION_X, 0), -1);
+       ck_assert_int_eq(libevdev_fetch_slot_value(dev, 0, ABS_MT_POSITION_X, &value), 0);
+
+       ck_assert(libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT - 1));
+       ck_assert(libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT));
+
+       ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_MT_SLOT, 1), 0);
+       ck_assert(libevdev_get_event_value(dev, EV_ABS, ABS_MT_SLOT) == 1);
+
+       uinput_device_free(uidev);
+} END_TEST
+
 
 START_TEST(test_device_name)
 {
@@ -1129,6 +1161,7 @@ libevdev_has_event_test(void)
        tcase_add_test(tc, test_no_slots);
        tcase_add_test(tc, test_slot_number);
        tcase_add_test(tc, test_slot_init_value);
+       tcase_add_test(tc, test_invalid_mt_device);
        suite_add_tcase(s, tc);
 
        tc = tcase_create("device info");