From 8fa5d0bf51083756e1a7ead11afae490a09542ab Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 20 Jun 2014 14:16:13 +1000 Subject: [PATCH] touchpad: disable tapping for fingers exceeding the timeout/motion threshold The current code triggers multi-finger tapping even if the finger released was previously held on the touchpad for a while. For an event sequence of: 1. first finger down 2. first finger move past threshold/wait past timeout 3. second finger down 4. first finger up The second finger initiates the two-finger tap state, but the button event is sent when the first finger releases - despite that finger not meeting the usual tap constraints. This sequence can happen whenever a user swaps fingers. Add the finger state to the actual touchpoints and update them whenever the constrains are broken. Then, discard button events if the respective touch did not meet the conditions. http://bugs.freedesktop.org/76760 Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- doc/touchpad-tap-state-machine.svg | 1527 ++++++++++++++-------------- src/evdev-mt-touchpad-tap.c | 162 ++- src/evdev-mt-touchpad.h | 10 + test/touchpad.c | 81 ++ 4 files changed, 957 insertions(+), 823 deletions(-) diff --git a/doc/touchpad-tap-state-machine.svg b/doc/touchpad-tap-state-machine.svg index 50ebc713..10739c68 100644 --- a/doc/touchpad-tap-state-machine.svg +++ b/doc/touchpad-tap-state-machine.svg @@ -1,771 +1,756 @@ -IDLETOUCHfirstfinger downfinger upbutton -1presstimeoutmove > thresholdsecondfinger downTOUCH_2secondfinger upbutton -2pressmove > -thresholdtimeoutbutton 1releasebutton -2releaseTAPPEDtimeoutfirstfinger downDRAGGINGfirstfinger upbtn1releaseIDLEthirdfinger downTOUCH_3secondfinger upbutton 3pressbutton 3releasemove > thresholdIDLEtimeoutthirdfinger upfirstfinger upIDLEfourthfinger downDRAGGING_OR_DOUBLETAPtimeoutfirstfinger upbutton -1releasebutton -1pressbtn1releasesecondfinger downmove > thresholdHOLDfirstfinger upsecondfinger downTOUCH_2_HOLDsecondfinger upfirstfinger upthirdfinger downTOUCH_3_HOLDsecondfinger upthirdfinger upfourthfinger downDEADsecondfinger upthirdfinger upfourthfinger downfirstfinger upfirstfinger upfirstfinger upIDLEif fingercount == 0secondfinger upDRAGGING_2firstfinger upsecondfinger downthirdfinger downbtn1releasephysbuttonpressfourthfinger downphysbuttonpressbutton 1releaseDRAGGING_WAITtimeoutfirstfinger down + + + + + + + + + + + + + IDLE + + + + TOUCH + + + + first + finger down + + + + + + finger up + + + + + + button 1 + press + + + + timeout + + + + + + move > + threshold + + + + + + second + finger down + + + + + + TOUCH_2 + + + + second + finger up + + + + + + button 2 + press + + + + move > + threshold + + + + timeout + + + + + + + + button 1 + release + + + + button 2 + release + + + + + + + + TAPPED + + + + timeout + + + + + + first + finger down + + + + + + DRAGGING + + + + first + finger up + + + + btn1 + release + + + + + + + + + + IDLE + + + + third + finger down + + + + + + TOUCH_3 + + + + + + button 3 + press + + + + button 3 + release + + + + + + move > + threshold + + + + + + IDLE + + + + timeout + + + + + + first + finger up + + + + + + IDLE + + + + fourth + finger down + + + + + + + + DRAGGING_OR_DOUBLETAP + + + + + + timeout + + + + + + first + finger up + + + + + + button 1 + release + + + + button 1 + press + + + + btn1 + release + + + + + + + + + + + + second + finger down + + + + + + move > + threshold + + + + + + + + HOLD + + + + first + finger up + + + + + + + + second + finger down + + + + + + + + + + TOUCH_2_HOLD + + + + second + finger up + + + + + + first + finger up + + + + + + + + + + third + finger down + + + + + + + + + + TOUCH_3_HOLD + + + + + + fourth + finger down + + + + DEAD + + + + + + + + + + any finger up + + + + fourth + finger up + + + + any finger up + + + + + + + + yes + + + + any finger up + + + + + + + + + + + + IDLE + + + + if finger + count == 0 + + + + + + + + + + second + finger up + + + + DRAGGING_2 + + + + + + + + first + finger up + + + + + + + + + + second + finger down + + + + + + + + + + third + finger down + + + + + + btn1 + release + + + + + + phys + button + press + + + + + + + + + + + + + + + + phys + button + press + + + + + + button 1 + release + + + + + + + + + + + + + + DRAGGING_WAIT + + + + timeout + + + + + + + + + + first + finger down + + + + + + TOUCH_TOUCH + + + + TOUCH_IDLE + + + + + + + + + + + + TOUCH_DEAD + + + + + + + + + + + + + + yes + + + + TOUCH_DEAD + + + + + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + + + TOUCH_IDLE + + + + + + TOUCH_IDLE + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + that finger + TOUCH_IDLE + + + + + + TOUCH_DEAD + + + + + + + + + + that finger + TOUCH_IDLE + + + + + + + + no + + + + TOUCH_TOUCH + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + TOUCH_DEAD + + + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + + + TOUCH_TOUCH + + + + + + TOUCH_IDLE + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + that finger + TOUCH_IDLE + + + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + TOUCH_DEAD + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + + + state == + TOUCH_TOUCH + + + + that finger state == + TOUCH_TOUCH + + + + + + no + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + TOUCH_DEAD + + + diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 25412184..8a129634 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -95,12 +95,16 @@ tap_event_to_str(enum tap_event event) { static void tp_tap_notify(struct tp_dispatch *tp, + struct tp_touch *t, uint64_t time, int nfingers, enum libinput_button_state state) { int32_t button; + if (t && t->tap.state == TAP_TOUCH_STATE_DEAD) + return; + switch (nfingers) { case 1: button = BTN_LEFT; break; case 2: button = BTN_RIGHT; break; @@ -128,7 +132,9 @@ tp_tap_clear_timer(struct tp_dispatch *tp) } static void -tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_idle_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { struct libinput *libinput = tp->device->base.seat->libinput; @@ -151,7 +157,9 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -161,7 +169,7 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_TAPPED; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); tp_tap_set_timer(tp, time); break; case TAP_EVENT_TIMEOUT: @@ -176,7 +184,9 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_hold_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -197,7 +207,9 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_tapped_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { struct libinput *libinput = tp->device->base.seat->libinput; @@ -213,17 +225,19 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch2_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -233,8 +247,8 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_HOLD; - tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_RELEASED); tp_tap_clear_timer(tp); break; case TAP_EVENT_MOTION: @@ -249,7 +263,9 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ } static void -tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -271,7 +287,9 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, ui } static void -tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch3_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -286,8 +304,8 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_TOUCH_2_HOLD; - tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; @@ -296,7 +314,9 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ } static void -tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -317,7 +337,9 @@ tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, ui } static void -tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { case TAP_EVENT_TOUCH: @@ -325,9 +347,9 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); tp_tap_clear_timer(tp); break; case TAP_EVENT_MOTION: @@ -336,13 +358,15 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dragging_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -359,13 +383,15 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint6 break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -378,17 +404,19 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dragging2_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -397,7 +425,7 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_MOTION: case TAP_EVENT_TIMEOUT: @@ -405,13 +433,16 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dead_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, + uint64_t time) { switch (event) { @@ -428,7 +459,10 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, + uint64_t time) { struct libinput *libinput = tp->device->base.seat->libinput; enum tp_tap_state current; @@ -440,43 +474,43 @@ tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) switch(tp->tap.state) { case TAP_STATE_IDLE: - tp_tap_idle_handle_event(tp, event, time); + tp_tap_idle_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH: - tp_tap_touch_handle_event(tp, event, time); + tp_tap_touch_handle_event(tp, t, event, time); break; case TAP_STATE_HOLD: - tp_tap_hold_handle_event(tp, event, time); + tp_tap_hold_handle_event(tp, t, event, time); break; case TAP_STATE_TAPPED: - tp_tap_tapped_handle_event(tp, event, time); + tp_tap_tapped_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_2: - tp_tap_touch2_handle_event(tp, event, time); + tp_tap_touch2_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_2_HOLD: - tp_tap_touch2_hold_handle_event(tp, event, time); + tp_tap_touch2_hold_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_3: - tp_tap_touch3_handle_event(tp, event, time); + tp_tap_touch3_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_3_HOLD: - tp_tap_touch3_hold_handle_event(tp, event, time); + tp_tap_touch3_hold_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_OR_DOUBLETAP: - tp_tap_dragging_or_doubletap_handle_event(tp, event, time); + tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING: - tp_tap_dragging_handle_event(tp, event, time); + tp_tap_dragging_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_WAIT: - tp_tap_dragging_wait_handle_event(tp, event, time); + tp_tap_dragging_wait_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_2: - tp_tap_dragging2_handle_event(tp, event, time); + tp_tap_dragging2_handle_event(tp, t, event, time); break; case TAP_STATE_DEAD: - tp_tap_dead_handle_event(tp, event, time); + tp_tap_dead_handle_event(tp, t, event, time); break; } @@ -508,19 +542,34 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) int filter_motion = 0; if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) - tp_tap_handle_event(tp, TAP_EVENT_BUTTON, time); + tp_tap_handle_event(tp, NULL, TAP_EVENT_BUTTON, time); tp_for_each_touch(tp, t) { if (!t->dirty || t->state == TOUCH_NONE) continue; - if (t->state == TOUCH_BEGIN) - tp_tap_handle_event(tp, TAP_EVENT_TOUCH, time); - else if (t->state == TOUCH_END) - tp_tap_handle_event(tp, TAP_EVENT_RELEASE, time); - else if (tp->tap.state != TAP_STATE_IDLE && - tp_tap_exceeds_motion_threshold(tp, t)) - tp_tap_handle_event(tp, TAP_EVENT_MOTION, time); + if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) + t->tap.state = TAP_TOUCH_STATE_DEAD; + + if (t->state == TOUCH_BEGIN) { + t->tap.state = TAP_TOUCH_STATE_TOUCH; + tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time); + } else if (t->state == TOUCH_END) { + tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time); + t->tap.state = TAP_TOUCH_STATE_DEAD; + } else if (tp->tap.state != TAP_STATE_IDLE && + tp_tap_exceeds_motion_threshold(tp, t)) { + struct tp_touch *tmp; + + /* Any touch exceeding the threshold turns all + * touches into DEAD */ + tp_for_each_touch(tp, tmp) { + if (tmp->tap.state == TAP_TOUCH_STATE_TOUCH) + tmp->tap.state = TAP_TOUCH_STATE_DEAD; + } + + tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time); + } } /** @@ -550,8 +599,17 @@ static void tp_tap_handle_timeout(uint64_t time, void *data) { struct tp_dispatch *tp = data; + struct tp_touch *t; + + tp_tap_handle_event(tp, NULL, TAP_EVENT_TIMEOUT, time); - tp_tap_handle_event(tp, TAP_EVENT_TIMEOUT, time); + tp_for_each_touch(tp, t) { + if (t->state == TOUCH_NONE || + t->tap.state == TAP_TOUCH_STATE_IDLE) + continue; + + t->tap.state = TAP_TOUCH_STATE_DEAD; + } } int diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 7afb3c46..494725a6 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -88,6 +88,12 @@ enum tp_tap_state { TAP_STATE_DEAD, /**< finger count exceeded */ }; +enum tp_tap_touch_state { + TAP_TOUCH_STATE_IDLE = 16, /**< not in touch */ + TAP_TOUCH_STATE_TOUCH, /**< touching, may tap */ + TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */ +}; + struct tp_motion { int32_t x; int32_t y; @@ -131,6 +137,10 @@ struct tp_touch { enum button_event curr; struct libinput_timer timer; } button; + + struct { + enum tp_tap_touch_state state; + } tap; }; struct tp_dispatch { diff --git a/test/touchpad.c b/test/touchpad.c index 288805ef..3e5ee202 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -320,6 +320,82 @@ START_TEST(touchpad_2fg_tap_click_apple) } END_TEST +START_TEST(touchpad_no_2fg_tap_after_move) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(dev->libinput); + + /* one finger down, move past threshold, + second finger down, first finger up + -> no event + */ + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10); + litest_drain_events(dev->libinput); + + litest_touch_down(dev, 1, 70, 50); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_no_2fg_tap_after_timeout) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(dev->libinput); + + /* one finger down, wait past tap timeout, + second finger down, first finger up + -> no event + */ + litest_touch_down(dev, 0, 50, 50); + libinput_dispatch(dev->libinput); + msleep(300); + libinput_dispatch(dev->libinput); + litest_drain_events(dev->libinput); + + litest_touch_down(dev, 1, 70, 50); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_no_first_fg_tap_after_move) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + + litest_drain_events(dev->libinput); + + /* one finger down, second finger down, + second finger moves beyond threshold, + first finger up + -> no event + */ + litest_touch_down(dev, 0, 50, 50); + litest_touch_down(dev, 1, 70, 50); + libinput_dispatch(dev->libinput); + litest_touch_move_to(dev, 1, 70, 50, 90, 90, 10); + libinput_dispatch(dev->libinput); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(dev->libinput); + + while ((event = libinput_get_event(li))) { + ck_assert_int_ne(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_BUTTON); + libinput_event_destroy(event); + } +} +END_TEST + START_TEST(touchpad_1fg_double_tap_click) { struct litest_device *dev = litest_current_device(); @@ -1127,6 +1203,11 @@ int main(int argc, char **argv) { litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_2fg_tap_click, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); litest_add("touchpad:tap", touchpad_2fg_tap_click_apple, LITEST_APPLE_CLICKPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_no_2fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_no_2fg_tap_after_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + /* Real buttons don't interfere with tapping, so don't run those for pads with buttons */ litest_add("touchpad:tap", touchpad_1fg_double_tap_click, LITEST_CLICKPAD, LITEST_ANY); -- 2.34.1