mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 03:20:05 +01:00
plugin: ignore high-resolution wheel events from disabled wheels
Make sure we drop any potential high-resolution wheel events from a device that isn't supposed to have them. Where the device's axes were disabled due to a quirk, re-enabling the axes means the device's events won't be filtered anymore. Our wheel emulation plugin thus emulates high-resolution wheel events in addition to the hardware events. Fix this by simply filtering out any high-resolution wheel events on any device that uses this plugin. Closes #1160 Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1279>
This commit is contained in:
parent
6aefc2f166
commit
36b2afae82
5 changed files with 157 additions and 2 deletions
|
|
@ -842,6 +842,7 @@ if get_option('tests')
|
||||||
'test/litest-device-magic-trackpad.c',
|
'test/litest-device-magic-trackpad.c',
|
||||||
'test/litest-device-mouse.c',
|
'test/litest-device-mouse.c',
|
||||||
'test/litest-device-mouse-wheel-tilt.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-ps2.c',
|
||||||
'test/litest-device-mouse-roccat.c',
|
'test/litest-device-mouse-roccat.c',
|
||||||
'test/litest-device-mouse-low-dpi.c',
|
'test/litest-device-mouse-low-dpi.c',
|
||||||
|
|
|
||||||
|
|
@ -64,24 +64,43 @@ wheel_plugin_evdev_frame(struct libinput_plugin *libinput_plugin,
|
||||||
size_t nevents;
|
size_t nevents;
|
||||||
struct evdev_event *events = evdev_frame_get_events(frame, &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++) {
|
for (size_t i = 0; i < nevents; i++) {
|
||||||
struct evdev_event *e = &events[i];
|
struct evdev_event *e = &events[i];
|
||||||
|
|
||||||
switch (evdev_usage_enum(e->usage)) {
|
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:
|
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),
|
evdev_usage_from(EVDEV_REL_WHEEL_HI_RES),
|
||||||
e->value * 120);
|
e->value * 120);
|
||||||
break;
|
break;
|
||||||
case EVDEV_REL_HWHEEL:
|
case EVDEV_REL_HWHEEL:
|
||||||
|
evdev_frame_append(filtered_frame, e, 1);
|
||||||
evdev_frame_append_one(
|
evdev_frame_append_one(
|
||||||
frame,
|
filtered_frame,
|
||||||
evdev_usage_from(EVDEV_REL_HWHEEL_HI_RES),
|
evdev_usage_from(EVDEV_REL_HWHEEL_HI_RES),
|
||||||
e->value * 120);
|
e->value * 120);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
evdev_frame_append(filtered_frame, e, 1);
|
||||||
break;
|
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 = {
|
static const struct libinput_plugin_interface interface = {
|
||||||
|
|
|
||||||
63
test/litest-device-mouse-wheel-hires-disabled.c
Normal file
63
test/litest-device-mouse-wheel-hires-disabled.c
Normal file
|
|
@ -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, )
|
||||||
|
|
@ -477,6 +477,7 @@ enum litest_device_type {
|
||||||
LITEST_MOUSE_WHEEL_CLICK_ANGLE,
|
LITEST_MOUSE_WHEEL_CLICK_ANGLE,
|
||||||
LITEST_MOUSE_WHEEL_CLICK_COUNT,
|
LITEST_MOUSE_WHEEL_CLICK_COUNT,
|
||||||
LITEST_MOUSE_WHEEL_TILT,
|
LITEST_MOUSE_WHEEL_TILT,
|
||||||
|
LITEST_MOUSE_WHEEL_HIRES_DISABLED,
|
||||||
LITEST_MS_NANO_TRANSCEIVER_MOUSE,
|
LITEST_MS_NANO_TRANSCEIVER_MOUSE,
|
||||||
LITEST_SONY_VAIO_KEYS,
|
LITEST_SONY_VAIO_KEYS,
|
||||||
LITEST_SYNAPTICS_TRACKPOINT_BUTTONS,
|
LITEST_SYNAPTICS_TRACKPOINT_BUTTONS,
|
||||||
|
|
|
||||||
|
|
@ -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, -5 * 120);
|
||||||
test_hi_res_wheel_event(dev, axis, 6 * 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, 30);
|
||||||
test_hi_res_wheel_event(dev, axis, -60);
|
test_hi_res_wheel_event(dev, axis, -60);
|
||||||
test_hi_res_wheel_event(dev, axis, -40);
|
test_hi_res_wheel_event(dev, axis, -40);
|
||||||
|
|
@ -855,6 +858,64 @@ START_TEST(pointer_scroll_wheel_hires_send_only_lores)
|
||||||
}
|
}
|
||||||
END_TEST
|
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)
|
START_TEST(pointer_scroll_wheel_inhibit_small_deltas)
|
||||||
{
|
{
|
||||||
struct litest_device *dev = litest_current_device();
|
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))
|
!libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES))
|
||||||
return LITEST_NOT_APPLICABLE;
|
return LITEST_NOT_APPLICABLE;
|
||||||
|
|
||||||
|
if (dev->which == LITEST_MOUSE_WHEEL_HIRES_DISABLED)
|
||||||
|
return LITEST_NOT_APPLICABLE;
|
||||||
|
|
||||||
litest_drain_events(dev->libinput);
|
litest_drain_events(dev->libinput);
|
||||||
|
|
||||||
/* A single delta (below the hardcoded threshold 60) is ignored */
|
/* 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))
|
!libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES))
|
||||||
return LITEST_NOT_APPLICABLE;
|
return LITEST_NOT_APPLICABLE;
|
||||||
|
|
||||||
|
if (dev->which == LITEST_MOUSE_WHEEL_HIRES_DISABLED)
|
||||||
|
return LITEST_NOT_APPLICABLE;
|
||||||
|
|
||||||
litest_drain_events(dev->libinput);
|
litest_drain_events(dev->libinput);
|
||||||
|
|
||||||
/* A single delta (below the hardcoded threshold 30) is ignored */
|
/* 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))
|
if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES))
|
||||||
return LITEST_NOT_APPLICABLE;
|
return LITEST_NOT_APPLICABLE;
|
||||||
|
|
||||||
|
if (dev->which == LITEST_MOUSE_WHEEL_HIRES_DISABLED)
|
||||||
|
return LITEST_NOT_APPLICABLE;
|
||||||
|
|
||||||
litest_drain_events(dev->libinput);
|
litest_drain_events(dev->libinput);
|
||||||
|
|
||||||
/* Scroll one detent and a bit */
|
/* 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_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_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(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_with_parameters(params, "hires-delta", 'u', 3, 5, 15, 20) {
|
||||||
litest_add_parametrized(pointer_scroll_wheel_inhibit_small_deltas, LITEST_WHEEL, LITEST_TABLET, params);
|
litest_add_parametrized(pointer_scroll_wheel_inhibit_small_deltas, LITEST_WHEEL, LITEST_TABLET, params);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue