Disregard touchless clicks on flaky devices
authorRobert Glossop <robgssp@gmail.com>
Tue, 11 Apr 2023 02:00:52 +0000 (02:00 +0000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Tue, 11 Apr 2023 02:00:52 +0000 (02:00 +0000)
Some touchpads, notably those on the Dell XPS 15 9500, are prone to registering
touchpad clicks when the case is sufficiently flexed. Ignore these by
disregarding any clicks that are registered without touchpad touch.

Signed-off-by: Rob Glossop <robgssp@gmail.com>
meson.build
quirks/50-system-dell.quirks
src/evdev-mt-touchpad-buttons.c
src/quirks.c
src/quirks.h
test/litest-device-synaptics-phantomclicks.c [new file with mode: 0644]
test/litest.h
test/test-device.c
test/test-touchpad-buttons.c
test/test-touchpad.c

index 211aae2c0ca5852138a1cc805b0bebe57b59d940..e6488eb41f3650fae69920c8d95bec7d366add58 100644 (file)
@@ -791,6 +791,7 @@ if get_option('tests')
                'test/litest-device-synaptics-st.c',
                'test/litest-device-synaptics-t440.c',
                'test/litest-device-synaptics-x1-carbon-3rd.c',
+               'test/litest-device-synaptics-phantomclicks.c',
                'test/litest-device-tablet-mode-switch.c',
                'test/litest-device-thinkpad-extrabuttons.c',
                'test/litest-device-trackpoint.c',
index 45ef58b2021388f91a47cde19e328236af478ddd..4a65020e9a3de311b609ecbc72e9e5be7780c080 100644 (file)
@@ -45,6 +45,7 @@ AttrPalmPressureThreshold=150
 MatchName=* Touchpad
 MatchDMIModalias=dmi:*svnDellInc.:pnXPS159500:*
 ModelTouchpadVisibleMarker=0
+ModelTouchpadPhantomClicks=1
 
 [Dell Latitude D620 Trackpoint]
 MatchName=*DualPoint Stick
index 75ddebb2147582cccd51e0a3900130fa3a080ffa..8b7813dc59813cc68f5c26d8b51efb3a118df8bd 100644 (file)
@@ -1233,6 +1233,18 @@ tp_post_clickpadbutton_buttons(struct tp_dispatch *tp, uint64_t time)
                struct tp_touch *t;
                uint32_t area = 0;
 
+               if (evdev_device_has_model_quirk(tp->device,
+                                                QUIRK_MODEL_TOUCHPAD_PHANTOM_CLICKS) &&
+                   tp->nactive_slots == 0) {
+                       /* Some touchpads, notably those on the Dell XPS 15 9500,
+                        * are prone to registering touchpad clicks when the
+                        * case is sufficiently flexed. Ignore these by
+                        * disregarding any clicks that are registered without
+                        * touchpad touch. */
+                       tp->buttons.click_pending = true;
+                       return 0;
+               }
+
                tp_for_each_touch(tp, t) {
                        switch (t->button.current) {
                        case BUTTON_EVENT_IN_AREA:
index 7e9160091fc526a1f8c76fdb061775d3796639b3..0fbd53f27caf266e95e1750062401e7960e84bcf 100644 (file)
@@ -267,6 +267,7 @@ quirk_get_name(enum quirk q)
        case QUIRK_MODEL_TABLET_MODE_NO_SUSPEND:        return "ModelTabletModeNoSuspend";
        case QUIRK_MODEL_TABLET_MODE_SWITCH_UNRELIABLE: return "ModelTabletModeSwitchUnreliable";
        case QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER:       return "ModelTouchpadVisibleMarker";
+       case QUIRK_MODEL_TOUCHPAD_PHANTOM_CLICKS:       return "ModelTouchpadPhantomClicks";
        case QUIRK_MODEL_TRACKBALL:                     return "ModelTrackball";
        case QUIRK_MODEL_WACOM_TOUCHPAD:                return "ModelWacomTouchpad";
        case QUIRK_MODEL_PRESSURE_PAD:                  return "ModelPressurePad";
index 30878546f6f3df0828bb5fba825dad70a8ab04cd..340d04635b9f3ce6db25c4560bba7893bcff2733 100644 (file)
@@ -87,6 +87,7 @@ enum quirk {
        QUIRK_MODEL_TRACKBALL,
        QUIRK_MODEL_WACOM_TOUCHPAD,
        QUIRK_MODEL_PRESSURE_PAD,
+       QUIRK_MODEL_TOUCHPAD_PHANTOM_CLICKS,
 
        _QUIRK_LAST_MODEL_QUIRK_, /* Guard: do not modify */
 
diff --git a/test/litest-device-synaptics-phantomclicks.c b/test/litest-device-synaptics-phantomclicks.c
new file mode 100644 (file)
index 0000000..2f65270
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2023 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "litest.h"
+#include "litest-int.h"
+
+static struct input_event down[] = {
+       { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN  },
+       { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+       { .type = -1, .code = -1 },
+};
+
+static struct input_event move[] = {
+       { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN  },
+       { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+       { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+       { .type = -1, .code = -1 },
+};
+
+static struct litest_device_interface interface = {
+       .touch_down_events = down,
+       .touch_move_events = move,
+};
+
+static struct input_id input_id = {
+       .bustype = 0x18,
+       .vendor = 0x4f3,
+       .product = 0x311c,
+};
+
+static int events[] = {
+       EV_KEY, BTN_LEFT,
+       EV_KEY, BTN_TOOL_FINGER,
+       EV_KEY, BTN_TOUCH,
+       EV_KEY, BTN_TOOL_DOUBLETAP,
+       EV_KEY, BTN_TOOL_TRIPLETAP,
+       EV_KEY, BTN_TOOL_QUADTAP,
+       EV_KEY, BTN_TOOL_QUINTTAP,
+       INPUT_PROP_MAX, INPUT_PROP_POINTER,
+       INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD,
+       -1, -1,
+};
+
+static struct input_absinfo absinfo[] = {
+       { ABS_X, 0, 4654, 0, 0, 31 },
+       { ABS_Y, 0, 2730, 0, 0, 31 },
+       { ABS_MT_SLOT, 0, 4, 0, 0, 0 },
+       { ABS_MT_POSITION_X, 0, 4654, 0, 0, 31 },
+       { ABS_MT_POSITION_Y, 0, 2730, 0, 0, 31 },
+       { ABS_MT_TOOL_TYPE, 0, 2, 0, 0, 0 },
+       { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
+       { .value = -1 }
+};
+
+static const char quirk_file[] =
+"[litest Dell XPS 15 9500 Touchpad]\n"
+"MatchName=litest DELL097D:00 04F3:311C Touchpad\n"
+"ModelTouchpadVisibleMarker=0\n"
+"ModelTouchpadPhantomClicks=1\n";
+
+TEST_DEVICE("synaptics-phantomclicks",
+       .type = LITEST_SYNAPTICS_PHANTOMCLICKS,
+       .features = LITEST_TOUCHPAD | LITEST_CLICKPAD | LITEST_BUTTON,
+       .interface = &interface,
+       .name = "DELL097D:00 04F3:311C Touchpad",
+       .id = &input_id,
+       .events = events,
+       .absinfo = absinfo,
+       .quirk_file = quirk_file,
+)
index 457790b336b87afbb2e7b5c2a638fe14f972b7b3..71344f905629e1af4a6f32f8fc3e3a81d7be84ba 100644 (file)
@@ -327,6 +327,7 @@ enum litest_device_type {
        LITEST_WACOM_ISDV4_524C_PEN,
        LITEST_MOUSE_FORMAT_STRING,
        LITEST_LENOVO_SCROLLPOINT,
+       LITEST_SYNAPTICS_PHANTOMCLICKS,
 };
 
 #define LITEST_DEVICELESS      -2
index f7895b28d788677fcb7aca24397df8d44ab7cf73..a117ac6533e3f997171ded22b6f18be9cdc73a3b 100644 (file)
@@ -1624,7 +1624,7 @@ START_TEST(device_has_size)
        ck_assert_int_eq(rc, 0);
        /* This matches the current set of test devices but may fail if
         * newer ones are added */
-       ck_assert_double_gt(w, 40);
+       ck_assert_double_gt(w, 30);
        ck_assert_double_gt(h, 20);
 }
 END_TEST
index eccc1eedec98101cc0c1e2f17d7f86a511c83f47..f3c7a3804a66081d6998662bd79d17be51cd4140 100644 (file)
@@ -169,6 +169,12 @@ START_TEST(touchpad_1fg_clickfinger_no_touch)
        struct litest_device *dev = litest_current_device();
        struct libinput *li = dev->libinput;
 
+       if (dev->which == LITEST_SYNAPTICS_PHANTOMCLICKS) {
+               /* The XPS 15 9500 touchpad has the ModelTouchpadPhantomClicks
+                * quirk enabled and doesn't generate events without touches. */
+               return;
+       }
+
        litest_enable_clickfinger(dev);
 
        litest_drain_events(li);
@@ -187,6 +193,26 @@ START_TEST(touchpad_1fg_clickfinger_no_touch)
 }
 END_TEST
 
+START_TEST(touchpad_1fg_clickfinger_no_touch_phantomclicks)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+
+       litest_enable_clickfinger(dev);
+
+       litest_drain_events(li);
+
+       litest_event(dev, EV_KEY, BTN_LEFT, 1);
+       litest_event(dev, EV_SYN, SYN_REPORT, 0);
+       litest_event(dev, EV_KEY, BTN_LEFT, 0);
+       litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+       libinput_dispatch(li);
+
+       litest_assert_empty_queue(li);
+}
+END_TEST
+
 START_TEST(touchpad_2fg_clickfinger)
 {
        struct litest_device *dev = litest_current_device();
@@ -1410,7 +1436,7 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move)
        litest_assert_empty_queue(li);
 
        litest_touch_down(dev, 1, 20, 20);
-       litest_touch_move_to(dev, 1, 20, 20, 80, 20, 10);
+       litest_touch_move_to(dev, 1, 20, 20, 80, 20, 15);
 
        libinput_dispatch(li);
        event = libinput_get_event(li);
@@ -1441,7 +1467,7 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move)
 
        /* second finger down */
        litest_touch_down(dev, 1, 20, 20);
-       litest_touch_move_to(dev, 1, 20, 20, 20, 80, 10);
+       litest_touch_move_to(dev, 1, 20, 20, 20, 80, 15);
 
        libinput_dispatch(li);
        event = libinput_get_event(li);
@@ -1492,7 +1518,7 @@ START_TEST(clickpad_softbutton_left_to_right)
        */
 
        litest_touch_down(dev, 0, 30, 90);
-       litest_touch_move_to(dev, 0, 30, 90, 90, 90, 10);
+       litest_touch_move_to(dev, 0, 30, 90, 90, 90, 15);
        litest_drain_events(li);
 
        litest_event(dev, EV_KEY, BTN_LEFT, 1);
@@ -1528,7 +1554,7 @@ START_TEST(clickpad_softbutton_right_to_left)
        */
 
        litest_touch_down(dev, 0, 80, 90);
-       litest_touch_move_to(dev, 0, 80, 90, 30, 90, 10);
+       litest_touch_move_to(dev, 0, 80, 90, 30, 90, 15);
        litest_drain_events(li);
 
        litest_event(dev, EV_KEY, BTN_LEFT, 1);
@@ -2130,6 +2156,8 @@ TEST_COLLECTION(touchpad_buttons)
        litest_add_for_device(touchpad_clickfinger_appletouch_2fg, LITEST_APPLETOUCH);
        litest_add_for_device(touchpad_clickfinger_appletouch_3fg, LITEST_APPLETOUCH);
 
+       litest_add_for_device(touchpad_1fg_clickfinger_no_touch_phantomclicks, LITEST_SYNAPTICS_PHANTOMCLICKS);
+
        litest_add_ranged(touchpad_clickfinger_click_drag, LITEST_CLICKPAD, LITEST_ANY, &finger_count);
 
        litest_add(touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY);
index d72ae0facafad25892e2a5eceb2f904f1cb1a399..2e057898cc4d827756feaea2c7db78536ee0c318 100644 (file)
@@ -801,7 +801,7 @@ START_TEST(touchpad_edge_scroll_horiz_clickpad)
        litest_enable_edge_scroll(dev);
 
        litest_touch_down(dev, 0, 20, 99);
-       litest_touch_move_to(dev, 0, 20, 99, 70, 99, 10);
+       litest_touch_move_to(dev, 0, 20, 99, 70, 99, 15);
        litest_touch_up(dev, 0);
 
        libinput_dispatch(li);
@@ -812,7 +812,7 @@ START_TEST(touchpad_edge_scroll_horiz_clickpad)
        litest_assert_empty_queue(li);
 
        litest_touch_down(dev, 0, 70, 99);
-       litest_touch_move_to(dev, 0, 70, 99, 20, 99, 10);
+       litest_touch_move_to(dev, 0, 70, 99, 20, 99, 15);
        litest_touch_up(dev, 0);
 
        libinput_dispatch(li);
@@ -1125,7 +1125,7 @@ START_TEST(touchpad_edge_scroll_buttonareas_click_stops_scroll)
        litest_drain_events(li);
 
        litest_touch_down(dev, 0, 20, 95);
-       litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10);
+       litest_touch_move_to(dev, 0, 20, 95, 70, 95, 15);
        litest_assert_only_axis_events(li, LIBINPUT_EVENT_POINTER_SCROLL_FINGER);
 
        litest_button_click(dev, BTN_LEFT, true);
@@ -1150,7 +1150,7 @@ START_TEST(touchpad_edge_scroll_buttonareas_click_stops_scroll)
         * edge scrolling, click, then scrolling without lifting the finger
         * is so small we'll let it pass.
         */
-       litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10);
+       litest_touch_move_to(dev, 0, 70, 95, 90, 95, 15);
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
 
        litest_button_click(dev, BTN_LEFT, false);
@@ -1175,7 +1175,7 @@ START_TEST(touchpad_edge_scroll_clickfinger_click_stops_scroll)
        litest_drain_events(li);
 
        litest_touch_down(dev, 0, 20, 95);
-       litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10);
+       litest_touch_move_to(dev, 0, 20, 95, 70, 95, 15);
        litest_assert_only_axis_events(li, LIBINPUT_EVENT_POINTER_SCROLL_FINGER);
 
        litest_button_click(dev, BTN_LEFT, true);
@@ -1194,7 +1194,7 @@ START_TEST(touchpad_edge_scroll_clickfinger_click_stops_scroll)
        libinput_event_destroy(event);
 
        /* clickfinger releases pointer -> expect movement */
-       litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10);
+       litest_touch_move_to(dev, 0, 70, 95, 90, 95, 15);
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
        litest_assert_empty_queue(li);
 
