touchpad: a touchpad with only one button is a clickpad
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 14 Apr 2021 05:18:13 +0000 (15:18 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 21 Apr 2021 00:15:42 +0000 (00:15 +0000)
There is only one touchpad with a physical left button but no right button and
that is the old Apple touchpad, discontinued in 2008. Not a huge number of
those left, I assume.

So let's change our assumptions because these days the vast majority of
touchpads are clickpads - any touchpad that only has a left button is treated
as clickpad, even where the kernel doesn't set the INPUT_PROP_BUTTONPAD.

We do need to check for BTN_LEFT as well though, because Wacom touchpads (i.e.
the touch part of non-integrated Wacom tablets) don't have a left button
either.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
src/evdev-mt-touchpad-buttons.c
test/test-touchpad-buttons.c

index d7f075c..be399bc 100644 (file)
@@ -943,9 +943,22 @@ tp_guess_clickpad(const struct tp_dispatch *tp, struct evdev_device *device)
             has_middle = libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE),
             has_right = libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT);
 
-
        is_clickpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD);
 
+       /* A non-clickpad without a right button is a clickpad, assume the
+        * kernel is wrong.
+        * Exceptions here:
+        * - The one-button Apple touchpad (discontinued in 2008) has a
+        *   single physical button
+        * - Wacom touch devices have neither left nor right buttons
+        */
+       if (!is_clickpad && has_left && !has_right &&
+           (tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON) == 0) {
+               evdev_log_bug_kernel(device,
+                                    "missing right button, assuming it is a clickpad.\n");
+               is_clickpad = true;
+       }
+
        if (has_middle || has_right) {
                if (is_clickpad)
                        evdev_log_bug_kernel(device,
index e0a8ddf..6af571d 100644 (file)
@@ -2053,6 +2053,51 @@ START_TEST(clickpad_middleemulation_click_disable_while_down)
 }
 END_TEST
 
+START_TEST(touchpad_non_clickpad_detection)
+{
+       struct libinput *li;
+       struct libinput_device *device;
+       struct libevdev_uinput *uinput;
+       static struct input_absinfo absinfo[] = {
+               { ABS_X, 1472, 5472, 0, 0, 75 },
+               { ABS_Y, 1408, 4448, 0, 0, 129 },
+               { ABS_PRESSURE, 0, 255, 0, 0, 0 },
+               { ABS_TOOL_WIDTH, 0, 15, 0, 0, 0 },
+               { ABS_MT_SLOT, 0, 1, 0, 0, 0 },
+               { ABS_MT_POSITION_X, 1472, 5472, 0, 0, 75 },
+               { ABS_MT_POSITION_Y, 1408, 4448, 0, 0, 129 },
+               { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
+               { ABS_MT_PRESSURE, 0, 255, 0, 0, 0 },
+               { .value = -1 }
+       };
+       uint32_t methods;
+
+       /* Create a touchpad with only a left button but missing
+        * INPUT_PROP_BUTTONPAD. We should treat this as clickpad.
+        */
+       uinput = litest_create_uinput_abs_device("litest NonClickpad",
+                                                NULL,
+                                                absinfo,
+                                                EV_KEY, BTN_LEFT,
+                                                EV_KEY, BTN_TOOL_FINGER,
+                                                EV_KEY, BTN_TOUCH,
+                                                -1);
+
+       li = litest_create_context();
+       device = libinput_path_add_device(li,
+                                         libevdev_uinput_get_devnode(uinput));
+
+       methods = libinput_device_config_click_get_methods(device);
+       ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
+       ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
+
+
+       libinput_path_remove_device(device);
+       libevdev_uinput_destroy(uinput);
+       litest_destroy_context(li);
+}
+END_TEST
+
 TEST_COLLECTION(touchpad_buttons)
 {
        struct range finger_count = {1, 4};
@@ -2122,4 +2167,6 @@ TEST_COLLECTION(touchpad_buttons)
        litest_add(clickpad_middleemulation_click_middle_right, LITEST_CLICKPAD, LITEST_ANY);
        litest_add(clickpad_middleemulation_click_enable_while_down, LITEST_CLICKPAD, LITEST_ANY);
        litest_add(clickpad_middleemulation_click_disable_while_down, LITEST_CLICKPAD, LITEST_ANY);
+
+       litest_add_no_device(touchpad_non_clickpad_detection);
 }