From: Peter Hutterer Date: Thu, 16 Apr 2015 00:19:11 +0000 (+1000) Subject: touchpad: introduce MULTITAP for multi-tap-and-drag X-Git-Tag: 0.14.0~12 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=abdca333877e9cbd7df0d9c295fa158bec96a407;p=platform%2Fupstream%2Flibinput.git touchpad: introduce MULTITAP for multi-tap-and-drag Once we have a doubletap, enter a loop in the state machine where we can tap multiple times and either get a multi-click or a multi-click drag-and-drop. The sequence down/up down/up down/up produces a triple-click. The sequence down/up down/up down/up down produces a triple-click with a button down for dragging. Yes, that glorious octuple-tap-and-drag, it is now possible. World domination has been achieved, thank you for playing. We don't know when we finish tapping now, so add a timeout to send the last click event once the finger has been released for the last time. This guarantees that the timestamp of the last button down is later than the last release. This avoids the bug fixed in synaptics commit xf86-input-synaptics-1.8.0-21-g37d34f0 (some application don't handle doubletap correctly without the timestamps). This works for double-tap immediately, for multi-tap we need to remember the timestamp of the first press event and use it for the release event so that there's a forced gap between the release and the second press. https://bugs.freedesktop.org/show_bug.cgi?id=89511 Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- diff --git a/doc/touchpad-tap-state-machine.svg b/doc/touchpad-tap-state-machine.svg index 7aecefc1..b168b4f6 100644 --- a/doc/touchpad-tap-state-machine.svg +++ b/doc/touchpad-tap-state-machine.svg @@ -1,756 +1,1094 @@ - - + + + + + - - - - - - - + + + + + + + - IDLE + + IDLE - + - TOUCH + + TOUCH - + - first - finger down + + first + + finger down - - - + + + - finger up + + finger up - - - + + + - button 1 - press + + button 1 + + press - + - timeout + + timeout - - - + + + - move > - threshold + + move > + + threshold - - - + + + - second - finger down + + second + + finger down - - - + + + - TOUCH_2 + + TOUCH_2 - + - second - finger up + + second + + finger up - - - + + + - button 2 - press + + button 2 + + press - + - move > - threshold + + move > + + threshold - + - timeout + + timeout - - - - - + + + + + - button 1 - release + + button 1 + + release - + - button 2 - release + + button 2 + + release - - - - - + + + + + - TAPPED + + TAPPED - + - timeout + + timeout - - - + + + - first - finger down + + first + + finger down - - - + + + - DRAGGING + + DRAGGING - + - first - finger up + + first + + finger up - + - btn1 - release + + btn1 + + release - - - - - - - + + + + + + + - IDLE + + IDLE - + - third - finger down + + third + + finger down - - - + + + - TOUCH_3 + + TOUCH_3 - - - + + + - button 3 - press + + button 3 + + press - + - button 3 - release + + button 3 + + release - - - + + + - move > - threshold + + move > + + threshold - - - + + + - IDLE + + IDLE - + - timeout + + timeout - - - + + + - first - finger up + + first + + finger up - - - + + + - IDLE + + IDLE - + - fourth - finger down - - - - - - - - DRAGGING_OR_DOUBLETAP - - - - - - timeout - - - - - - first - finger up - - - - - - button 1 - release - - - - button 1 - press - - - - btn1 - release - - - - - - - - - - - - second - finger down - - - - + + fourth + + finger down + + + + + + - move > - threshold - - - - - - + + DRAGGING_OR_DOUBLETAP + + + + + + + timeout + + + + - 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 - - - - - + + 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 - - - - + + + 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 + + + + - clickpad - button - press - - - - - - - - - - - - - - + + phys + + button + + press + + + + + + + + + + + + + + - clickpad - button - press - - - - - - button 1 - release - - - - - - - - - - - - - - DRAGGING_WAIT - - - - timeout - - - - - - - - - - first - finger down - - - - - - TOUCH_TOUCH - - - - TOUCH_IDLE - - - - - - - - - - - - TOUCH_DEAD - - - - - - - - - - - + + 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 + + + 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_IDLE + + TOUCH_TOUCH - - - + + + - TOUCH_TOUCH + + TOUCH_IDLE - - - + - that finger - TOUCH_IDLE + + TOUCH_TOUCH - - - + + + - TOUCH_DEAD + + TOUCH_DEAD - - - - - - - + + + + + - that finger - TOUCH_IDLE - - - - - - - - no + + TOUCH_IDLE - + + + - TOUCH_TOUCH + + TOUCH_TOUCH - - - + + + + + - TOUCH_IDLE + + TOUCH_TOUCH - - - + + + - TOUCH_TOUCH + + TOUCH_IDLE - - - + + + - TOUCH_DEAD + + TOUCH_IDLE - - - - - + + + - TOUCH_IDLE + + TOUCH_TOUCH - - - + + + - TOUCH_TOUCH + + TOUCH_IDLE - - - - - + + + - TOUCH_TOUCH + + TOUCH_TOUCH - - - + + + - TOUCH_IDLE + + that finger + + TOUCH_IDLE - - - + + + - TOUCH_IDLE + + TOUCH_DEAD - - - + + + - TOUCH_TOUCH + + TOUCH_DEAD - - - + - TOUCH_IDLE + + TOUCH_DEAD - - - + - TOUCH_TOUCH + + TOUCH_DEAD - - - + + + - that finger - TOUCH_IDLE + + TOUCH_DEAD - - - + + + - TOUCH_DEAD + + TOUCH_DEAD - - - + + + - TOUCH_DEAD + + state == + + TOUCH_TOUCH - + - TOUCH_DEAD + + that finger state == + + TOUCH_TOUCH - - - TOUCH_DEAD + + + + + + no - - - + - TOUCH_DEAD + + TOUCH_DEAD - - - + + + - TOUCH_DEAD + + TOUCH_DEAD - - - + - state == - TOUCH_TOUCH + + TOUCH_DEAD - + - that finger state == - TOUCH_TOUCH - - - - - - no + + first + + finger down - + - TOUCH_DEAD + + MULTITAP - - - + + + + + - TOUCH_DEAD - - - - TOUCH_DEAD + + timeout + + + + + + + + + IDLE + + + + + + + + + + MULTITAP_DOWN + + + + + button 1 + + press + + + + + + + + + first + + finger up + + + + + + + button 1 + + release + + + + + + + timeout + + + + + second + + finger down + + + + + move > + + threshold + + + + + + + + + + + button 1 + + release + + + + + button 1 + + press + + + + + + + + + + + button 1 + + release + + + + + button 1 + + press + + + + + + + + + + + button 1 + + release + + + + + button 1 + + press + + + + + + + + + + + + + TOUCH_TOUCH + + + + + + + TOUCH_IDLE + + + + + + + phys + + button + + press + + + + + + + diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 49fabb50..0f25e267 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -74,6 +74,8 @@ tap_state_to_str(enum tp_tap_state state) { CASE_RETURN_STRING(TAP_STATE_DRAGGING_WAIT); CASE_RETURN_STRING(TAP_STATE_DRAGGING_OR_DOUBLETAP); CASE_RETURN_STRING(TAP_STATE_DRAGGING_2); + CASE_RETURN_STRING(TAP_STATE_MULTITAP); + CASE_RETURN_STRING(TAP_STATE_MULTITAP_DOWN); CASE_RETURN_STRING(TAP_STATE_DEAD); } return NULL; @@ -351,11 +353,9 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, tp->tap.state = TAP_STATE_DRAGGING_2; 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.state = TAP_STATE_MULTITAP; tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); - tp_tap_clear_timer(tp); + tp_tap_set_timer(tp, time); break; case TAP_EVENT_MOTION: case TAP_EVENT_TIMEOUT: @@ -443,6 +443,79 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, } } +static void +tp_tap_multitap_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; + + switch (event) { + case TAP_EVENT_RELEASE: + log_bug_libinput(libinput, + "invalid tap event, no fingers are down\n"); + break; + case TAP_EVENT_TOUCH: + tp->tap.state = TAP_STATE_MULTITAP_DOWN; + tp->tap.multitap_last_time = time; + tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_set_timer(tp, time); + break; + case TAP_EVENT_MOTION: + log_bug_libinput(libinput, + "invalid tap event, no fingers are down\n"); + break; + case TAP_EVENT_TIMEOUT: + tp->tap.state = TAP_STATE_IDLE; + tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + break; + case TAP_EVENT_BUTTON: + tp->tap.state = TAP_STATE_IDLE; + tp_tap_clear_timer(tp); + break; + } +} + +static void +tp_tap_multitap_down_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, + uint64_t time) +{ + switch (event) { + case TAP_EVENT_RELEASE: + tp->tap.state = TAP_STATE_MULTITAP; + tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_set_timer(tp, time); + break; + case TAP_EVENT_TOUCH: + tp->tap.state = TAP_STATE_DRAGGING_2; + tp_tap_notify(tp, + tp->tap.multitap_last_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_clear_timer(tp); + break; + case TAP_EVENT_MOTION: + case TAP_EVENT_TIMEOUT: + tp->tap.state = TAP_STATE_DRAGGING; + tp_tap_notify(tp, + tp->tap.multitap_last_time, + 1, + LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_clear_timer(tp); + break; + case TAP_EVENT_BUTTON: + tp->tap.state = TAP_STATE_DEAD; + tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_clear_timer(tp); + break; + } +} + static void tp_tap_dead_handle_event(struct tp_dispatch *tp, struct tp_touch *t, @@ -511,6 +584,12 @@ tp_tap_handle_event(struct tp_dispatch *tp, case TAP_STATE_DRAGGING_2: tp_tap_dragging2_handle_event(tp, t, event, time); break; + case TAP_STATE_MULTITAP: + tp_tap_multitap_handle_event(tp, t, event, time); + break; + case TAP_STATE_MULTITAP_DOWN: + tp_tap_multitap_down_handle_event(tp, t, event, time); + break; case TAP_STATE_DEAD: tp_tap_dead_handle_event(tp, t, event, time); break; @@ -610,6 +689,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) case TAP_STATE_DRAGGING_OR_DOUBLETAP: case TAP_STATE_TOUCH_2: case TAP_STATE_TOUCH_3: + case TAP_STATE_MULTITAP_DOWN: filter_motion = 1; break; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 7b7600c3..97b17cde 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -97,6 +97,8 @@ enum tp_tap_state { TAP_STATE_DRAGGING, TAP_STATE_DRAGGING_WAIT, TAP_STATE_DRAGGING_2, + TAP_STATE_MULTITAP, + TAP_STATE_MULTITAP_DOWN, TAP_STATE_DEAD, /**< finger count exceeded */ }; @@ -256,6 +258,7 @@ struct tp_dispatch { enum tp_tap_state state; uint32_t buttons_pressed; unsigned int tap_finger_count; + uint64_t multitap_last_time; } tap; struct { diff --git a/test/touchpad.c b/test/touchpad.c index ac8ffb92..5ff4a366 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -123,6 +123,394 @@ START_TEST(touchpad_1fg_tap) } END_TEST +START_TEST(touchpad_1fg_doubletap) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + uint32_t oldtime, curtime; + + libinput_device_config_tap_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_TAP_ENABLED); + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_timeout_tap(); + + libinput_dispatch(li); + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + oldtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_le(oldtime, curtime); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_lt(oldtime, curtime); + oldtime = curtime; + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_le(oldtime, curtime); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_1fg_multitap) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + uint32_t oldtime = 0, + curtime; + int i, ntaps; + + libinput_device_config_tap_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_TAP_ENABLED); + + litest_drain_events(li); + + for (i = 3; i < 8; i++) { + + for (ntaps = 0; ntaps <= i; ntaps++) { + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + libinput_dispatch(li); + msleep(10); + } + + litest_timeout_tap(); + libinput_dispatch(li); + + for (ntaps = 0; ntaps <= i; ntaps++) { + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_ge(curtime, oldtime); + oldtime = curtime; + } + litest_timeout_tap(); + litest_assert_empty_queue(li); + } +} +END_TEST + +START_TEST(touchpad_1fg_multitap_n_drag_move) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + uint32_t oldtime = 0, + curtime; + int i, ntaps; + + libinput_device_config_tap_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_TAP_ENABLED); + + litest_drain_events(li); + + for (i = 3; i < 8; i++) { + + for (ntaps = 0; ntaps <= i; ntaps++) { + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + libinput_dispatch(li); + msleep(10); + } + + libinput_dispatch(li); + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 70, 50, 10, 4); + libinput_dispatch(li); + + for (ntaps = 0; ntaps <= i; ntaps++) { + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_ge(curtime, oldtime); + oldtime = curtime; + } + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + 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_2fg) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + uint32_t oldtime = 0, + curtime; + int i, ntaps; + + libinput_device_config_tap_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_TAP_ENABLED); + + litest_drain_events(li); + + for (i = 3; i < 8; i++) { + + for (ntaps = 0; ntaps <= i; ntaps++) { + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + libinput_dispatch(li); + msleep(10); + } + + libinput_dispatch(li); + litest_touch_down(dev, 0, 50, 50); + msleep(10); + litest_touch_down(dev, 1, 70, 50); + libinput_dispatch(li); + + for (ntaps = 0; ntaps <= i; ntaps++) { + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_ge(curtime, oldtime); + oldtime = curtime; + } + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + litest_touch_move_to(dev, 1, 70, 50, 90, 50, 10, 4); + + litest_assert_only_typed_events(li, + LIBINPUT_EVENT_POINTER_MOTION); + + litest_touch_up(dev, 1); + litest_touch_up(dev, 0); + litest_timeout_tap(); + 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_click) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + uint32_t oldtime = 0, + curtime; + int i, ntaps; + + libinput_device_config_tap_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_TAP_ENABLED); + + litest_drain_events(li); + + for (i = 3; i < 8; i++) { + + for (ntaps = 0; ntaps <= i; ntaps++) { + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + libinput_dispatch(li); + msleep(10); + } + + litest_touch_down(dev, 0, 50, 50); + libinput_dispatch(li); + litest_button_click(dev, BTN_LEFT, true); + litest_button_click(dev, BTN_LEFT, false); + libinput_dispatch(li); + + for (ntaps = 0; ntaps <= i; ntaps++) { + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_ge(curtime, oldtime); + oldtime = curtime; + } + + litest_assert_button_event(li, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + litest_touch_up(dev, 1); + litest_timeout_tap(); + + litest_assert_empty_queue(li); + } +} +END_TEST + +START_TEST(touchpad_1fg_multitap_n_drag_timeout) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + uint32_t oldtime = 0, + curtime; + int i, ntaps; + + libinput_device_config_tap_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_TAP_ENABLED); + + litest_drain_events(li); + + for (i = 3; i < 8; i++) { + + for (ntaps = 0; ntaps <= i; ntaps++) { + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + libinput_dispatch(li); + msleep(10); + } + + libinput_dispatch(li); + litest_touch_down(dev, 0, 50, 50); + libinput_dispatch(li); + + litest_timeout_tap(); + libinput_dispatch(li); + + for (ntaps = 0; ntaps <= i; ntaps++) { + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_ge(curtime, oldtime); + oldtime = curtime; + } + + event = libinput_get_event(li); + ptrev = litest_is_button_event(event, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + curtime = libinput_event_pointer_get_time(ptrev); + libinput_event_destroy(event); + ck_assert_int_gt(curtime, oldtime); + + litest_touch_move_to(dev, 0, 50, 50, 70, 50, 10, 4); + + 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_tap_n_drag) { struct litest_device *dev = litest_current_device(); @@ -3636,6 +4024,12 @@ int main(int argc, char **argv) { litest_add("touchpad:motion", touchpad_2fg_no_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:tap", touchpad_1fg_tap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_1fg_doubletap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_1fg_multitap, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_1fg_multitap_n_drag_timeout, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_1fg_multitap_n_drag_move, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_1fg_multitap_n_drag_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_1fg_multitap_n_drag_click, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_1fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_timeout, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_2fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);