touchpad: disable the pressure axes wherever the resolution is nonzero

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>
This commit is contained in:
Peter Hutterer 2021-02-05 08:35:10 +10:00
parent 4422e95747
commit 61e41df901
7 changed files with 163 additions and 6 deletions

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

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

View file

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

View file

@ -26,7 +26,12 @@
#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 }
};

View 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

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

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