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.
This commit is contained in:
Paolo Giangrandi 2019-03-13 21:53:54 -06:00
parent c741a42aec
commit a88d73cef4
2 changed files with 53 additions and 0 deletions

View file

@ -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;

View file

@ -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);