@@ -1286,7 +1286,7 @@ START_TEST(touchpad_palm_detect_at_top)
        litest_drain_events(li);
 
        litest_touch_down(dev, 0, 20, 1);
-       litest_touch_move_to(dev, 0, 20, 1, 70, 1, 10);
+       litest_touch_move_to(dev, 0, 20, 1, 70, 1, 15);
        litest_touch_up(dev, 0);
 
        litest_assert_empty_queue(li);
@@ -1433,7 +1433,7 @@ START_TEST(touchpad_palm_detect_palm_becomes_pointer)
        litest_drain_events(li);
 
        litest_touch_down(dev, 0, 99, 50);
-       litest_touch_move_to(dev, 0, 99, 50, 0, 70, 20);
+       litest_touch_move_to(dev, 0, 99, 50, 0, 70, 25);
        litest_touch_up(dev, 0);
 
        libinput_dispatch(li);
@@ -1483,11 +1483,11 @@ START_TEST(touchpad_palm_detect_no_palm_moving_into_edges)
        litest_drain_events(li);
 
        litest_touch_down(dev, 0, 50, 50);
-       litest_touch_move_to(dev, 0, 50, 50, 99, 50, 10);
+       litest_touch_move_to(dev, 0, 50, 50, 99, 50, 15);
 
        litest_drain_events(li);
 
-       litest_touch_move_to(dev, 0, 99, 50, 99, 90, 10);
+       litest_touch_move_to(dev, 0, 99, 50, 99, 90, 15);
        libinput_dispatch(li);
 
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
@@ -1513,11 +1513,11 @@ START_TEST(touchpad_palm_detect_no_palm_moving_into_top)
        litest_drain_events(li);
 
        litest_touch_down(dev, 0, 50, 50);
-       litest_touch_move_to(dev, 0, 50, 50, 0, 2, 10);
+       litest_touch_move_to(dev, 0, 50, 50, 0, 2, 15);
 
        litest_drain_events(li);
 
-       litest_touch_move_to(dev, 0, 0, 2, 50, 50, 10);
+       litest_touch_move_to(dev, 0, 0, 2, 50, 50, 15);
        libinput_dispatch(li);
 
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);