diff options
author | José Expósito <jose.exposito89@gmail.com> | 2022-06-06 20:24:16 +0200 |
---|---|---|
committer | José Expósito <jose.exposito89@gmail.com> | 2022-06-07 19:55:42 +0200 |
commit | 4ae72b6eb2e4487a16d2c8e9b663bcb66618e388 (patch) | |
tree | c87a0cdae819f44dc174b7fece2f86e4d9c1cbd8 | |
parent | 7688f35477cae9ecceec86ac15a2619ed222d2fe (diff) | |
download | libinput-4ae72b6eb2e4487a16d2c8e9b663bcb66618e388.tar.gz |
wheel: fix Lenovo Scrollpoint quirk
The IBM/Lenovo Scrollpoint mouse features a trackpoint-like stick that
sends a great amount of scroll deltas.
In order to handle the device, a quirk is in place to normalize the
scroll events as they were relative motion.
However, when high-resolution scroll was implemented, we started
normalizing the hi-res events instead of the lo-res events by mistake.
Fix the quirk by normalizing the right deltas.
Fixes: 6bb02aaf307a ("High-resolution scroll wheel support")
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
Tested-by: Peter Ganzhorn <peter.ganzhorn@gmail.com>
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | src/evdev-wheel.c | 9 | ||||
-rw-r--r-- | test/litest-device-lenovo-scrollpoint.c | 60 | ||||
-rw-r--r-- | test/litest.h | 1 | ||||
-rw-r--r-- | test/test-pointer.c | 71 |
5 files changed, 139 insertions, 3 deletions
diff --git a/meson.build b/meson.build index afbcc7a9..b8b92710 100644 --- a/meson.build +++ b/meson.build @@ -758,6 +758,7 @@ if get_option('tests') 'test/litest-device-keyboard-razer-blackwidow.c', 'test/litest-device-keyboard-razer-blade-stealth.c', 'test/litest-device-keyboard-razer-blade-stealth-videoswitch.c', + 'test/litest-device-lenovo-scrollpoint.c', 'test/litest-device-lid-switch.c', 'test/litest-device-lid-switch-surface3.c', 'test/litest-device-logitech-media-keyboard-elite.c', diff --git a/src/evdev-wheel.c b/src/evdev-wheel.c index 69984c9b..7fcf658d 100644 --- a/src/evdev-wheel.c +++ b/src/evdev-wheel.c @@ -187,17 +187,22 @@ wheel_flush_scroll(struct fallback_dispatch *dispatch, struct discrete_coords discrete = { 0.0, 0.0 }; struct wheel_v120 v120 = { 0.0, 0.0 }; + /* This mouse has a trackstick instead of a mouse wheel and sends + * trackstick data via REL_WHEEL. Normalize it like normal x/y coordinates. + */ if (device->model_flags & EVDEV_MODEL_LENOVO_SCROLLPOINT) { struct normalized_coords unaccel = { 0.0, 0.0 }; - dispatch->wheel.hi_res.y *= -1; - fallback_normalize_delta(device, &dispatch->wheel.hi_res, &unaccel); + dispatch->wheel.lo_res.y *= -1; + fallback_normalize_delta(device, &dispatch->wheel.lo_res, &unaccel); evdev_post_scroll(device, time, LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, &unaccel); dispatch->wheel.hi_res.x = 0; dispatch->wheel.hi_res.y = 0; + dispatch->wheel.lo_res.x = 0; + dispatch->wheel.lo_res.y = 0; return; } diff --git a/test/litest-device-lenovo-scrollpoint.c b/test/litest-device-lenovo-scrollpoint.c new file mode 100644 index 00000000..a61db926 --- /dev/null +++ b/test/litest-device-lenovo-scrollpoint.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2013 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_id input_id = { + .bustype = 0x3, + .vendor = 0x04b3, + .product = 0x3109, +}; + +static int events[] = { + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + EV_KEY, BTN_MIDDLE, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_REL, REL_WHEEL, + EV_REL, REL_WHEEL_HI_RES, + EV_REL, REL_HWHEEL, + -1 , -1, +}; + +/* Note: device is not tagged with LITEST_WHEEL to avoid running the + * "standard" wheel tests. Device has a custom wheel + * behavior that is tested directly. + */ +TEST_DEVICE("lenovo-scrollpoint", + .type = LITEST_LENOVO_SCROLLPOINT, + .features = LITEST_RELATIVE | LITEST_BUTTON, + .interface = NULL, + + .name = "HID 04b3:3109", + .id = &input_id, + .absinfo = NULL, + .events = events, +) diff --git a/test/litest.h b/test/litest.h index 1b1daa90..7ac54f3e 100644 --- a/test/litest.h +++ b/test/litest.h @@ -322,6 +322,7 @@ enum litest_device_type { LITEST_GENERIC_PRESSUREPAD, LITEST_WACOM_ISDV4_524C_PEN, LITEST_MOUSE_FORMAT_STRING, + LITEST_LENOVO_SCROLLPOINT, }; #define LITEST_DEVICELESS -2 diff --git a/test/test-pointer.c b/test/test-pointer.c index 0fac6387..7fbec60d 100644 --- a/test/test-pointer.c +++ b/test/test-pointer.c @@ -900,6 +900,73 @@ START_TEST(pointer_scroll_wheel_inhibit_dir_change) } END_TEST +START_TEST(pointer_scroll_wheel_lenovo_scrollpoint) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + double v; + + litest_drain_events(dev->libinput); + + /* Lenovo ScrollPoint has a trackstick instead of a wheel, data sent + * via REL_WHEEL is close to x/y coordinate space. + */ + litest_event(dev, EV_REL, REL_WHEEL, 30); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_REL, REL_WHEEL, -60); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + /* Hi-res scroll event first */ + event = libinput_get_event(li); + litest_assert(litest_is_high_res_axis_event(event)); + ptrev = litest_is_axis_event(event, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); + + v = libinput_event_pointer_get_scroll_value(ptrev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + litest_assert_double_eq(v, -30.0); + libinput_event_destroy(event); + + /* legacy lo-res scroll event */ + event = libinput_get_event(li); + litest_assert(!litest_is_high_res_axis_event(event)); + ptrev = litest_is_axis_event(event, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); + v = libinput_event_pointer_get_axis_value(ptrev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + litest_assert_double_eq(v, -30.0); + libinput_event_destroy(event); + + /* Hi-res scroll event first */ + event = libinput_get_event(li); + ptrev = litest_is_axis_event(event, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); + + v = libinput_event_pointer_get_scroll_value(ptrev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + litest_assert_double_eq(v, 60.0); + libinput_event_destroy(event); + + /* legacy lo-res scroll event */ + event = libinput_get_event(li); + litest_assert(!litest_is_high_res_axis_event(event)); + ptrev = litest_is_axis_event(event, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); + v = libinput_event_pointer_get_axis_value(ptrev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + litest_assert_double_eq(v, 60.0); + libinput_event_destroy(event); + +} +END_TEST + START_TEST(pointer_scroll_natural_defaults) { struct litest_device *dev = litest_current_device(); @@ -1964,7 +2031,8 @@ START_TEST(pointer_scroll_nowheel_defaults) /* button scrolling is only enabled if there is a middle button present */ - if (libinput_device_pointer_has_button(device, BTN_MIDDLE)) + if (libinput_device_pointer_has_button(device, BTN_MIDDLE) && + dev->which != LITEST_LENOVO_SCROLLPOINT) expected = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; else expected = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; @@ -3528,6 +3596,7 @@ TEST_COLLECTION(pointer) litest_add(pointer_scroll_wheel_hires_send_only_lores_horizontal, LITEST_WHEEL, LITEST_TABLET); litest_add(pointer_scroll_wheel_inhibit_small_deltas, LITEST_WHEEL, LITEST_TABLET); litest_add(pointer_scroll_wheel_inhibit_dir_change, LITEST_WHEEL, LITEST_TABLET); + litest_add_for_device(pointer_scroll_wheel_lenovo_scrollpoint, LITEST_LENOVO_SCROLLPOINT); litest_add(pointer_scroll_button, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY); litest_add(pointer_scroll_button_noscroll, LITEST_ABSOLUTE|LITEST_BUTTON, LITEST_RELATIVE); litest_add(pointer_scroll_button_noscroll, LITEST_ANY, LITEST_RELATIVE|LITEST_BUTTON); |