touchpad: disable the pressure axes wherever the resolution is nonzero
authorPeter Hutterer <peter.hutterer@who-t.net>
Thu, 4 Feb 2021 22:35:10 +0000 (08:35 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Mon, 8 Feb 2021 03:38:26 +0000 (03:38 +0000)
The kernel/udev set the pressure resolution to nonzero to indicate the value
is in a known scale (units/g). We use that information to disable the
pressure axis on such devices - real pressure cannot be translated to
contact size.

For the kernel patch see:
https://www.spinics.net/lists/linux-input/msg71237.html

Fixes #569

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
meson.build
src/evdev-mt-touchpad.c
test/litest-device-generic-pressurepad.c [new file with mode: 0644]
test/litest-device-synaptics-pressurepad.c
test/litest.h
test/test-touchpad-tap.c
test/test-touchpad.c

index 319e5747ea6a4748a29be6802d7b223b289abc84..f2a064a86cf0e74a139313f30ad627eab525f958 100644 (file)
@@ -777,6 +777,7 @@ if get_option('tests')
                'test/litest-device-dell-canvas-totem-touch.c',
                'test/litest-device-elantech-touchpad.c',
                'test/litest-device-elan-tablet.c',
+               'test/litest-device-generic-pressurepad.c',
                'test/litest-device-generic-singletouch.c',
                'test/litest-device-gpio-keys.c',
                'test/litest-device-huion-pentablet.c',
index 4d8c2a04a748abf3ee6b5b75f4f415ed6616b40f..2b0a1bc1ab5c81bb641d6108b6cc02fe7aa467fc 100644 (file)
@@ -3610,6 +3610,26 @@ out:
        return rc;
 }
 
+static void
+tp_init_pressurepad(struct tp_dispatch *tp,
+                   struct evdev_device *device)
+{
+       /* On traditional touchpads, the pressure value equals contact
+        * size. On PressurePads, pressure is a real physical axis for the
+        * force down. So we disable it here because we don't do anything
+        * with it anyway and using it for touch size messes things up.
+        *
+        * The kernel/udev set the resolution to non-zero on those devices
+        * to indicate that the value is in a known axis space.
+        *
+        * See also #562
+        */
+       if (libevdev_get_abs_resolution(device->evdev, ABS_MT_PRESSURE) != 0) {
+               libevdev_disable_event_code(device->evdev, EV_ABS, ABS_MT_PRESSURE);
+               libevdev_disable_event_code(device->evdev, EV_ABS, ABS_PRESSURE);
+       }
+}
+
 static int
 tp_init(struct tp_dispatch *tp,
        struct evdev_device *device)
@@ -3625,10 +3645,12 @@ tp_init(struct tp_dispatch *tp,
                return false;
 
        tp_init_default_resolution(tp, device);
+       tp_init_pressurepad(tp, device);
 
        if (!tp_init_slots(tp, device))
                return false;
 
+
        evdev_device_init_abs_range_warnings(device);
        use_touch_size = tp_init_touch_size(tp, device);
 
diff --git a/test/litest-device-generic-pressurepad.c b/test/litest-device-generic-pressurepad.c
new file mode 100644 (file)
index 0000000..298b328
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright © 2021 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"
+
+/* This is the same device as the one from
+   https://gitlab.freedesktop.org/libinput/libinput/-/issues/562
+
+   Except this one has a different input_id and sets the pressure
+   resolution to test the generic pressure handling.
+ */
+
+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_PRESSURE, .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_PRESSURE, .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 int
+get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
+{
+       switch (evcode) {
+       /* Always set pressure to zero. The real device sends pressure
+        * values > 30 when the device is clicked but until this is a)
+        * handled by libinput and b) integrated into this test suite
+        * a zero value does the job.
+        */
+       case ABS_PRESSURE:
+       case ABS_MT_PRESSURE:
+               *value = 0;
+               return 0;
+       }
+       return 1;
+}
+
+static struct litest_device_interface interface = {
+       .touch_down_events = down,
+       .touch_move_events = move,
+
+       .get_axis_default = get_axis_default,
+};
+
+static struct input_id input_id = {
+       .bustype = 0x18,
+       .vendor = 0x123,
+       .product = 0x4567,
+};
+
+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, 1224, 0, 0, 12 },
+       { ABS_Y, 0, 756, 0, 0, 12 },
+       { ABS_PRESSURE, 0, 255, 0, 0, 40 }, /* some random resolution */
+       { ABS_MT_SLOT, 0, 4, 0, 0, 0 },
+       { ABS_MT_POSITION_X, 0, 1224, 0, 0, 12 },
+       { ABS_MT_POSITION_Y, 0, 756, 0, 0, 12 },
+       { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
+       { ABS_MT_PRESSURE, 0, 255, 0, 0, 40 }, /* some random resolution */
+       { ABS_MT_TOOL_TYPE, 0, 2, 0, 0, 0 },
+       { .value = -1 }
+};
+
+TEST_DEVICE("generic-pressurepad",
+       .type = LITEST_GENERIC_PRESSUREPAD,
+       .features = LITEST_TOUCHPAD | LITEST_CLICKPAD | LITEST_BUTTON,
+       .interface = &interface,
+
+       .name = "Some Generic Pressurepad Touchpad",
+       .id = &input_id,
+       .events = events,
+       .absinfo = absinfo,
+)
index e0e5562daddd3b1863e3492d3f2cc2eaf931d312..bd214a271968a587803e26a77d653a72ad216776 100644 (file)
 #include "litest.h"
 #include "litest-int.h"
 
