From 6a77cae8509bd45bff7ae220101295bbc57b9803 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 6 Jul 2017 11:46:12 +1000 Subject: [PATCH] touchpad: sync the slot state after tp_resume() If the touchpad is suspended and resumed (e.g. lid switch), the initial slot state may be out of sync. If a touch happened while the touchpad was suspended and the next touch down is on exactly the same x and/or y coordinate, our touch point would still have the coordinates of the most recently seen touch (i.e. before touchpad suspend). This could cause a pointer jump or test case failures. The real-world impact of this is minimal, putting the finger down in exactly the same spot is virtually impossible. It could cause a test case failure in the lid_disable_touchpad() test though, the second touch sequence was on the same y coordinate and the touch location for that whole sequence was x/0. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 75 +++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 4d0cff97..2b9bc28b 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -1446,6 +1446,45 @@ tp_interface_suspend(struct evdev_dispatch *dispatch, tp_clear_state(tp); } +static inline void +tp_sync_touch(struct tp_dispatch *tp, + struct evdev_device *device, + struct tp_touch *t, + int slot) +{ + struct libevdev *evdev = device->evdev; + + if (!libevdev_fetch_slot_value(evdev, + slot, + ABS_MT_POSITION_X, + &t->point.x)) + t->point.x = libevdev_get_event_value(evdev, EV_ABS, ABS_X); + if (!libevdev_fetch_slot_value(evdev, + slot, + ABS_MT_POSITION_Y, + &t->point.y)) + t->point.y = libevdev_get_event_value(evdev, EV_ABS, ABS_Y); + + if (!libevdev_fetch_slot_value(evdev, + slot, + ABS_MT_PRESSURE, + &t->pressure)) + t->pressure = libevdev_get_event_value(evdev, + EV_ABS, + ABS_PRESSURE); +} + +static void +tp_sync_slots(struct tp_dispatch *tp, + struct evdev_device *device) +{ + /* Always sync the first touch so we get ABS_X/Y synced on + * single-touch touchpads */ + tp_sync_touch(tp, device, &tp->touches[0], 0); + for (unsigned int i = 1; i < tp->num_slots; i++) + tp_sync_touch(tp, device, &tp->touches[i], i); +} + static void tp_resume(struct tp_dispatch *tp, struct evdev_device *device) { @@ -1458,6 +1497,8 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device *device) } else { evdev_device_resume(device); } + + tp_sync_slots(tp, device); } static void @@ -1912,34 +1953,6 @@ tp_init_touch(struct tp_dispatch *tp, t->has_ended = true; } -static void -tp_sync_touch(struct tp_dispatch *tp, - struct evdev_device *device, - struct tp_touch *t, - int slot) -{ - struct libevdev *evdev = device->evdev; - - if (!libevdev_fetch_slot_value(evdev, - slot, - ABS_MT_POSITION_X, - &t->point.x)) - t->point.x = libevdev_get_event_value(evdev, EV_ABS, ABS_X); - if (!libevdev_fetch_slot_value(evdev, - slot, - ABS_MT_POSITION_Y, - &t->point.y)) - t->point.y = libevdev_get_event_value(evdev, EV_ABS, ABS_Y); - - if (!libevdev_fetch_slot_value(evdev, - slot, - ABS_MT_PRESSURE, - &t->pressure)) - t->pressure = libevdev_get_event_value(evdev, - EV_ABS, - ABS_PRESSURE); -} - static inline void tp_disable_abs_mt(struct evdev_device *device) { @@ -2025,11 +2038,7 @@ tp_init_slots(struct tp_dispatch *tp, for (i = 0; i < tp->ntouches; i++) tp_init_touch(tp, &tp->touches[i]); - /* Always sync the first touch so we get ABS_X/Y synced on - * single-touch touchpads */ - tp_sync_touch(tp, device, &tp->touches[0], 0); - for (i = 1; i < tp->num_slots; i++) - tp_sync_touch(tp, device, &tp->touches[i], i); + tp_sync_slots(tp, device); /* Some touchpads don't reset BTN_TOOL_FINGER on touch up and only * change to/from it when BTN_TOOL_DOUBLETAP is set. This causes us