Fix negative value range for the dial to ring-mapping (RHEL-104952)
Resolves: RHEL-104952
This commit is contained in:
parent
57458bd0ae
commit
fedc85ddb7
@ -1,4 +1,4 @@
|
||||
From 52bd7e03558c2a5f2356e34cc1fdc9486712d378 Mon Sep 17 00:00:00 2001
|
||||
From 6b3b71d0ddd27207ef4c52c72080ba10b672fa5a Mon Sep 17 00:00:00 2001
|
||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
||||
Date: Tue, 22 Jul 2025 14:22:34 +1000
|
||||
Subject: [PATCH] RHEL: map dials to rings on the Intuos Pro 3rd Gen devices
|
||||
@ -14,13 +14,30 @@ remembered but we only get so much data from a dial.
|
||||
|
||||
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
|
||||
---
|
||||
quirks/30-vendor-wacom.quirks | 42 +++++++++++++++++++++
|
||||
src/evdev-tablet-pad.c | 71 ++++++++++++++++++++++++++++++-----
|
||||
src/evdev-tablet-pad.h | 5 +++
|
||||
src/quirks.c | 1 +
|
||||
src/quirks.h | 1 +
|
||||
5 files changed, 110 insertions(+), 10 deletions(-)
|
||||
meson.build | 1 +
|
||||
quirks/30-vendor-wacom.quirks | 42 +++++++++
|
||||
src/evdev-tablet-pad.c | 89 ++++++++++++++++---
|
||||
src/evdev-tablet-pad.h | 5 ++
|
||||
src/quirks.c | 1 +
|
||||
src/quirks.h | 1 +
|
||||
test/litest-device-wacom-intuos-pro-3rd-pad.c | 87 ++++++++++++++++++
|
||||
test/litest.h | 1 +
|
||||
test/test-tablet.c | 59 ++++++++++++
|
||||
9 files changed, 276 insertions(+), 10 deletions(-)
|
||||
create mode 100644 test/litest-device-wacom-intuos-pro-3rd-pad.c
|
||||
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 3f0583e5879f..f7fbe8222eea 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -822,6 +822,7 @@ if get_option('tests')
|
||||
'test/litest-device-wacom-cintiq-pro-16-pen.c',
|
||||
'test/litest-device-wacom-ekr.c',
|
||||
'test/litest-device-wacom-hid4800-pen.c',
|
||||
+ 'test/litest-device-wacom-intuos-pro-3rd-pad.c',
|
||||
'test/litest-device-wacom-intuos3-pad.c',
|
||||
'test/litest-device-wacom-intuos5-finger.c',
|
||||
'test/litest-device-wacom-intuos5-pad.c',
|
||||
diff --git a/quirks/30-vendor-wacom.quirks b/quirks/30-vendor-wacom.quirks
|
||||
index 51211684c821..79c860efca39 100644
|
||||
--- a/quirks/30-vendor-wacom.quirks
|
||||
@ -72,10 +89,41 @@ index 51211684c821..79c860efca39 100644
|
||||
+MatchProduct=0x03F5
|
||||
+ModelWacomIntuosPro3rd=1
|
||||
diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c
|
||||
index 90614c5dae91..f7b2117c3a56 100644
|
||||
index 90614c5dae91..64d0eae2b603 100644
|
||||
--- a/src/evdev-tablet-pad.c
|
||||
+++ b/src/evdev-tablet-pad.c
|
||||
@@ -335,7 +335,7 @@ pad_check_notify_axes(struct pad_dispatch *pad,
|
||||
@@ -317,6 +317,30 @@ pad_strip_get_mode_group(struct pad_dispatch *pad,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static double
|
||||
+pad_ring_to_dial(double *current_value, double delta)
|
||||
+{
|
||||
+ /* The dial value is in v120 range but needs to be mapped to the 0..360
|
||||
+ * degrees that the ring provides.
|
||||
+ *
|
||||
+ * Let's say one wheel detent (v120) is 15 degrees, this gives us 24
|
||||
+ * lores wheel clicks to go the full 360 degrees circle.
|
||||
+ * If we have 24 clicks per 360 that means our max value is 120 * 24
|
||||
+ * after which we wrap around.
|
||||
+ */
|
||||
+ const int dial_degrees = 15;
|
||||
+ const int detents_per_360 = 360 / dial_degrees;
|
||||
+ const int wrap_threshold = 120 * detents_per_360;
|
||||
+
|
||||
+ double abs_value = *current_value + delta;
|
||||
+ abs_value = fmod(abs_value + wrap_threshold, wrap_threshold);
|
||||
+ *current_value = abs_value;
|
||||
+
|
||||
+ double degrees = abs_value * dial_degrees / 120;
|
||||
+
|
||||
+ return degrees;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
pad_check_notify_axes(struct pad_dispatch *pad,
|
||||
struct evdev_device *device,
|
||||
@@ -335,7 +359,7 @@ pad_check_notify_axes(struct pad_dispatch *pad,
|
||||
|
||||
/* Unlike the ring axis we don't get an event when we release
|
||||
* so we can't set a source */
|
||||
@ -84,7 +132,7 @@ index 90614c5dae91..f7b2117c3a56 100644
|
||||
group = pad_dial_get_mode_group(pad, 0);
|
||||
tablet_pad_notify_dial(base,
|
||||
time,
|
||||
@@ -344,7 +344,7 @@ pad_check_notify_axes(struct pad_dispatch *pad,
|
||||
@@ -344,7 +368,7 @@ pad_check_notify_axes(struct pad_dispatch *pad,
|
||||
group);
|
||||
}
|
||||
|
||||
@ -93,40 +141,34 @@ index 90614c5dae91..f7b2117c3a56 100644
|
||||
group = pad_dial_get_mode_group(pad, 1);
|
||||
tablet_pad_notify_dial(base,
|
||||
time,
|
||||
@@ -353,6 +353,40 @@ pad_check_notify_axes(struct pad_dispatch *pad,
|
||||
@@ -353,6 +377,34 @@ pad_check_notify_axes(struct pad_dispatch *pad,
|
||||
group);
|
||||
}
|
||||
|
||||
+ if (pad->changed_axes & PAD_AXIS_DIAL1 && pad->dials.map_to_ring) {
|
||||
+ pad->dials.abs_dial1_value += pad->dials.dial1;
|
||||
+
|
||||
+ /* Map one dial detent (in v120) to 15 degrees */
|
||||
+ double value = fmod(pad->dials.abs_dial1_value / 8, 360);
|
||||
+ double degrees = pad_ring_to_dial(&pad->dials.abs_dial1_value, pad->dials.dial1);
|
||||
+ if (device->left_handed.enabled)
|
||||
+ value = fmod(value + 180, 360);
|
||||
+ degrees = fmod(degrees + 180, 360);
|
||||
+
|
||||
+ group = pad_ring_get_mode_group(pad, 0);
|
||||
+ tablet_pad_notify_ring(base,
|
||||
+ time,
|
||||
+ 0,
|
||||
+ value,
|
||||
+ degrees,
|
||||
+ LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN,
|
||||
+ group);
|
||||
+ }
|
||||
+
|
||||
+ if (pad->changed_axes & PAD_AXIS_DIAL2 && pad->dials.map_to_ring) {
|
||||
+ pad->dials.abs_dial2_value += pad->dials.dial2;
|
||||
+
|
||||
+ /* Map one dial detent (in v120) to 15 degrees */
|
||||
+ double value = fmod(pad->dials.abs_dial2_value / 8, 360);
|
||||
+ double degrees = pad_ring_to_dial(&pad->dials.abs_dial2_value, pad->dials.dial2);
|
||||
+ if (device->left_handed.enabled)
|
||||
+ value = fmod(value + 180, 360);
|
||||
+ degrees = fmod(degrees + 180, 360);
|
||||
+
|
||||
+ group = pad_ring_get_mode_group(pad, 1);
|
||||
+ tablet_pad_notify_ring(base,
|
||||
+ time,
|
||||
+ 1,
|
||||
+ value,
|
||||
+ degrees,
|
||||
+ LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN,
|
||||
+ group);
|
||||
+ }
|
||||
@ -134,7 +176,7 @@ index 90614c5dae91..f7b2117c3a56 100644
|
||||
if (pad->changed_axes & PAD_AXIS_RING1) {
|
||||
value = pad_handle_ring(pad, device, ABS_WHEEL);
|
||||
if (send_finger_up)
|
||||
@@ -780,6 +814,9 @@ pad_init(struct pad_dispatch *pad, struct evdev_device *device)
|
||||
@@ -780,6 +832,9 @@ pad_init(struct pad_dispatch *pad, struct evdev_device *device)
|
||||
pad->status = PAD_NONE;
|
||||
pad->changed_axes = PAD_AXIS_NONE;
|
||||
|
||||
@ -144,7 +186,7 @@ index 90614c5dae91..f7b2117c3a56 100644
|
||||
/* We expect the kernel to either give us both axes as hires or neither.
|
||||
* Getting one is a kernel bug we don't need to care about */
|
||||
pad->dials.has_hires_dial = libevdev_has_event_code(device->evdev, EV_REL, REL_WHEEL_HI_RES) ||
|
||||
@@ -886,18 +923,15 @@ evdev_device_tablet_pad_get_num_buttons(struct evdev_device *device)
|
||||
@@ -886,18 +941,15 @@ evdev_device_tablet_pad_get_num_buttons(struct evdev_device *device)
|
||||
return pad->nbuttons;
|
||||
}
|
||||
|
||||
@ -168,7 +210,7 @@ index 90614c5dae91..f7b2117c3a56 100644
|
||||
EV_REL,
|
||||
REL_HWHEEL))
|
||||
ndials++;
|
||||
@@ -906,6 +940,19 @@ evdev_device_tablet_pad_get_num_dials(struct evdev_device *device)
|
||||
@@ -906,6 +958,19 @@ evdev_device_tablet_pad_get_num_dials(struct evdev_device *device)
|
||||
return ndials;
|
||||
}
|
||||
|
||||
@ -188,7 +230,7 @@ index 90614c5dae91..f7b2117c3a56 100644
|
||||
int
|
||||
evdev_device_tablet_pad_get_num_rings(struct evdev_device *device)
|
||||
{
|
||||
@@ -914,6 +961,10 @@ evdev_device_tablet_pad_get_num_rings(struct evdev_device *device)
|
||||
@@ -914,6 +979,10 @@ evdev_device_tablet_pad_get_num_rings(struct evdev_device *device)
|
||||
if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD))
|
||||
return -1;
|
||||
|
||||
@ -239,6 +281,186 @@ index 340d04635b9f..ff0ac94e424f 100644
|
||||
QUIRK_MODEL_PRESSURE_PAD,
|
||||
QUIRK_MODEL_TOUCHPAD_PHANTOM_CLICKS,
|
||||
|
||||
diff --git a/test/litest-device-wacom-intuos-pro-3rd-pad.c b/test/litest-device-wacom-intuos-pro-3rd-pad.c
|
||||
new file mode 100644
|
||||
index 000000000000..d5e54d46db6b
|
||||
--- /dev/null
|
||||
+++ b/test/litest-device-wacom-intuos-pro-3rd-pad.c
|
||||
@@ -0,0 +1,87 @@
|
||||
+/*
|
||||
+ * Copyright © 2016 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 = -1, .code = -1 },
|
||||
+};
|
||||
+
|
||||
+static struct input_event move[] = {
|
||||
+ { .type = -1, .code = -1 },
|
||||
+};
|
||||
+
|
||||
+static struct litest_device_interface interface = {
|
||||
+ .touch_down_events = down,
|
||||
+ .touch_move_events = move,
|
||||
+};
|
||||
+
|
||||
+static struct input_absinfo absinfo[] = {
|
||||
+ { ABS_X, 0, 1, 0, 0, 0 },
|
||||
+ { ABS_Y, 0, 1, 0, 0, 0 },
|
||||
+ { ABS_MISC, 0, 0, 0, 0, 0 },
|
||||
+ { .value = -1 },
|
||||
+};
|
||||
+
|
||||
+static struct input_id input_id = {
|
||||
+ .bustype = 0x3,
|
||||
+ .vendor = 0x56a,
|
||||
+ .product = 0x3f9,
|
||||
+};
|
||||
+
|
||||
+static int events[] = {
|
||||
+ EV_KEY, BTN_0,
|
||||
+ EV_KEY, BTN_1,
|
||||
+ EV_KEY, BTN_2,
|
||||
+ EV_KEY, BTN_3,
|
||||
+ EV_KEY, BTN_4,
|
||||
+ EV_KEY, BTN_5,
|
||||
+ EV_KEY, BTN_6,
|
||||
+ EV_KEY, BTN_7,
|
||||
+ EV_KEY, BTN_8,
|
||||
+ EV_KEY, BTN_9,
|
||||
+ EV_KEY, BTN_STYLUS,
|
||||
+ EV_REL, REL_WHEEL,
|
||||
+ EV_REL, REL_HWHEEL,
|
||||
+ EV_REL, REL_WHEEL_HI_RES,
|
||||
+ EV_REL, REL_HWHEEL_HI_RES,
|
||||
+ -1, -1,
|
||||
+};
|
||||
+
|
||||
+TEST_DEVICE("wacom-intuos3-pad",
|
||||
+ .type = LITEST_WACOM_INTUOS_PRO_3RD_PAD,
|
||||
+ .features = LITEST_TABLET_PAD, /* RHEL: not LITEST_DIAL because it's special */
|
||||
+ .interface = &interface,
|
||||
+
|
||||
+ .name = "Wacom Intuos Pro L Pad",
|
||||
+ .id = &input_id,
|
||||
+ .events = events,
|
||||
+ .absinfo = absinfo,
|
||||
+ .udev_properties = {
|
||||
+ { "ID_INPUT_TABLET_PAD", "1" },
|
||||
+ { NULL },
|
||||
+ },
|
||||
+)
|
||||
diff --git a/test/litest.h b/test/litest.h
|
||||
index 6108be50a4c1..93bea19dcd3e 100644
|
||||
--- a/test/litest.h
|
||||
+++ b/test/litest.h
|
||||
@@ -352,6 +352,7 @@ enum litest_device_type {
|
||||
LITEST_WACOM_EKR,
|
||||
LITEST_WACOM_HID4800_PEN,
|
||||
LITEST_WACOM_INTUOS,
|
||||
+ LITEST_WACOM_INTUOS_PRO_3RD_PAD,
|
||||
LITEST_WACOM_INTUOS3_PAD,
|
||||
LITEST_WACOM_INTUOS5_PAD,
|
||||
LITEST_WACOM_ISDV4,
|
||||
diff --git a/test/test-tablet.c b/test/test-tablet.c
|
||||
index b652dcfd5345..ae88c844be91 100644
|
||||
--- a/test/test-tablet.c
|
||||
+++ b/test/test-tablet.c
|
||||
@@ -6560,6 +6560,62 @@ START_TEST(tablet_smoothing)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
+START_TEST(tablet_dial_to_ring)
|
||||
+{
|
||||
+ struct litest_device *dev = litest_current_device();
|
||||
+ struct libinput *li = dev->libinput;
|
||||
+ struct libinput_event *event;
|
||||
+ struct libinput_event_tablet_pad *pev;
|
||||
+
|
||||
+ /* The range is a bitmask of ring, direction, left-handed */
|
||||
+ int testcase = _i; /* ranged test */
|
||||
+ unsigned int ring = testcase & 0x1;
|
||||
+ int direction = testcase & 0x2 ? -1 : 1;
|
||||
+ bool left_handed = !!(testcase & 0x4);
|
||||
+
|
||||
+ litest_assert_int_lt(testcase, 8);
|
||||
+
|
||||
+ const int degrees_per_detent = 15;
|
||||
+
|
||||
+ litest_assert_int_eq(libinput_device_tablet_pad_get_num_dials(dev->libinput_device), 0);
|
||||
+ litest_assert_int_eq(libinput_device_tablet_pad_get_num_rings(dev->libinput_device), 2);
|
||||
+
|
||||
+ /* The dial-to-ring affected devices do not support left-handed so let's
|
||||
+ * make sure setting left-handed a) doesn't work and b) the setting
|
||||
+ * doesn't affect anything.
|
||||
+ */
|
||||
+ enum libinput_config_status rc = libinput_device_config_left_handed_set(dev->libinput_device, left_handed);
|
||||
+ litest_assert_int_eq(rc, (unsigned)LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
|
||||
+
|
||||
+ litest_drain_events(li);
|
||||
+
|
||||
+ double expected = 0.0;
|
||||
+ for (size_t count = 0; count < 36; count++) { /* 24 per 360 so let's do 1.5 rotations */
|
||||
+ if (ring == 0) {
|
||||
+ /* REL_WHEEL is inverted to expectations */
|
||||
+ litest_event(dev, EV_REL, REL_WHEEL, 1 * -direction);
|
||||
+ litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 120 * -direction);
|
||||
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
+ } else {
|
||||
+ litest_event(dev, EV_REL, REL_HWHEEL, 1 * direction);
|
||||
+ litest_event(dev, EV_REL, REL_HWHEEL_HI_RES, 120 * direction);
|
||||
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
+ }
|
||||
+
|
||||
+ libinput_dispatch(li);
|
||||
+
|
||||
+ expected += 360 + direction * degrees_per_detent;
|
||||
+ expected = fmod(expected, 360);
|
||||
+
|
||||
+ event = libinput_get_event(li);
|
||||
+ pev = litest_is_pad_ring_event(event, ring, LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN);
|
||||
+ double value = libinput_event_tablet_pad_get_ring_position(pev);
|
||||
+ litest_assert_double_eq(value, expected);
|
||||
+ libinput_event_destroy(event);
|
||||
+ }
|
||||
+}
|
||||
+END_TEST
|
||||
+
|
||||
TEST_COLLECTION(tablet)
|
||||
{
|
||||
struct range with_timeout = { 0, 2 };
|
||||
@@ -6704,4 +6760,7 @@ TEST_COLLECTION(tablet)
|
||||
litest_add_ranged_for_device(huion_static_btn_tool_pen_disable_quirk_on_prox_out, LITEST_HUION_TABLET, &with_timeout);
|
||||
|
||||
litest_add_for_device(tablet_smoothing, LITEST_WACOM_HID4800_PEN);
|
||||
+
|
||||
+ struct range dial_ring_cases = { 0, 8 };
|
||||
+ litest_add_ranged_for_device(tablet_dial_to_ring, LITEST_WACOM_INTUOS_PRO_3RD_PAD, &dial_ring_cases);
|
||||
}
|
||||
--
|
||||
2.50.1
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
Name: libinput
|
||||
Version: 1.26.1
|
||||
Release: 3%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist}
|
||||
Release: 4%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist}
|
||||
Summary: Input device library
|
||||
|
||||
# SPDX
|
||||
@ -160,6 +160,9 @@ intended to be run by users.
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jul 25 2025 Peter Hutterer <peter.hutterer@redhat.com> - 1.26.1-4
|
||||
- Fix negative value range for the dial to ring-mapping (RHEL-104952)
|
||||
|
||||
* Wed Jul 23 2025 Peter Hutterer <peter.hutterer@redhat.com> - 1.26.1-3
|
||||
- Support Wacom Intuos Pro 3rd by mapping the dial to a ring (RHEL-104952)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user