From a88d73cef4ebbfb781374e58beafb9a35b87d9b8 Mon Sep 17 00:00:00 2001 From: Paolo Giangrandi Date: Wed, 13 Mar 2019 21:53:54 -0600 Subject: [PATCH] touchpad: multitap state transitions use the same timing used for taps Multitap sequences (more than 2 taps) had a 180ms timer set only on press, not on release. New taps within those 180ms could either trigger multitap+drag or another multitap (for N+1 taps), resetting the timer on press once again. If no new tap appears within those 180ms, the sequence was considered complete. This behavior differed from regular taps: for the very first tap of a sequence the timer was set both on touch and on release. The multitap timing caused misdetection of triple-tap-and-drag sequences as the timer was hit frequently. Some of those were correctly detected, others as tripletap only. Changing the timer to be set on press **and** release gives us a more lenient timeout. 180ms for tap-and-drag and 180ms for the next tap down after release. This was also the behavior for the xorg synaptics driver. Note that quadruple-tap-and-drag didn't suffer from this because the timeout resulted in double-tap + double-tap-and-drag. Which has the same user-visible effect. --- src/evdev-mt-touchpad-tap.c | 2 ++ test/test-touchpad-tap.c | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 665567dc..5255469e 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -531,6 +531,7 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, 1, LIBINPUT_BUTTON_STATE_RELEASED); tp->tap.saved_release_time = time; + tp_tap_set_timer(tp, time); break; case TAP_EVENT_MOTION: case TAP_EVENT_TIMEOUT: @@ -754,6 +755,7 @@ tp_tap_multitap_down_handle_event(struct tp_dispatch *tp, 1, LIBINPUT_BUTTON_STATE_RELEASED); tp->tap.saved_release_time = time; + tp_tap_set_timer(tp, time); break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DRAGGING_2; diff --git a/test/test-touchpad-tap.c b/test/test-touchpad-tap.c index f68f5066..c1fc613e 100644 --- a/test/test-touchpad-tap.c +++ b/test/test-touchpad-tap.c @@ -488,6 +488,55 @@ START_TEST(touchpad_1fg_multitap_n_drag_timeout) } END_TEST +START_TEST(touchpad_1fg_tap_drag_high_delay) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int range = _i, /* looped test */ + ntaps; + + litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock(dev->libinput_device); + + litest_drain_events(li); + + for (ntaps = 0; ntaps <= range; ntaps++) { + /* Tap timeout is 180ms after a touch or release. Make sure we + * go over 180ms for touch+release, but stay under 180ms for + * each single event. */ + litest_touch_down(dev, 0, 50, 50); + libinput_dispatch(li); + msleep(100); + litest_touch_up(dev, 0); + libinput_dispatch(li); + msleep(100); + } + + libinput_dispatch(li); + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 50, 70, 10); + libinput_dispatch(li); + + for (ntaps = 0; ntaps < range; ntaps++) { + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + } + + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); + + litest_touch_up(dev, 0); + litest_assert_button_event(li, BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + + litest_assert_empty_queue(li); +} +END_TEST + START_TEST(touchpad_1fg_multitap_n_drag_tap) { struct litest_device *dev = litest_current_device(); @@ -3502,6 +3551,7 @@ END_TEST TEST_COLLECTION(touchpad_tap) { + struct range any_tap_range = {1, 4}; struct range multitap_range = {3, 5}; struct range tap_map_range = { LIBINPUT_CONFIG_TAP_MAP_LRM, LIBINPUT_CONFIG_TAP_MAP_LMR + 1 }; @@ -3511,6 +3561,7 @@ TEST_COLLECTION(touchpad_tap) litest_add("tap-1fg:1fg", touchpad_1fg_tap, LITEST_TOUCHPAD, LITEST_ANY); litest_add("tap-1fg:1fg", touchpad_1fg_doubletap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add_ranged("tap-1fg:1fg", touchpad_1fg_tap_drag_high_delay, LITEST_TOUCHPAD, LITEST_ANY, &any_tap_range); litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap_timeout, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range); litest_add_ranged("tap-multitap:1fg", touchpad_1fg_multitap_n_drag_timeout, LITEST_TOUCHPAD, LITEST_ANY, &multitap_range);