Reporting high-resolution scroll events

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

I'm currently working on supporting high-resolution scrolling, such as is found
on a growing number of mice from Logitech and Microsoft. Below you'll find my
proposal for reporting these events through evdev in a backwards-compatible way.
I'd appreciate any input you might have. For a quick summary, just read the
"Proposed solution" section.

Thanks,

Harry Cutts
Chromium OS Touch/Input Team


Background
==========

A lot of modern mice (mostly from Logitech but also from Microsoft) support
high-resolution (sometimes called high-precision) scrolling, which is normally
eight times as precise as standard scroll events. The Linux kernel does not
currently support this feature, so the mice remain in low-resolution mode.

Objective
=========

Report high-resolution scrolling events to user-space libraries and applications
(e.g. libinput, Chromium OS's Aura, LibSDL...).

Requirements:
1. Should be backwards-compatible, that is, an application which is unaware of
   the existence of high-res scrolling should still behave normally (instead of,
   for example, scrolling 8 times faster on an 8x resolution mouse).
2. Should support horizontal scroll wheels (like the one on the Logitech MX
   Master).
3. Should handle higher-resolution scroll wheels that may be produced in future
   without requiring additional user-space changes.
4. Should be vendor-agnostic.

Proposed solution
=================

When in high-resolution mode, evdev would report scroll wheel movements at high
resolution on new axes (e.g. REL_WHEEL_HI_RES and REL_HWHEEL_HI_RES). For
backwards compatibility, however, evdev would continue to report events on
REL_WHEEL and REL_HWHEEL, after adjusting for the mouse's scroll resolution.

On the high-resolution axes, movement would be reported as the distance moved by
the user's finger, in 256ths of a millimetre. For a wheel this would be
calculated using the radius of the wheel and the angle through which it has
turned. While it might seem more intuitive to report the angle that the wheel
has rotated, this would require the user-space library to scale the values to
account for the size of the wheel, as otherwise mice with very small wheels
would seem to scroll very fast. (See "Alternatives considered" below for more
discussion of this.)

For example, if the mouse scroll resolution is 8x and the user scrolls 16 mouse
units up (which translates into 8mm of movement), evdev would report a
REL_WHEEL_HI_RES movement of 2048 (8mm * 256) and a REL_WHEEL movement of 2. The
resolution of the REL_WHEEL_HI_RES axis would be reported as 128 (0.5mm). An
input library which supported high-resolution scrolling would ignore REL_WHEEL
and use REL_WHEEL_HI_RES instead, while one that didn't would ignore
REL_WHEEL_HI_RES (since it wouldn't know it existed) and just use REL_WHEEL.

Reporting remainders
--------------------

Of course, the movements aren't always going to be exact multiples of
low-resolution units, in particular when the wheel is in freewheel mode. In the
example above, what should evdev report on REL_WHEEL if the movement is 11, or
15? The mouse that I tested (a Logitech MX Master 2S) reports frequent scroll
events with small magnitudes, meaning that simply rounding the number on each
event would stop any scrolling from happening at all (as each event would be
rounded to 0).

Instead, we can accumulate the remainder across multiple events until it is
greater than one (low-res) notch. For example, we get the following scroll
events in quick succession from an 8x wheel:

Value |  Remainder | Cumulative | REL_WHEEL units reported
------+------------+------------+-------------------------
   19 | 19 % 8 = 3 |          3 | 2
   14 |          6 |  9 - 8 = 1 | 2 (1 from this event, plus 1 from the
      |            |            |    accumulated remainder)
   11 |          3 |          4 | 1

After these events we have an accumulated remainder of 4 left. We should
probably also store the timestamp of the last scroll event, and discard the
accumulated remainder if it was last added to some time ago (maybe 100ms).

Alternatives considered
=======================

Different high-resolution reporting units
-----------------------------------------

Current scroll events (on REL_(H)WHEEL axes) are reported as the number of
"notches" that the wheel moved. The angle between these notches varies by mouse,
but is typically assumed to be 15 degrees unless an hwdb entry [0] specifies
otherwise. High-resolution mice (at least from Logitech) report movements as
fractions of a notch when in high-resolution mode. Given that we will be adding
a new pair of scrolling axes for which backwards compatibility need not be
considered, this is a good opportunity to standardise the unit in which
scrolling is reported.

The most obvious unit to use would be an angular one, representing the angle
through which the wheel has been rotated, and this is indeed how libinput
reports scroll events. However, there is variation in the size of scroll wheels
[1], which would cause the scroll speed to vary by mouse unless this was
accounted for by a similar set of scaling factors in something like hwdb.

Using distance moved instead removes the need for the user-space library to
scale for the wheel size. It does require the device driver to know or guess the
wheel size. For devices which do not expose this in any way (which is all of
them, as far as I know) the driver can either look the size up in a hard-coded
table or assume a sensible default.

Using existing event codes but specifying the resolution
--------------------------------------------------------

libinput already takes into account the angle represented by one notch of the
scroll wheel by reading the MOUSE_WHEEL_CLICK_COUNT or MOUSE_WHEEL_CLICK_ANGLE
properties (or their _HORIZONTAL variants) from udev/hwdb. These are currently
only set for relatively minor adjustments, like for a mouse with 20 degree
clicks instead of the default 15 degree, but we could set
MOUSE_WHEEL_CLICK_COUNT as high as 65535. Ideally, of course, systemd et al
wouldn't have to maintain lists of mice and their scroll resolutions, so we
could report the resolution using the resolution field of the REL_(H)WHEEL event
codes for newer user-space libraries to use.

I don't think we should use this approach, because it fails requirement 1. I had
thought that would be OK if all major input libraries respected the hwdb
properties, but LibSDL, a cross-platform library used by a lot of games
(including Valve’s Source engine [3]) does not. If we changed the resolution
being reported by evdev scrolling in these games would break, and updating
LibSDL would not fix the problem because games generally compile libraries into
the binary.

[0]: https://github.com/systemd/systemd/blob/master/hwdb/70-mouse.hwdb
[1]: For example, the Apple Mighty Mouse has a very small scroll ball.
[2]: Citation: "Porting Source to Linux: Valve’s Lessons Learned", NVIDIA,
retrieved on 2018-07-11 from
https://developer.nvidia.com/sites/default/files/akamai/gamedev/docs/Porting%20Source%20to%20Linux.pdf
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux