diff --git a/doc/touchpad-tap-state-machine.svg b/doc/touchpad-tap-state-machine.svg
index b1c5995b..9fee48ac 100644
--- a/doc/touchpad-tap-state-machine.svg
+++ b/doc/touchpad-tap-state-machine.svg
@@ -35,11 +35,11 @@
-
+
-
+
button 1
-
+
press
@@ -72,20 +72,20 @@
TOUCH_2
-
+
-
+
second
-
+
finger up
-
-
-
+
+
+
-
+
button 2
-
+
press
@@ -104,45 +104,45 @@
-
+
-
+
button 1
-
+
release
-
+
-
+
button 2
-
+
release
-
-
-
-
-
+
+
+
+
+
-
+
TAPPED
-
+
-
+
timeout
-
-
-
+
+
+
-
+
first
-
+
finger down
-
-
+
+
@@ -164,10 +164,10 @@
-
-
-
-
+
+
+
+
@@ -226,18 +226,18 @@
-
+
-
+
first
-
+
finger up
-
-
-
+
+
+
-
+
IDLE
@@ -249,8 +249,8 @@
-
-
+
+
@@ -344,8 +344,6 @@
-
-
@@ -371,7 +369,7 @@
-
+
@@ -558,8 +556,8 @@
press
-
-
+
+
@@ -607,15 +605,15 @@
TOUCH_TOUCH
-
+
-
+
TOUCH_IDLE
-
-
-
-
+
+
+
+
@@ -631,15 +629,8 @@
-
-
-
-
-
-
-
- yes
-
+
+
@@ -667,27 +658,20 @@
-
+
-
+
TOUCH_IDLE
-
-
-
+
+
+
-
+
TOUCH_IDLE
-
-
-
-
-
- TOUCH_IDLE
-
-
-
+
+
@@ -736,8 +720,8 @@
TOUCH_TOUCH
-
-
+
+
@@ -860,13 +844,6 @@
-
-
-
- state ==
-
- TOUCH_TOUCH
-
@@ -874,13 +851,6 @@
TOUCH_TOUCH
-
-
-
-
-
- no
-
@@ -1197,5 +1167,97 @@
+
+
+
+ TOUCH_2_RELEASE
+
+
+
+
+ second
+
+ finger up
+
+
+
+
+
+
+ timeout
+
+
+
+
+
+
+ move >
+
+ threshold
+
+
+
+
+
+
+
+
+
+
+
+
+ first
+
+ finger down
+
+
+
+
+
+
+
+
+ TOUCH_IDLE
+
+
+
+
+
+
+ first
+
+ finger up
+
+
+
+
+
+
+
+
+ second
+
+ finger down
+
+
+
+
+
+
+ TOUCH_DEAD
+
+
+
+
+ TOUCH_DEAD
+
+
+
+
+
+
+
+
+
diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c
index de4945e6..753fc6b5 100644
--- a/src/evdev-mt-touchpad-tap.c
+++ b/src/evdev-mt-touchpad-tap.c
@@ -69,6 +69,7 @@ tap_state_to_str(enum tp_tap_state state)
CASE_RETURN_STRING(TAP_STATE_TAPPED);
CASE_RETURN_STRING(TAP_STATE_TOUCH_2);
CASE_RETURN_STRING(TAP_STATE_TOUCH_2_HOLD);
+ CASE_RETURN_STRING(TAP_STATE_TOUCH_2_RELEASE);
CASE_RETURN_STRING(TAP_STATE_TOUCH_3);
CASE_RETURN_STRING(TAP_STATE_TOUCH_3_HOLD);
CASE_RETURN_STRING(TAP_STATE_DRAGGING);
@@ -275,12 +276,8 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp,
tp_tap_set_timer(tp, time);
break;
case TAP_EVENT_RELEASE:
- tp->tap.state = TAP_STATE_HOLD;
- if (t->tap.state == TAP_TOUCH_STATE_TOUCH) {
- tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_PRESSED);
- tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_RELEASED);
- }
- tp_tap_clear_timer(tp);
+ tp->tap.state = TAP_STATE_TOUCH_2_RELEASE;
+ tp_tap_set_timer(tp, time);
break;
case TAP_EVENT_MOTION:
tp_tap_clear_timer(tp);
@@ -322,6 +319,35 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp,
}
}
+static void
+tp_tap_touch2_release_handle_event(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ enum tap_event event, uint64_t time)
+{
+
+ switch (event) {
+ case TAP_EVENT_TOUCH:
+ tp->tap.state = TAP_STATE_TOUCH_2_HOLD;
+ t->tap.state = TAP_TOUCH_STATE_DEAD;
+ tp_tap_clear_timer(tp);
+ break;
+ case TAP_EVENT_RELEASE:
+ tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_PRESSED);
+ tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_RELEASED);
+ tp->tap.state = TAP_STATE_IDLE;
+ break;
+ case TAP_EVENT_MOTION:
+ case TAP_EVENT_TIMEOUT:
+ tp->tap.state = TAP_STATE_HOLD;
+ break;
+ case TAP_EVENT_BUTTON:
+ tp->tap.state = TAP_STATE_DEAD;
+ break;
+ case TAP_EVENT_THUMB:
+ break;
+ }
+}
+
static void
tp_tap_touch3_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
@@ -649,6 +675,9 @@ tp_tap_handle_event(struct tp_dispatch *tp,
case TAP_STATE_TOUCH_2_HOLD:
tp_tap_touch2_hold_handle_event(tp, t, event, time);
break;
+ case TAP_STATE_TOUCH_2_RELEASE:
+ tp_tap_touch2_release_handle_event(tp, t, event, time);
+ break;
case TAP_STATE_TOUCH_3:
tp_tap_touch3_handle_event(tp, t, event, time);
break;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 5f87c3f3..f42fb02d 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -97,6 +97,7 @@ enum tp_tap_state {
TAP_STATE_TAPPED,
TAP_STATE_TOUCH_2,
TAP_STATE_TOUCH_2_HOLD,
+ TAP_STATE_TOUCH_2_RELEASE,
TAP_STATE_TOUCH_3,
TAP_STATE_TOUCH_3_HOLD,
TAP_STATE_DRAGGING_OR_DOUBLETAP,
diff --git a/test/touchpad-tap.c b/test/touchpad-tap.c
index 62c7a5c3..334d7977 100644
--- a/test/touchpad-tap.c
+++ b/test/touchpad-tap.c
@@ -966,6 +966,50 @@ START_TEST(touchpad_2fg_tap_inverted)
}
END_TEST
+START_TEST(touchpad_2fg_tap_n_hold_first)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ litest_enable_tap(dev->libinput_device);
+
+ litest_drain_events(dev->libinput);
+
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_down(dev, 1, 70, 70);
+ litest_touch_up(dev, 1);
+
+ libinput_dispatch(li);
+
+ litest_assert_empty_queue(li);
+ litest_timeout_tap();
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_2fg_tap_n_hold_second)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ litest_enable_tap(dev->libinput_device);
+
+ litest_drain_events(dev->libinput);
+
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_down(dev, 1, 70, 70);
+ litest_touch_up(dev, 0);
+
+ libinput_dispatch(li);
+
+ litest_assert_empty_queue(li);
+ litest_timeout_tap();
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
START_TEST(touchpad_2fg_tap_quickrelease)
{
struct litest_device *dev = litest_current_device();
@@ -1755,6 +1799,8 @@ litest_setup_tests(void)
litest_add("touchpad:tap", touchpad_2fg_tap_n_drag_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
litest_add("touchpad:tap", touchpad_2fg_tap_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+ litest_add("touchpad:tap", touchpad_2fg_tap_n_hold_first, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+ litest_add("touchpad:tap", touchpad_2fg_tap_n_hold_second, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:tap", touchpad_2fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD);
litest_add("touchpad:tap", touchpad_2fg_tap_click, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_SINGLE_TOUCH|LITEST_CLICKPAD);