-/* Device from https://gitlab.freedesktop.org/libinput/libinput/-/issues/562 */
+/*
+ * Device from https://gitlab.freedesktop.org/libinput/libinput/-/issues/562
+ *
+ * This device relies on a quirk to disable the pressure axis, resolution is
+ * not set on ABS_PRESSURE.
+ */
 
 static struct input_event down[] = {
        { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN  },
@@ -98,12 +103,12 @@ static int events[] = {
 static struct input_absinfo absinfo[] = {
        { ABS_X, 0, 1224, 0, 0, 12 },
        { ABS_Y, 0, 756, 0, 0, 12 },
-       { ABS_PRESSURE, 0, 255, 0, 0, 0 },
+       { ABS_PRESSURE, 0, 255, 0, 0, 0 }, /* note: resolution zero */
        { ABS_MT_SLOT, 0, 4, 0, 0, 0 },
        { ABS_MT_POSITION_X, 0, 1224, 0, 0, 12 },
        { ABS_MT_POSITION_Y, 0, 756, 0, 0, 12 },
        { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
-       { ABS_MT_PRESSURE, 0, 255, 0, 0, 0 },
+       { ABS_MT_PRESSURE, 0, 255, 0, 0, 0 }, /* note: resolution zero */
        { ABS_MT_TOOL_TYPE, 0, 2, 0, 0, 0 },
        { .value = -1 }
 };
index 0790264e8f0d108eb7d7877f050692a4d9e53c8b..a8c4a575a8b700a59b8a32366944663bf2ac6e0e 100644 (file)
@@ -308,6 +308,7 @@ enum litest_device_type {
        LITEST_SONY_VAIO_KEYS,
        LITEST_KEYBOARD_QUIRKED,
        LITEST_SYNAPTICS_PRESSUREPAD,
+       LITEST_GENERIC_PRESSUREPAD,
 };
 
 #define LITEST_DEVICELESS      -2
index 6b39d11fbeeb812af254dc14b3fe2aff5f7461ae..87c0e5abe31dafaa278a9a62fd73d2cf19c4e0fd 100644 (file)
@@ -3801,7 +3801,8 @@ touchpad_has_palm_pressure(struct litest_device *dev)
                return false;
 
        if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_PRESSURE))
-               return true;
+               return libevdev_get_abs_resolution(evdev,
+                                                  ABS_MT_PRESSURE) == 0;
 
        return false;
 }
index c7e3cbd19f057c099a63a89d06fc2b90904c633a..f6dad2378d4efad6b1479382b09e62cf45e50241 100644 (file)
@@ -1799,7 +1799,8 @@ touchpad_has_palm_pressure(struct litest_device *dev)
                return false;
 
        if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_PRESSURE))
-               return true;
+               return libevdev_get_abs_resolution(evdev,
+                                                  ABS_MT_PRESSURE) == 0;
 
        return false;
 }
@@ -5920,7 +5921,8 @@ touchpad_has_pressure(struct litest_device *dev)
                return false;
 
        if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_PRESSURE))
-               return true;
+               return libevdev_get_abs_resolution(evdev,
+                                                  ABS_MT_PRESSURE) == 0;
 
        if (libevdev_has_event_code(evdev, EV_ABS, ABS_PRESSURE) &&
            !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT))