[PATCH libevdev 4/6] Send an extra ABS_MT_SLOT event to sync the client up with the current slot

Peter Hutterer peter.hutterer at who-t.net
Wed Mar 5 20:44:28 PST 2014


From: Benjamin Tissoires <btissoire at redhat.com>

If multiple slots have changed during the sync handling, the client must be
re-set to the current slot before continuing with normal events.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 libevdev/libevdev.c         | 25 +++++++++++-
 test/test-libevdev-events.c | 93 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 116 insertions(+), 2 deletions(-)

diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
index 7ba4629..958580f 100644
--- a/libevdev/libevdev.c
+++ b/libevdev/libevdev.c
@@ -551,9 +551,12 @@ out:
 static int
 sync_mt_state(struct libevdev *dev, int create_events)
 {
+	struct input_event *ev;
+	struct input_absinfo abs_info;
 	int rc;
 	int axis, slot;
 	int ioctl_success = 0;
+	int last_reported_slot = 0;
 	struct mt_state {
 		int code;
 		int val[MAX_SLOTS];
@@ -599,14 +602,18 @@ sync_mt_state(struct libevdev *dev, int create_events)
 		}
 	}
 
-	for (slot = 0; create_events && slot < min(dev->num_slots, MAX_SLOTS); slot++) {
-		struct input_event *ev;
+	if (!create_events) {
+		rc = 0;
+		goto out;
+	}
 
+	for (slot = 0; slot < min(dev->num_slots, MAX_SLOTS); slot++) {
 		if (!bit_is_set(slot_update, AXISBIT(slot, ABS_MT_SLOT)))
 			continue;
 
 		ev = queue_push(dev);
 		init_event(dev, ev, EV_ABS, ABS_MT_SLOT, slot);
+		last_reported_slot = slot;
 
 		for (axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
 			if (axis == ABS_MT_SLOT ||
@@ -620,6 +627,20 @@ sync_mt_state(struct libevdev *dev, int create_events)
 		}
 	}
 
+	/* add one last slot event to make sure the client is on the same
+	   slot as the kernel */
+
+	rc = ioctl(dev->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
+	if (rc < 0)
+		goto out;
+
+	dev->current_slot = abs_info.value;
+
+	if (dev->current_slot != last_reported_slot) {
+		ev = queue_push(dev);
+		init_event(dev, ev, EV_ABS, ABS_MT_SLOT, dev->current_slot);
+	}
+
 #undef AXISBIT
 
 	rc = 0;
diff --git a/test/test-libevdev-events.c b/test/test-libevdev-events.c
index 5d38c62..eca8a94 100644
--- a/test/test-libevdev-events.c
+++ b/test/test-libevdev-events.c
@@ -585,6 +585,93 @@ START_TEST(test_syn_delta_mt)
 }
 END_TEST
 
+START_TEST(test_syn_delta_mt_reset_slot)
+{
+	struct uinput_device* uidev;
+	struct libevdev *dev;
+	int rc;
+	struct input_event ev,
+			   last_slot_event = { .type = 0};
+	struct input_absinfo abs[6];
+
+	memset(abs, 0, sizeof(abs));
+	abs[0].value = ABS_X;
+	abs[0].maximum = 1000;
+	abs[1].value = ABS_MT_POSITION_X;
+	abs[1].maximum = 1000;
+
+	abs[2].value = ABS_Y;
+	abs[2].maximum = 1000;
+	abs[3].value = ABS_MT_POSITION_Y;
+	abs[3].maximum = 1000;
+
+
+	abs[4].value = ABS_MT_SLOT;
+	abs[4].maximum = 1;
+	abs[5].value = ABS_MT_TRACKING_ID;
+	abs[5].minimum = -1;
+	abs[5].maximum = 2;
+
+	rc = test_create_abs_device(&uidev, &dev,
+				    6, abs,
+				    EV_SYN, SYN_REPORT,
+				    -1);
+	ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
+
+	uinput_device_event(uidev, EV_ABS, ABS_MT_SLOT, 1);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_X, 100);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_Y, 500);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, 1);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_SLOT, 0);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_X, 1);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_Y, 5);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, 2);
+	uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
+
+	rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev);
+	ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SYNC);
+
+	do {
+		rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
+		if (libevdev_event_is_code(&ev, EV_ABS, ABS_MT_SLOT))
+			last_slot_event = ev;
+	} while (rc != -EAGAIN);
+
+	ck_assert(libevdev_event_is_code(&last_slot_event, EV_ABS, ABS_MT_SLOT));
+	ck_assert_int_eq(last_slot_event.value, 0);
+	ck_assert_int_eq(libevdev_get_current_slot(dev), 0);
+
+	last_slot_event.type = 0;
+
+	/* same thing again, this time swap the numbers */
+	uinput_device_event(uidev, EV_ABS, ABS_MT_SLOT, 0);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_X, 100);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_Y, 500);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, 1);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_SLOT, 1);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_X, 1);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_Y, 5);
+	uinput_device_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, 2);
+	uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
+
+	rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev);
+	ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SYNC);
+
+	do {
+		rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
+		if (libevdev_event_is_code(&ev, EV_ABS, ABS_MT_SLOT))
+			last_slot_event = ev;
+	} while (rc != -EAGAIN);
+
+	ck_assert(libevdev_event_is_code(&last_slot_event, EV_ABS, ABS_MT_SLOT));
+	ck_assert_int_eq(last_slot_event.value, 1);
+	ck_assert_int_eq(libevdev_get_current_slot(dev), 1);
+
+	uinput_device_free(uidev);
+	libevdev_free(dev);
+}
+END_TEST
+
 START_TEST(test_syn_delta_mt_too_many)
 {
 	struct uinput_device* uidev;
@@ -656,6 +743,11 @@ START_TEST(test_syn_delta_mt_too_many)
 		ck_assert_int_lt(slot, MAX_SLOTS);
 
 		rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
+
+		/* last MT_SLOT event is on its own */
+		if (libevdev_event_is_code(&ev, EV_SYN, SYN_REPORT))
+			break;
+
 		ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SYNC);
 		ck_assert_int_eq(ev.type, EV_ABS);
 		ck_assert_int_eq(ev.code, ABS_MT_POSITION_X);
@@ -1590,6 +1682,7 @@ libevdev_events(void)
 	tcase_add_test(tc, test_syn_delta_abs);
 	tcase_add_test(tc, test_syn_delta_mt);
 	tcase_add_test(tc, test_syn_delta_mt_too_many);
+	tcase_add_test(tc, test_syn_delta_mt_reset_slot);
 	tcase_add_test(tc, test_syn_delta_led);
 	tcase_add_test(tc, test_syn_delta_sw);
 	tcase_add_test(tc, test_syn_delta_fake_mt);
-- 
1.8.5.3



More information about the Input-tools mailing list