diff --git a/meson.build b/meson.build index 290ae30f..5c1587c3 100644 --- a/meson.build +++ b/meson.build @@ -842,6 +842,7 @@ if get_option('tests') 'test/litest-device-magic-trackpad.c', 'test/litest-device-mouse.c', 'test/litest-device-mouse-wheel-tilt.c', + 'test/litest-device-mouse-wheel-hires-disabled.c', 'test/litest-device-mouse-ps2.c', 'test/litest-device-mouse-roccat.c', 'test/litest-device-mouse-low-dpi.c', diff --git a/src/libinput-plugin-mouse-wheel-lowres.c b/src/libinput-plugin-mouse-wheel-lowres.c index ce3847e2..4302c2be 100644 --- a/src/libinput-plugin-mouse-wheel-lowres.c +++ b/src/libinput-plugin-mouse-wheel-lowres.c @@ -64,24 +64,43 @@ wheel_plugin_evdev_frame(struct libinput_plugin *libinput_plugin, size_t nevents; struct evdev_event *events = evdev_frame_get_events(frame, &nevents); + _unref_(evdev_frame) *filtered_frame = evdev_frame_new(nevents + 2); for (size_t i = 0; i < nevents; i++) { struct evdev_event *e = &events[i]; + switch (evdev_usage_enum(e->usage)) { + case EVDEV_REL_WHEEL_HI_RES: + case EVDEV_REL_HWHEEL_HI_RES: + /* In the uncommon case that our device sends high-res events + * filter those out. This can happen on devices that have the + * highres scroll axes disabled via quirks. The device still + * sends events so when we re-enable the axis in + * wheel_plugin_device_new we get the device events again, + * effectively duplicating the high resolution scroll events. + */ + break; case EVDEV_REL_WHEEL: - evdev_frame_append_one(frame, + evdev_frame_append(filtered_frame, e, 1); + evdev_frame_append_one(filtered_frame, evdev_usage_from(EVDEV_REL_WHEEL_HI_RES), e->value * 120); break; case EVDEV_REL_HWHEEL: + evdev_frame_append(filtered_frame, e, 1); evdev_frame_append_one( - frame, + filtered_frame, evdev_usage_from(EVDEV_REL_HWHEEL_HI_RES), e->value * 120); break; default: + evdev_frame_append(filtered_frame, e, 1); break; } } + + evdev_frame_set(frame, + evdev_frame_get_events(filtered_frame, NULL), + evdev_frame_get_count(filtered_frame)); } static const struct libinput_plugin_interface interface = { diff --git a/test/litest-device-mouse-wheel-hires-disabled.c b/test/litest-device-mouse-wheel-hires-disabled.c new file mode 100644 index 00000000..e41d90c2 --- /dev/null +++ b/test/litest-device-mouse-wheel-hires-disabled.c @@ -0,0 +1,63 @@ +/* + * 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-int.h" +#include "litest.h" + +static struct input_id input_id = { + .bustype = 0x3, + .vendor = 0x1234, + .product = 0xabcd, +}; + +/* clang-format off */ +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, + EV_REL, REL_HWHEEL_HI_RES, + -1 , -1, +}; +/* clang-format on */ + +static const char quirk_file[] = + "[litest hires wheel disabled mouse]\n" + "MatchName=litest Mouse with disabled high-res wheels\n" + "AttrEventCode=-REL_WHEEL_HI_RES;-REL_HWHEEL_HI_RES\n"; + +TEST_DEVICE(LITEST_MOUSE_WHEEL_HIRES_DISABLED, + .features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL, + .interface = NULL, + + .name = "Mouse with disabled high-res wheels", + .id = &input_id, + .absinfo = NULL, + .events = events, + .quirk_file = quirk_file, ) diff --git a/test/litest.h b/test/litest.h index dba61baf..79152b91 100644 --- a/test/litest.h +++ b/test/litest.h @@ -477,6 +477,7 @@ enum litest_device_type { LITEST_MOUSE_WHEEL_CLICK_ANGLE, LITEST_MOUSE_WHEEL_CLICK_COUNT, LITEST_MOUSE_WHEEL_TILT, + LITEST_MOUSE_WHEEL_HIRES_DISABLED, LITEST_MS_NANO_TRANSCEIVER_MOUSE, LITEST_SONY_VAIO_KEYS, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS, diff --git a/test/test-pointer.c b/test/test-pointer.c index 38498d69..e6379321 100644 --- a/test/test-pointer.c +++ b/test/test-pointer.c @@ -794,6 +794,9 @@ START_TEST(pointer_scroll_wheel_hires) test_hi_res_wheel_event(dev, axis, -5 * 120); test_hi_res_wheel_event(dev, axis, 6 * 120); + if (dev->which == LITEST_MOUSE_WHEEL_HIRES_DISABLED) + return LITEST_NOT_APPLICABLE; + test_hi_res_wheel_event(dev, axis, 30); test_hi_res_wheel_event(dev, axis, -60); test_hi_res_wheel_event(dev, axis, -40); @@ -855,6 +858,64 @@ START_TEST(pointer_scroll_wheel_hires_send_only_lores) } END_TEST +START_TEST(pointer_scroll_wheel_hires_disabled) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int direction; + unsigned int lores_code, hires_code; + enum libinput_pointer_axis axis = + litest_test_param_get_i32(test_env->params, "axis"); + + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + lores_code = REL_WHEEL; + hires_code = REL_WHEEL_HI_RES; + direction = -1; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + lores_code = REL_HWHEEL; + hires_code = REL_HWHEEL_HI_RES; + direction = 1; + break; + default: + litest_abort_msg("Invalid test axis '%d'", axis); + } + + litest_drain_events(li); + + litest_log_group("High-res events on this device should be ignored") { + for (size_t i = 0; i < 4; i++) { + litest_event(dev, EV_REL, hires_code, 60); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + litest_assert_empty_queue(li); + } + + litest_log_group("Only low-res events should be handled") { + for (size_t i = 0; i < 4; i++) { + litest_event(dev, EV_REL, hires_code, 60); + litest_event(dev, EV_REL, lores_code, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_dispatch(li); + + litest_drain_events_of_type(li, LIBINPUT_EVENT_POINTER_AXIS); + _destroy_(libinput_event) *ev = libinput_get_event(li); + struct libinput_event_pointer *pev = litest_is_axis_event( + ev, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + axis, + 0); + int v120 = + libinput_event_pointer_get_scroll_value_v120(pev, axis); + litest_assert_int_eq(v120, direction * 120); + } + litest_drain_events_of_type(li, LIBINPUT_EVENT_POINTER_AXIS); + litest_assert_empty_queue(li); + } +} +END_TEST + START_TEST(pointer_scroll_wheel_inhibit_small_deltas) { struct litest_device *dev = litest_current_device(); @@ -865,6 +926,9 @@ START_TEST(pointer_scroll_wheel_inhibit_small_deltas) !libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES)) return LITEST_NOT_APPLICABLE; + if (dev->which == LITEST_MOUSE_WHEEL_HIRES_DISABLED) + return LITEST_NOT_APPLICABLE; + litest_drain_events(dev->libinput); /* A single delta (below the hardcoded threshold 60) is ignored */ @@ -910,6 +974,9 @@ START_TEST(pointer_scroll_wheel_inhibit_small_deltas_reduce_delta) !libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES)) return LITEST_NOT_APPLICABLE; + if (dev->which == LITEST_MOUSE_WHEEL_HIRES_DISABLED) + return LITEST_NOT_APPLICABLE; + litest_drain_events(dev->libinput); /* A single delta (below the hardcoded threshold 30) is ignored */ @@ -959,6 +1026,9 @@ START_TEST(pointer_scroll_wheel_inhibit_dir_change) if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES)) return LITEST_NOT_APPLICABLE; + if (dev->which == LITEST_MOUSE_WHEEL_HIRES_DISABLED) + return LITEST_NOT_APPLICABLE; + litest_drain_events(dev->libinput); /* Scroll one detent and a bit */ @@ -3707,6 +3777,7 @@ TEST_COLLECTION(pointer) litest_with_parameters(params, "axis", 'I', 2, litest_named_i32(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, "vertical"), litest_named_i32(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, "horizontal")) { litest_add_parametrized(pointer_scroll_wheel_hires_send_only_lores, LITEST_WHEEL, LITEST_TABLET, params); + litest_add_parametrized_for_device(pointer_scroll_wheel_hires_disabled, LITEST_MOUSE_WHEEL_HIRES_DISABLED, params); } litest_with_parameters(params, "hires-delta", 'u', 3, 5, 15, 20) { litest_add_parametrized(pointer_scroll_wheel_inhibit_small_deltas, LITEST_WHEEL, LITEST_TABLET, params);