Disregard touchless clicks on flaky devices

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>
This commit is contained in:
Robert Glossop 2023-04-11 02:00:52 +00:00 committed by Peter Hutterer
parent 7c84fb87e9
commit 57f0354ee5
10 changed files with 162 additions and 17 deletions

View 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',

View file

@ -45,6 +45,7 @@ AttrPalmPressureThreshold=150
MatchName=* Touchpad
MatchDMIModalias=dmi:*svnDellInc.:pnXPS159500:*
ModelTouchpadVisibleMarker=0
ModelTouchpadPhantomClicks=1
[Dell Latitude D620 Trackpoint]
MatchName=*DualPoint Stick

View 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:

View 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";

View 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 */

View file

@ -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,
)

View 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

View 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

View 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);

View 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);