From 8a95c0e3c82422b6da5f2436557e1c2d4b284602 Mon Sep 17 00:00:00 2001 From: Ryan Hendrickson Date: Sun, 8 Jun 2025 01:29:33 -0400 Subject: [PATCH] wheel: add and use ignore_small_hi_res_movements ignore_small_hi_res_movements is set to true if the underlying device is not virtual. Part-of: --- meson.build | 1 + src/evdev-fallback.h | 1 + src/evdev-wheel.c | 37 +++++++++++++------- src/evdev.h | 7 ++++ test/litest-device-mouse-virtual.c | 54 ++++++++++++++++++++++++++++++ test/litest.h | 1 + test/test-pointer.c | 16 +++++++++ 7 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 test/litest-device-mouse-virtual.c diff --git a/meson.build b/meson.build index 98e500b2..afe7018b 100644 --- a/meson.build +++ b/meson.build @@ -823,6 +823,7 @@ if get_option('tests') 'test/litest-device-mouse-wheel-tilt.c', 'test/litest-device-mouse-roccat.c', 'test/litest-device-mouse-low-dpi.c', + 'test/litest-device-mouse-virtual.c', 'test/litest-device-mouse-wheel-click-angle.c', 'test/litest-device-mouse-wheel-click-count.c', 'test/litest-device-ms-nano-transceiver-mouse.c', diff --git a/src/evdev-fallback.h b/src/evdev-fallback.h index 519ae0a9..f0967307 100644 --- a/src/evdev-fallback.h +++ b/src/evdev-fallback.h @@ -118,6 +118,7 @@ struct fallback_dispatch { bool hi_res_event_received; struct libinput_timer scroll_timer; enum wheel_direction dir; + bool ignore_small_hi_res_movements; } wheel; struct { diff --git a/src/evdev-wheel.c b/src/evdev-wheel.c index 13efece6..5d20fd28 100644 --- a/src/evdev-wheel.c +++ b/src/evdev-wheel.c @@ -92,7 +92,10 @@ wheel_handle_event_on_state_none(struct fallback_dispatch *dispatch, { switch (event) { case WHEEL_EVENT_SCROLL: - dispatch->wheel.state = WHEEL_STATE_ACCUMULATING_SCROLL; + dispatch->wheel.state = + dispatch->wheel.ignore_small_hi_res_movements ? + WHEEL_STATE_ACCUMULATING_SCROLL : + WHEEL_STATE_SCROLLING; break; case WHEEL_EVENT_SCROLL_DIR_CHANGED: break; @@ -132,14 +135,17 @@ wheel_handle_event_on_state_scrolling(struct fallback_dispatch *dispatch, { switch (event) { case WHEEL_EVENT_SCROLL: - wheel_cancel_scroll_timer(dispatch); - wheel_set_scroll_timer(dispatch, time); + if (dispatch->wheel.ignore_small_hi_res_movements) { + wheel_cancel_scroll_timer(dispatch); + wheel_set_scroll_timer(dispatch, time); + } break; case WHEEL_EVENT_SCROLL_TIMEOUT: dispatch->wheel.state = WHEEL_STATE_NONE; break; case WHEEL_EVENT_SCROLL_DIR_CHANGED: - wheel_cancel_scroll_timer(dispatch); + if (dispatch->wheel.ignore_small_hi_res_movements) + wheel_cancel_scroll_timer(dispatch); dispatch->wheel.state = WHEEL_STATE_NONE; break; case WHEEL_EVENT_SCROLL_ACCUMULATED: @@ -447,13 +453,18 @@ fallback_init_wheel(struct fallback_dispatch *dispatch, REL_HWHEEL_HI_RES))) dispatch->wheel.emulate_hi_res_wheel = true; - snprintf(timer_name, - sizeof(timer_name), - "%s wheel scroll", - evdev_device_get_sysname(device)); - libinput_timer_init(&dispatch->wheel.scroll_timer, - evdev_libinput_context(device), - timer_name, - wheel_init_scroll_timer, - device); + dispatch->wheel.ignore_small_hi_res_movements = + !evdev_device_is_virtual(dispatch->device); + + if (dispatch->wheel.ignore_small_hi_res_movements) { + snprintf(timer_name, + sizeof(timer_name), + "%s wheel scroll", + evdev_device_get_sysname(device)); + libinput_timer_init(&dispatch->wheel.scroll_timer, + evdev_libinput_context(device), + timer_name, + wheel_init_scroll_timer, + device); + } } diff --git a/src/evdev.h b/src/evdev.h index e1851ff5..05f6bfba 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -77,6 +77,7 @@ enum evdev_device_tags { EVDEV_TAG_EXTERNAL_KEYBOARD = bit(7), EVDEV_TAG_TABLET_MODE_SWITCH = bit(8), EVDEV_TAG_TABLET_TOUCHPAD = bit(9), + EVDEV_TAG_VIRTUAL = bit(10), }; enum evdev_middlebutton_state { @@ -1046,4 +1047,10 @@ evdev_paired_keyboard_destroy(struct evdev_paired_keyboard *kbd) free(kbd); } +static inline bool +evdev_device_is_virtual(struct evdev_device *device) +{ + return device->tags & EVDEV_TAG_VIRTUAL; +} + #endif /* EVDEV_H */ diff --git a/test/litest-device-mouse-virtual.c b/test/litest-device-mouse-virtual.c new file mode 100644 index 00000000..930521b8 --- /dev/null +++ b/test/litest-device-mouse-virtual.c @@ -0,0 +1,54 @@ +/* + * Copyright © 2025 Ryan Hendrickson + * + * 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 "litest.h" +#include "litest-int.h" + +static struct input_id input_id = { + .bustype = 0x11, + .vendor = 0x1, + .product = 0x2, +}; + +static int events[] = { + EV_REL, REL_WHEEL, + EV_REL, REL_WHEEL_HI_RES, + -1, -1, +}; + +static const char quirk_file[] = +"[litest Virtual Mouse is virtual]\n" +"MatchName=litest Virtual Mouse\n" +"AttrIsVirtual=1\n" +; + +TEST_DEVICE(LITEST_MOUSE_VIRTUAL, + .features = LITEST_WHEEL | LITEST_IGNORED, /* Only needed for mouse wheel tests */ + .interface = NULL, + + .name = "Virtual Mouse", + .id = &input_id, + .events = events, + .absinfo = NULL, + .quirk_file = quirk_file, +) diff --git a/test/litest.h b/test/litest.h index edb569b4..1dc1d596 100644 --- a/test/litest.h +++ b/test/litest.h @@ -461,6 +461,7 @@ enum litest_device_type { LITEST_MOUSE_GLADIUS, LITEST_MOUSE_LOW_DPI, LITEST_MOUSE_ROCCAT, + LITEST_MOUSE_VIRTUAL, LITEST_MOUSE_WHEEL_CLICK_ANGLE, LITEST_MOUSE_WHEEL_CLICK_COUNT, LITEST_MOUSE_WHEEL_TILT, diff --git a/test/test-pointer.c b/test/test-pointer.c index e949f9d6..f0e6ecc7 100644 --- a/test/test-pointer.c +++ b/test/test-pointer.c @@ -916,6 +916,21 @@ START_TEST(pointer_scroll_wheel_inhibit_dir_change) } END_TEST +START_TEST(pointer_scroll_wheel_no_inhibit_small_deltas_when_virtual) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + /* Scroll deltas below the threshold (60) must *not* be ignored */ + litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 15); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_dispatch(li); + test_high_and_low_wheel_events_value(dev, REL_WHEEL_HI_RES, -15); +} +END_TEST + START_TEST(pointer_scroll_wheel_lenovo_scrollpoint) { struct litest_device *dev = litest_current_device(); @@ -3714,6 +3729,7 @@ TEST_COLLECTION(pointer) } 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_no_inhibit_small_deltas_when_virtual, LITEST_MOUSE_VIRTUAL); 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);