summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2018-08-02 16:58:58 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2018-08-03 15:01:55 +1000
commitba603ea1925cf68bafe24958d882dbe01d9111a5 (patch)
treeddfa95131cadb05da4464ad99be2ffa479a2185b
parentda0fbb580f26aec37ccac9eeb8856e1717d29802 (diff)
touchpad: improve finger counting for synaptics serial touchpads
A three-finger touch may cause slot N to end, in a frame after the BTN_TOOL_TRIPLETAP. This causes tp->nfinger_down to be decremented to 2 as the touch switches to MAYBE_END - which happens to be our num_slots. We exit early and never restore the touch correctly. Fix this by checking that the number of fake touches is equal to the slots, if it is higher then we need to check for recovery. Fixes https://gitlab.freedesktop.org/libinput/libinput/issues/99 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/evdev-mt-touchpad.c2
-rw-r--r--test/test-touchpad-tap.c92
-rw-r--r--test/test-touchpad.c109
3 files changed, 202 insertions, 1 deletions
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 25d0f23b..79f69b7d 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -554,7 +554,7 @@ tp_restore_synaptics_touches(struct tp_dispatch *tp,
return;
if (tp->nfingers_down >= nfake_touches ||
- tp->nfingers_down == tp->num_slots)
+ (tp->nfingers_down == tp->num_slots && nfake_touches == tp->num_slots))
return;
/* Synaptics devices may end touch 2 on BTN_TOOL_TRIPLETAP
diff --git a/test/test-touchpad-tap.c b/test/test-touchpad-tap.c
index 6471d9c0..7a6c2216 100644
--- a/test/test-touchpad-tap.c
+++ b/test/test-touchpad-tap.c
@@ -1886,6 +1886,96 @@ START_TEST(touchpad_3fg_tap_btntool_pointerjump)
}
END_TEST
+START_TEST(touchpad_3fg_tap_slot_release_btntool)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ /* Synaptics touchpads sometimes end one touch point after
+ * setting BTN_TOOL_TRIPLETAP.
+ * https://gitlab.freedesktop.org/libinput/libinput/issues/99
+ */
+ litest_drain_events(li);
+ litest_enable_tap(dev->libinput_device);
+
+ /* touch 1 down */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 2200);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3200);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
+ litest_event(dev, EV_ABS, ABS_X, 2200);
+ litest_event(dev, EV_ABS, ABS_Y, 3200);
+ litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
+ litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
+ litest_event(dev, EV_KEY, BTN_TOUCH, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ msleep(2);
+
+ /* touch 2 and TRIPLETAP down */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 2500);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3800);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
+ litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
+ litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ msleep(2);
+
+ /* touch 2 up, coordinate jump + ends slot 1, TRIPLETAP stays */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 2500);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3800);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ litest_event(dev, EV_ABS, ABS_X, 2500);
+ litest_event(dev, EV_ABS, ABS_Y, 3800);
+ litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ msleep(2);
+
+ /* slot 2 reactivated
+ */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 2500);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3800);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 3);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 3500);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3500);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
+ litest_event(dev, EV_ABS, ABS_X, 2200);
+ litest_event(dev, EV_ABS, ABS_Y, 3200);
+ litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+
+ /* now end all three */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ litest_event(dev, EV_KEY, BTN_TOUCH, 0);
+ litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_timeout_tap();
+ libinput_dispatch(li);
+
+ litest_assert_button_event(li, BTN_MIDDLE,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ litest_assert_button_event(li, BTN_MIDDLE,
+ LIBINPUT_BUTTON_STATE_RELEASED);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
START_TEST(touchpad_4fg_tap)
{
struct litest_device *dev = litest_current_device();
@@ -3454,6 +3544,8 @@ TEST_COLLECTION(touchpad_tap)
litest_add("tap-3fg:3fg", touchpad_3fg_tap_hover_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("tap-3fg:3fg", touchpad_3fg_tap_pressure_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add_for_device("tap-3fg:3fg", touchpad_3fg_tap_btntool_pointerjump, LITEST_SYNAPTICS_TOPBUTTONPAD);
+ litest_add_for_device("tap-3fg:3fg", touchpad_3fg_tap_slot_release_btntool, LITEST_SYNAPTICS_TOPBUTTONPAD);
+
litest_add("tap-4fg:4fg", touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
litest_add("tap-4fg:4fg", touchpad_4fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
litest_add("tap-5fg:5fg", touchpad_5fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
diff --git a/test/test-touchpad.c b/test/test-touchpad.c
index eb21b96b..f95d08e7 100644
--- a/test/test-touchpad.c
+++ b/test/test-touchpad.c
@@ -5165,6 +5165,114 @@ START_TEST(touchpad_tool_tripletap_touch_count)
}
END_TEST
+START_TEST(touchpad_tool_tripletap_touch_count_late)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+
+ /* Synaptics touchpads sometimes end one touch point after
+ * setting BTN_TOOL_TRIPLETAP.
+ * https://gitlab.freedesktop.org/libinput/libinput/issues/99
+ */
+ litest_drain_events(li);
+ litest_enable_clickfinger(dev);
+
+ /* touch 1 down */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 1200);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3200);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
+ litest_event(dev, EV_ABS, ABS_X, 1200);
+ litest_event(dev, EV_ABS, ABS_Y, 3200);
+ litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
+ litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
+ litest_event(dev, EV_KEY, BTN_TOUCH, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ msleep(2);
+
+ /* touch 2 and TRIPLETAP down */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 2200);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3200);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
+ litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
+ litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ msleep(2);
+
+ /* touch 2 up, coordinate jump + ends slot 1, TRIPLETAP stays */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 4000);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 4000);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ litest_event(dev, EV_ABS, ABS_X, 4000);
+ litest_event(dev, EV_ABS, ABS_Y, 4000);
+ litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ msleep(2);
+
+ /* slot 2 reactivated:
+ * Note, slot is activated close enough that we don't accidentally
+ * trigger the clickfinger distance check, remains to be seen if
+ * that is true for real-world interaction.
+ */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 4000);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 4000);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 3);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 3500);
+ litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3500);
+ litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
+ litest_event(dev, EV_ABS, ABS_X, 4000);
+ litest_event(dev, EV_ABS, ABS_Y, 4000);
+ litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ msleep(2);
+
+ /* now a click should trigger middle click */
+ litest_event(dev, EV_KEY, BTN_LEFT, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ litest_event(dev, EV_KEY, BTN_LEFT, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+
+ litest_wait_for_event(li);
+ event = libinput_get_event(li);
+ litest_is_button_event(event,
+ BTN_MIDDLE,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ libinput_event_destroy(event);
+ event = libinput_get_event(li);
+ litest_is_button_event(event,
+ BTN_MIDDLE,
+ LIBINPUT_BUTTON_STATE_RELEASED);
+ libinput_event_destroy(event);
+
+ /* release everything */
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
+ litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
+ litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
+ litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
+ litest_event(dev, EV_KEY, BTN_TOUCH, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+}
+END_TEST
+
START_TEST(touchpad_slot_swap)
{
struct litest_device *dev = litest_current_device();
@@ -6482,6 +6590,7 @@ TEST_COLLECTION(touchpad)
litest_add("touchpad:thumb", touchpad_thumb_move_and_tap, LITEST_CLICKPAD, LITEST_ANY);
litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD);
+ litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count_late, LITEST_SYNAPTICS_TOPBUTTONPAD);
litest_add_for_device("touchpad:bugs", touchpad_slot_swap, LITEST_SYNAPTICS_TOPBUTTONPAD);
litest_add_for_device("touchpad:bugs", touchpad_finger_always_down, LITEST_SYNAPTICS_TOPBUTTONPAD);