mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-03 13:30:27 +01:00
fallback: hires scroll heuristics for buggy devices
Some devices might announce support for high-resolution scroll wheel by enabling REL_WHEEL_HI_RES and/or REL_HWHEEL_HI_RES but never send a high-resolution scroll event. When the first low-resolution scroll event is received without any previous high-resolution event, print a kernel bug warning and start emulating high-resolution scroll events. Fix #668 Signed-off-by: José Expósito <jose.exposito89@gmail.com>
This commit is contained in:
parent
e0aa946e39
commit
5bda716ebf
6 changed files with 146 additions and 0 deletions
62
doc/user/incorrectly-enabled-hires.rst
Normal file
62
doc/user/incorrectly-enabled-hires.rst
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
.. _incorrectly_enabled_hires:
|
||||
|
||||
==============================================================================
|
||||
Incorrectly enabled high-resolution scroll
|
||||
==============================================================================
|
||||
|
||||
Some devices might announce support for high-resolution scroll wheel by enabling
|
||||
``REL_WHEEL_HI_RES`` and/or ``REL_HWHEEL_HI_RES`` but never send a
|
||||
high-resolution scroll event.
|
||||
|
||||
When the first low-resolution scroll event is received without any previous
|
||||
high-resolution event, libinput prints a bug warning with the text **"device
|
||||
supports high-resolution scroll but only low-resolution events have been
|
||||
received"** and a link to this page.
|
||||
|
||||
.. note:: This warning will be printed only once
|
||||
|
||||
In most cases this is a bug on the device firmware, the kernel driver or in a
|
||||
software used to create user-space devices through uinput.
|
||||
|
||||
Once the bug is detected, libinput will start emulating high-resolution scroll
|
||||
events.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Detecting and fixing the issue
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Events sent by a buggy device can be shown in the
|
||||
:ref:`libinput record <libinput-record>` output for the device. Notice that
|
||||
``REL_WHEEL_HI_RES`` and ``REL_HWHEEL_HI_RES`` are set but only ``REL_WHEEL``
|
||||
events are sent: ::
|
||||
|
||||
# Supported Events:
|
||||
# Event type 0 (EV_SYN)
|
||||
# Event type 1 (EV_KEY)
|
||||
# Event code 272 (BTN_LEFT)
|
||||
# Event type 2 (EV_REL)
|
||||
# Event code 0 (REL_X)
|
||||
# Event code 1 (REL_Y)
|
||||
# Event code 6 (REL_HWHEEL)
|
||||
# Event code 8 (REL_WHEEL)
|
||||
# Event code 11 (REL_WHEEL_HI_RES)
|
||||
# Event code 12 (REL_HWHEEL_HI_RES)
|
||||
[...]
|
||||
quirks:
|
||||
events:
|
||||
- evdev:
|
||||
- [ 0, 0, 2, 8, 1] # EV_REL / REL_WHEEL 1
|
||||
- [ 0, 0, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +0ms
|
||||
- evdev:
|
||||
- [ 0, 15126, 2, 8, 1] # EV_REL / REL_WHEEL 1
|
||||
- [ 0, 15126, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +15ms
|
||||
- evdev:
|
||||
- [ 0, 30250, 2, 8, 1] # EV_REL / REL_WHEEL 1
|
||||
- [ 0, 30250, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +15ms
|
||||
|
||||
The issue can be fixed by adding a quirk to unset the ``REL_WHEEL_HI_RES`` and
|
||||
``REL_HWHEEL_HI_RES`` event codes: ::
|
||||
|
||||
AttrEventCodeDisable=REL_WHEEL_HI_RES;REL_HWHEEL_HI_RES;
|
||||
|
||||
Please see :ref:`device-quirks` for details.
|
||||
|
|
@ -50,6 +50,7 @@ src_404s = [
|
|||
[ 'faqs.rst', 'faq.html'],
|
||||
[ 'features.rst', 'features.html'],
|
||||
[ 'gestures.rst', 'gestures.html'],
|
||||
[ 'incorrectly-enabled-hires.rst', 'incorrectly-enabled-hires.html'],
|
||||
[ 'middle-button-emulation.rst', 'middle_button_emulation.html'],
|
||||
[ 'normalization-of-relative-motion.rst', 'motion_normalization.html'],
|
||||
[ 'palm-detection.rst', 'palm_detection.html'],
|
||||
|
|
@ -143,6 +144,7 @@ src_rst = files(
|
|||
'device-quirks.rst',
|
||||
'faqs.rst',
|
||||
'gestures.rst',
|
||||
'incorrectly-enabled-hires.rst',
|
||||
'middle-button-emulation.rst',
|
||||
'normalization-of-relative-motion.rst',
|
||||
'palm-detection.rst',
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ Troubleshooting
|
|||
touchpad-pressure-debugging.rst
|
||||
trackpoint-configuration.rst
|
||||
tablet-debugging.rst
|
||||
incorrectly-enabled-hires.rst
|
||||
|
|
|
|||
|
|
@ -235,6 +235,18 @@ fallback_flush_wheels(struct fallback_dispatch *dispatch,
|
|||
if (!(device->seat_caps & EVDEV_DEVICE_POINTER))
|
||||
return;
|
||||
|
||||
if (!dispatch->wheel.emulate_hi_res_wheel &&
|
||||
!dispatch->wheel.hi_res_event_received &&
|
||||
(dispatch->wheel.lo_res.x != 0 || dispatch->wheel.lo_res.y != 0)) {
|
||||
evdev_log_bug_kernel(device,
|
||||
"device supports high-resolution scroll but only low-resolution events have been received.\n"
|
||||
"See %s/incorrectly-enabled-hires.html for details\n",
|
||||
HTTP_DOC_LINK);
|
||||
dispatch->wheel.emulate_hi_res_wheel = true;
|
||||
dispatch->wheel.hi_res.x = dispatch->wheel.lo_res.x * 120;
|
||||
dispatch->wheel.hi_res.y = dispatch->wheel.lo_res.y * 120;
|
||||
}
|
||||
|
||||
if (dispatch->wheel.is_inhibited) {
|
||||
dispatch->wheel.hi_res.x = 0;
|
||||
dispatch->wheel.hi_res.y = 0;
|
||||
|
|
@ -897,10 +909,12 @@ fallback_process_relative(struct fallback_dispatch *dispatch,
|
|||
break;
|
||||
case REL_WHEEL_HI_RES:
|
||||
dispatch->wheel.hi_res.y += e->value;
|
||||
dispatch->wheel.hi_res_event_received = true;
|
||||
dispatch->pending_event |= EVDEV_WHEEL;
|
||||
break;
|
||||
case REL_HWHEEL_HI_RES:
|
||||
dispatch->wheel.hi_res.x += e->value;
|
||||
dispatch->wheel.hi_res_event_received = true;
|
||||
dispatch->pending_event |= EVDEV_WHEEL;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ struct fallback_dispatch {
|
|||
struct device_coords hi_res;
|
||||
bool emulate_hi_res_wheel;
|
||||
bool is_inhibited;
|
||||
bool hi_res_event_received;
|
||||
} wheel;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -803,6 +803,70 @@ START_TEST(pointer_scroll_wheel_hires)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pointer_scroll_wheel_hires_send_only_lores_vertical)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES) &&
|
||||
!libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES))
|
||||
return;
|
||||
|
||||
litest_drain_events(dev->libinput);
|
||||
litest_set_log_handler_bug(li);
|
||||
|
||||
litest_event(dev, EV_REL, REL_WHEEL, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
test_high_and_low_wheel_events_value(dev, REL_WHEEL, -120);
|
||||
|
||||
litest_event(dev, EV_REL, REL_WHEEL, -1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
test_high_and_low_wheel_events_value(dev, REL_WHEEL, 120);
|
||||
|
||||
litest_event(dev, EV_REL, REL_HWHEEL, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
test_high_and_low_wheel_events_value(dev, REL_HWHEEL, 120);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
litest_restore_log_handler(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pointer_scroll_wheel_hires_send_only_lores_horizontal)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES) &&
|
||||
!libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL_HI_RES))
|
||||
return;
|
||||
|
||||
litest_drain_events(dev->libinput);
|
||||
litest_set_log_handler_bug(li);
|
||||
|
||||
litest_event(dev, EV_REL, REL_HWHEEL, 2);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
test_high_and_low_wheel_events_value(dev, REL_HWHEEL, 240);
|
||||
|
||||
litest_event(dev, EV_REL, REL_WHEEL, -1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
test_high_and_low_wheel_events_value(dev, REL_WHEEL, 120);
|
||||
|
||||
litest_event(dev, EV_REL, REL_HWHEEL, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
test_high_and_low_wheel_events_value(dev, REL_HWHEEL, 120);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
litest_restore_log_handler(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pointer_scroll_natural_defaults)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -3429,6 +3493,8 @@ TEST_COLLECTION(pointer)
|
|||
litest_add_for_device(pointer_scroll_wheel_pressed_noscroll, LITEST_MOUSE);
|
||||
litest_add_for_device(pointer_scroll_hi_res_wheel_pressed_noscroll, LITEST_MOUSE);
|
||||
litest_add(pointer_scroll_wheel_hires, LITEST_WHEEL, LITEST_TABLET);
|
||||
litest_add(pointer_scroll_wheel_hires_send_only_lores_vertical, LITEST_WHEEL, LITEST_TABLET);
|
||||
litest_add(pointer_scroll_wheel_hires_send_only_lores_horizontal, LITEST_WHEEL, LITEST_TABLET);
|
||||
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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue