Wheel scrolling

libinput provides two events to handle wheel scrolling:

  • LIBINPUT_EVENT_POINTER_AXIS events are sent for regular wheel clicks, usually those representing one detent on the device. These wheel clicks usually require a rotation of 15 or 20 degrees. This event is deprecated as of libinput 1.19.
  • LIBINPUT_EVENT_POINTER_SCROLL_WHEEL events are sent for regular and/or high resolution wheel movements. High-resolution events are often 4 or 8 times more frequent than wheel clicks and require the device to be switched into high-resolution mode (Linux kernel 5.0 and later). Where high-resolution wheels are not provided by the kernel, libinput emulates these events for regular wheel clicks. This event is available since libinput 1.19.

The events are separate for historical reasons. Both events are generated for the same device but are independent event streams. Callers must not assume any relation between the two, i.e. there is no guarantee that an axis event is sent before or after any specific high-resolution event and vice versa. Callers should not handle both events.

Warning

do not handle both LIBINPUT_EVENT_POINTER_AXIS and LIBINPUT_EVENT_POINTER_SCROLL_WHEEL. Always use the latter where possible, otherwise only use the former.

Both events have their own set of APIs to access the data within:

  • LIBINPUT_EVENT_POINTER_AXIS: Deprecated as of libinput 1.19, where possible it is recommended to handle only LIBINPUT_EVENT_POINTER_SCROLL_WHEEL.
    • libinput_event_pointer_get_axis_value() returns the angle of movement in degrees.
    • libinput_event_pointer_get_axis_source() returns the source of the event: wheel, finger or continuous.
    • libinput_event_pointer_get_axis_value_discrete() returns the number of logical wheel clicks.
  • LIBINPUT_EVENT_POINTER_SCROLL_WHEEL available since libinput 1.19.
    • libinput_event_pointer_get_scroll_value_v120() returns a value normalized into the 0..120 range, see below. Any multiple of 120 should be treated as one full wheel click.

Note

Where possible, the libinput_event_pointer_get_axis_value(), libinput_event_pointer_get_axis_source() and libinput_event_pointer_get_axis_value_discrete() API should be avoided.

The v120 Wheel API

The v120 value matches the Windows API for wheel scrolling. Wheel movements are normalized into multiples (or fractions) of 120 with each multiple of 120 representing one detent of movement. The v120 API is the recommended API for callers that do not care about the exact physical motion and is the simplest API to handle high-resolution scrolling.

Most wheels provide 24 detents per 360 degree rotation (click angle of 15), others provide 18 detents per 360 degree rotation (click angle 20). Mice falling outside these two are rare but do exist. Below is a table showing the various values for a single event, depending on the click angle of the wheel:

Click angle Axis value Discrete value v120
15 15 1 120
20 20 1 120

Fast scrolling may trigger cover than one detent per event and thus each event may contain multiples of the value, discrete or v120 value:

Click angle Axis value Discrete value v120
15 30 2 240
20 60 3 360

Scrolling on high-resolution wheels will produce fractions of 120, depending on the resolution of the wheel. The example below shows a mouse with click angle 15 and a resolution of 3 events per wheel click and a mouse with click angle 20 and a resolution of 2 events per wheel click.

Click angle Axis value Discrete value v120
15 5 0 40
20 10 0 60

Event sequences for high-resolution wheel mice

High-resolution scroll wheels provide multiple events for each detent is hit. For those mice, an event sequence covering two detents may look like this:

Event number Type Axis value Discrete value v120
1 WHEEL 5 n/a 40
2 WHEEL 5 n/a 40
3 WHEEL 5 n/a 40
4 AXIS 15 1 120
5 WHEEL 5 n/a 40
6 WHEEL 5 n/a 40
7 AXIS 15 1 120

The above assumes a click angle of 15 for the physical detents. Note how the second set of high-resolution events do not add up to a multiple of 120 before the low-resolution event. A caller must not assume any relation between LIBINPUT_EVENT_POINTER_SCROLL_WHEEL and LIBINPUT_EVENT_POINTER_AXIS.

Fast-scrolling on a high-resolution mouse may trigger multiple fractions per hardware scanout cycle and result in an event sequence like this:

Event number Type Axis value Discrete value v120
1 WHEEL 5 n/a 40
2 WHEEL 10 n/a 80
3 AXIS 15 1 120
4 WHEEL 10 n/a 80
5 WHEEL 10 n/a 80
6 AXIS 15 1 120
7 WHEEL 5 n/a 40

Note how the first low-resolution event is sent at an accumulated 15 degrees, the second at an accumulated 20 degrees. The libinput API does not specify the smallest fraction a wheel supports.

Event sequences for regular wheel mice

LIBINPUT_EVENT_POINTER_SCROLL_WHEEL for low-resolution mice are virtually identical to LIBINPUT_EVENT_POINTER_AXIS events. Note that the discrete value is always 0 for LIBINPUT_EVENT_POINTER_SCROLL_WHEEL.

Event number Type Axis value Discrete value v120
1 AXIS 15 1 120
2 WHEEL 15 n/a 120
3 WHEEL 15 n/a 120
4 AXIS 15 1 120

Note that the order of LIBINPUT_EVENT_POINTER_AXIS vs LIBINPUT_EVENT_POINTER_SCROLL_WHEEL events is not guaranteed, as shown in the example above.