mirror of
https://gitlab.freedesktop.org/libevdev/libevdev.git
synced 2025-12-20 17:20:05 +01:00
If the tracking ID changes during SYN_DROPPED, terminate the touch first
Most clients can't deal with tracking ID changes unless a -1 is sent first. So if we notice that the tracking ID has changed during the sync process, send a set of ABS_MT_TRACKING_ID -1 events for each of those, then send the rest of the events. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
parent
d3ae3da90f
commit
41334b5b40
2 changed files with 189 additions and 0 deletions
|
|
@ -562,6 +562,8 @@ sync_mt_state(struct libevdev *dev, int create_events)
|
|||
int val[MAX_SLOTS];
|
||||
} mt_state;
|
||||
unsigned long slot_update[NLONGS(MAX_SLOTS * ABS_MT_CNT)] = {0};
|
||||
unsigned long tracking_id_changes[NLONGS(MAX_SLOTS)] = {0};
|
||||
int need_tracking_id_changes = 0;
|
||||
|
||||
#define AXISBIT(_slot, _axis) (_slot * ABS_MT_CNT + _axis - ABS_MT_MIN)
|
||||
|
||||
|
|
@ -591,6 +593,13 @@ sync_mt_state(struct libevdev *dev, int create_events)
|
|||
if (*slot_value(dev, slot, axis) == mt_state.val[slot])
|
||||
continue;
|
||||
|
||||
if (axis == ABS_MT_TRACKING_ID &&
|
||||
*slot_value(dev, slot, axis) != -1 &&
|
||||
mt_state.val[slot] != -1) {
|
||||
set_bit(tracking_id_changes, slot);
|
||||
need_tracking_id_changes = 1;
|
||||
}
|
||||
|
||||
*slot_value(dev, slot, axis) = mt_state.val[slot];
|
||||
|
||||
set_bit(slot_update, AXISBIT(slot, axis));
|
||||
|
|
@ -607,6 +616,23 @@ sync_mt_state(struct libevdev *dev, int create_events)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (need_tracking_id_changes) {
|
||||
for (slot = 0; slot < min(dev->num_slots, MAX_SLOTS); slot++) {
|
||||
if (!bit_is_set(tracking_id_changes, slot))
|
||||
continue;
|
||||
|
||||
ev = queue_push(dev);
|
||||
init_event(dev, ev, EV_ABS, ABS_MT_SLOT, slot);
|
||||
ev = queue_push(dev);
|
||||
init_event(dev, ev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
|
||||
last_reported_slot = slot;
|
||||
}
|
||||
|
||||
ev = queue_push(dev);
|
||||
init_event(dev, ev, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
|
||||
for (slot = 0; slot < min(dev->num_slots, MAX_SLOTS); slot++) {
|
||||
if (!bit_is_set(slot_update, AXISBIT(slot, ABS_MT_SLOT)))
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -884,6 +884,168 @@ START_TEST(test_syn_delta_sw)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_syn_delta_tracking_ids)
|
||||
{
|
||||
struct uinput_device* uidev;
|
||||
struct libevdev *dev;
|
||||
int rc;
|
||||
struct input_event ev;
|
||||
struct input_absinfo abs[6];
|
||||
int i;
|
||||
const int num_slots = 15;
|
||||
int slot = -1;
|
||||
unsigned long terminated[NLONGS(num_slots)];
|
||||
unsigned long restarted[NLONGS(num_slots)];
|
||||
|
||||
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 = num_slots - 1;
|
||||
|
||||
abs[5].minimum = -1;
|
||||
abs[5].maximum = 255;
|
||||
abs[5].value = ABS_MT_TRACKING_ID;
|
||||
|
||||
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));
|
||||
|
||||
/* Test the sync process to make sure we get touches terminated when
|
||||
* the tracking id changes:
|
||||
* 1) start a bunch of touch points
|
||||
* 2) read data into libevdev, make sure state is up-to-date
|
||||
* 3) change touchpoints
|
||||
* 3.1) change the tracking ID on some (indicating terminated and
|
||||
* re-started touchpoint)
|
||||
* 3.2) change the tracking ID to -1 on some (indicating termianted
|
||||
* touchpoint)
|
||||
* 3.3) just update the data on others
|
||||
* 4) force a sync on the device
|
||||
* 5) make sure we get the right tracking ID changes in the caller
|
||||
*/
|
||||
|
||||
/* Start a bunch of touch points */
|
||||
for (i = num_slots; i >= 0; i--) {
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_SLOT, i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_X, 100 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_Y, 500 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_X, 100 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_Y, 500 + i);
|
||||
uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
|
||||
do {
|
||||
rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
||||
ck_assert_int_ne(rc, LIBEVDEV_READ_STATUS_SYNC);
|
||||
} while (rc >= 0);
|
||||
}
|
||||
|
||||
/* we have a bunch of touches now, and libevdev knows it. Change all
|
||||
* touches */
|
||||
for (i = num_slots; i >= 0; i--) {
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_SLOT, i);
|
||||
if (i % 3 == 0) {
|
||||
/* change some slots with a new tracking id */
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, num_slots + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_X, 200 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_Y, 700 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_X, 200 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_Y, 700 + i);
|
||||
} else if (i % 3 == 1) {
|
||||
/* stop others */
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
||||
} else {
|
||||
/* just update */
|
||||
uinput_device_event(uidev, EV_ABS, ABS_X, 200 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_Y, 700 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_X, 200 + i);
|
||||
uinput_device_event(uidev, EV_ABS, ABS_MT_POSITION_Y, 700 + i);
|
||||
}
|
||||
uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
|
||||
/* Force sync */
|
||||
rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev);
|
||||
ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SYNC);
|
||||
|
||||
/* now check for the right tracking IDs */
|
||||
memset(terminated, 0, sizeof(terminated));
|
||||
memset(restarted, 0, sizeof(restarted));
|
||||
slot = -1;
|
||||
while ((rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev)) != -EAGAIN) {
|
||||
if (libevdev_event_is_code(&ev, EV_SYN, SYN_REPORT))
|
||||
continue;
|
||||
|
||||
if (libevdev_event_is_code(&ev, EV_ABS, ABS_MT_SLOT)) {
|
||||
slot = ev.value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (libevdev_event_is_code(&ev, EV_ABS, ABS_X) ||
|
||||
libevdev_event_is_code(&ev, EV_ABS, ABS_Y))
|
||||
continue;
|
||||
|
||||
ck_assert_int_ne(slot, -1);
|
||||
|
||||
if (libevdev_event_is_code(&ev, EV_ABS, ABS_MT_TRACKING_ID)) {
|
||||
if (slot % 3 == 0) {
|
||||
if (!bit_is_set(terminated, slot)) {
|
||||
ck_assert_int_eq(ev.value, -1);
|
||||
set_bit(terminated, slot);
|
||||
} else {
|
||||
ck_assert_int_eq(ev.value, num_slots + slot);
|
||||
set_bit(restarted, slot);
|
||||
}
|
||||
} else if (slot % 3 == 1) {
|
||||
ck_assert(!bit_is_set(terminated, slot));
|
||||
ck_assert_int_eq(ev.value, -1);
|
||||
set_bit(terminated, slot);
|
||||
} else
|
||||
ck_abort();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(ev.code) {
|
||||
case ABS_MT_POSITION_X:
|
||||
ck_assert_int_eq(ev.value, 200 + slot);
|
||||
break;
|
||||
case ABS_MT_POSITION_Y:
|
||||
ck_assert_int_eq(ev.value, 700 + slot);
|
||||
break;
|
||||
default:
|
||||
ck_abort();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_slots; i++) {
|
||||
if (i % 3 == 0) {
|
||||
ck_assert(bit_is_set(terminated, i));
|
||||
ck_assert(bit_is_set(restarted, i));
|
||||
} else if (i % 3 == 1) {
|
||||
ck_assert(bit_is_set(terminated, i));
|
||||
ck_assert(!bit_is_set(restarted, i));
|
||||
} else {
|
||||
ck_assert(!bit_is_set(terminated, i));
|
||||
ck_assert(!bit_is_set(restarted, i));
|
||||
}
|
||||
}
|
||||
|
||||
uinput_device_free(uidev);
|
||||
libevdev_free(dev);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_syn_delta_fake_mt)
|
||||
{
|
||||
struct uinput_device* uidev;
|
||||
|
|
@ -1686,6 +1848,7 @@ libevdev_events(void)
|
|||
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);
|
||||
tcase_add_test(tc, test_syn_delta_tracking_ids);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("skipped syncs");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue