touchpad: don't process state for a touch in TOUCH_NONE
authorPeter Hutterer <peter.hutterer@who-t.net>
Thu, 5 Apr 2018 01:18:40 +0000 (11:18 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Mon, 9 Apr 2018 03:57:14 +0000 (13:57 +1000)
If a touch is in TOUCH_NONE, there is nothing to see here, please move along.

In the case of bug 105696, we were accessing the speed.exceeded_count of a
touch that was released previously, erroneously detecting a speed-based thumb.
The sequence was:
- touch down in slot 0, speed.exceeded_count is reset to 0
- move touch until exceeded_count is greater than our threshold
- touch up in slot 0
- touch down in slot 1 [1]
- touch down in slot 2 (more than 25mm away)
- we counted the slot 0 speed.exceeded_count, labeling the slot 2 touch as
  speed-based thumb

[1] peculiar behavior only observed on this device, usually slots get re-used
at the first opportunity so having an inactive slot followed by higher slots
being used is unusual.

https://bugs.freedesktop.org/show_bug.cgi?id=105696

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 928bad9104f6270dc638022ba8cc20f42a0e1b41)

src/evdev-mt-touchpad.c
test/test-touchpad.c

index 8a3923c73cd9d4e16d56a8e4a3fb99024c3c7ede..cc01976a5831c9ca4005fe56c0c5a7ad5ca20a25 100644 (file)
@@ -1489,6 +1489,9 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
        want_motion_reset = tp_need_motion_history_reset(tp);
 
        tp_for_each_touch(tp, t) {
+               if (t->state == TOUCH_NONE)
+                       continue;
+
                if (want_motion_reset) {
                        tp_motion_history_reset(t);
                        t->quirks.reset_motion_history = true;
index 4759bfb68c67e308bbd7700c54862c5b81950b3c..028af4c418872296d9f7a91eec97d9610e301a02 100644 (file)
@@ -4487,6 +4487,43 @@ START_TEST(touchpad_thumb_moving)
 }
 END_TEST
 
+START_TEST(touchpad_thumb_moving_empty_slots)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+
+       litest_disable_tap(dev->libinput_device);
+       litest_enable_2fg_scroll(dev);
+
+       if (libevdev_get_num_slots(dev->evdev) < 3)
+               return;
+
+       litest_drain_events(li);
+
+       /* exceed the speed movement threshold in slot 0 */
+       litest_touch_down(dev, 0, 50, 20);
+       litest_touch_move_to(dev, 0, 50, 20, 70, 99, 15, 0);
+       litest_touch_up(dev, 0);
+
+       litest_drain_events(li);
+
+       /* scroll in slots 1 and 2 */
+       litest_touch_down(dev, 1, 50, 50);
+       litest_touch_down(dev, 2, 90, 50);
+       libinput_dispatch(li);
+       for (int i = 0, y = 50; i < 10; i++, y++) {
+               litest_touch_move_to(dev, 1, 50, y, 50, y + 1, 1, 0);
+               litest_touch_move_to(dev, 2, 50, y, 50, y + 1, 1, 0);
+       }
+       libinput_dispatch(li);
+       litest_touch_up(dev, 1);
+       litest_touch_up(dev, 2);
+       libinput_dispatch(li);
+       litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 2);
+
+}
+END_TEST
+
 START_TEST(touchpad_thumb_clickfinger)
 {
        struct litest_device *dev = litest_current_device();
@@ -5898,6 +5935,7 @@ litest_setup_tests_touchpad(void)
        litest_add("touchpad:thumb", touchpad_thumb_begin_no_motion, LITEST_CLICKPAD, LITEST_ANY);
        litest_add("touchpad:thumb", touchpad_thumb_update_no_motion, LITEST_CLICKPAD, LITEST_ANY);
        litest_add("touchpad:thumb", touchpad_thumb_moving, LITEST_CLICKPAD, LITEST_ANY);
+       litest_add("touchpad:thumb", touchpad_thumb_moving_empty_slots, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
        litest_add("touchpad:thumb", touchpad_thumb_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
        litest_add("touchpad:thumb", touchpad_thumb_btnarea, LITEST_CLICKPAD, LITEST_ANY);
        litest_add("touchpad:thumb", touchpad_thumb_tap_begin, LITEST_CLICKPAD, LITEST_ANY);