mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 06:50:05 +01:00
This adds a third profile to the available profiles to map device-specific speed to an acceleration factor, fully defined by the caller. There has been a consistent call for different acceleration profiles in libinput, but very little specifics in what actually needs to be changed. "faster horses" and whatnot (some notable exceptions in e.g. bug 101139). Attempts to change the actual acceleration function will likely break things for others. This approach opens up the profile itself to a user-specific acceleration curve. A caller can set an acceleration curve by defining a number of points on that curve to map input speed to an output factor. That factor is applied to the input delta. libinput does relatively little besides mapping the deltas to the device-specific speed, querying the curve for that speed and applying that factor. The curve is device-specific, the input speed is in device units/ms. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
226 lines
9.8 KiB
Text
226 lines
9.8 KiB
Text
/**
|
|
@page pointer-acceleration Pointer acceleration
|
|
|
|
libinput uses device-specific pointer acceleration methods, with the default
|
|
being the @ref ptraccel-linear. The methods share common properties, such as
|
|
@ref ptraccel-velocity.
|
|
|
|
This page explains the high-level concepts used in the code. It aims to
|
|
provide an overview for developers and is not necessarily useful for
|
|
users.
|
|
|
|
@section ptraccel-profiles Pointer acceleration profiles
|
|
|
|
The profile decides the general method of pointer acceleration.
|
|
libinput currently supports two profiles: "adaptive" and "flat". The aptive
|
|
profile is the default profile for all devices and takes the current speed
|
|
of the device into account when deciding on acceleration. The flat profile
|
|
is simply a constant factor applied to all device deltas, regardless of the
|
|
speed of motion (see @ref ptraccel-profile-flat). Most of this document
|
|
describes the adaptive pointer acceleration.
|
|
|
|
@section ptraccel-velocity Velocity calculation
|
|
|
|
The device's speed of movement is measured across multiple input events
|
|
through so-called "trackers". Each event prepends a the tracker item, each
|
|
subsequent tracker contains the delta of that item to the current position,
|
|
the timestamp of the event that created it and the cardinal direction of the
|
|
movement at the time. If a device moves into the same direction, the
|
|
velocity is calculated across multiple trackers. For example, if a device
|
|
moves steadily for 10 events to the left, the velocity is calculated across
|
|
all 10 events.
|
|
|
|
Whenever the movement changes direction or significantly changes speed, the
|
|
velocity is calculated from the direction/speed change only. For example, if
|
|
a device moves steadily for 8 events to the left and then 2 events to the
|
|
right, the velocity is only that of the last 2 events.
|
|
|
|
An extra time limit prevents events that are too old to factor into the
|
|
velocity calculation. For example, if a device moves steadily for 5 events
|
|
to the left, then pauses, then moves again for 5 events to the left, only
|
|
the last 5 events are used for velocity calculation.
|
|
|
|
The velocity is then used to calculate the acceleration factor
|
|
|
|
@section ptraccel-factor Acceleration factor
|
|
|
|
The acceleration factor is the final outcome of the pointer acceleration
|
|
calculations. It is a unitless factor that is applied to the current delta,
|
|
a factor of 2 doubles the delta (i.e. speeds up the movement), a factor of
|
|
less than 1 reduces the delta (i.e. slows the movement).
|
|
|
|
Any factor less than 1 requires the user to move the device further to move
|
|
the visible pointer. This is called deceleration and enables high precision
|
|
target selection through subpixel movements. libinput's current maximum
|
|
deceleration factor is 0.3 (i.e. slow down to 30% of the pointer speed).
|
|
|
|
A factor higher than 1 moves the pointer further than the physical device
|
|
moves. This is acceleration and allows a user to cross the screen quickly
|
|
but effectively skips pixels. libinput's current maximum acceleration factor
|
|
is 3.5.
|
|
|
|
@section ptraccel-linear Linear pointer acceleration
|
|
|
|
The linear pointer acceleration method is the default for most pointer
|
|
devices. It provides deceleration at very slow movements, a 1:1 mapping for
|
|
regular movements and a linear increase to the maximum acceleration factor
|
|
for fast movements.
|
|
|
|
Linear pointer acceleration applies to devices with above 1000dpi resolution
|
|
and after @ref motion_normalization is applied.
|
|
|
|
@image html ptraccel-linear.svg "Linear pointer acceleration"
|
|
|
|
The image above shows the linear pointer acceleration settings at various
|
|
speeds. The line for 0.0 is the default acceleration curve, speed settings
|
|
above 0.0 accelerate sooner, faster and to a higher maximum acceleration.
|
|
Speed settings below 0 delay when acceleration kicks in, how soon the
|
|
maximum acceleration is reached and the maximum acceleration factor.
|
|
|
|
Extremely low speed settings provide no acceleration and additionally
|
|
decelerate all movement by a constant factor.
|
|
|
|
@section ptraccel-low-dpi Pointer acceleration for low-dpi devices
|
|
|
|
Low-dpi devices are those with a physical resolution of less than 1000 dots
|
|
per inch (dpi). The pointer acceleration is adjusted to provide roughly the
|
|
same feel for all devices at normal to high speeds. At slow speeds, the
|
|
pointer acceleration works on device-units rather than normalized
|
|
coordinates (see @ref motion_normalization).
|
|
|
|
@image html ptraccel-low-dpi.svg "Pointer acceleration for low-dpi devices"
|
|
|
|
The image above shows the default pointer acceleration curve for a speed of
|
|
0.0 at different DPI settings. A device with low DPI has the acceleration
|
|
applied sooner and with a stronger acceleration factor.
|
|
|
|
@section ptraccel-touchpad Pointer acceleration on touchpads
|
|
|
|
Touchpad pointer acceleration uses the same approach as the @ref
|
|
ptraccel-linear profile, with a constant deceleration factor applied. The
|
|
user expectation of how much a pointer should move in response to finger
|
|
movement is different to that of a mouse device, hence the constant
|
|
deceleration factor.
|
|
|
|
@image html ptraccel-touchpad.svg "Pointer acceleration curve for touchpads"
|
|
|
|
The image above shows the touchpad acceleration profile in comparison to the
|
|
@ref ptraccel-linear. The shape of the curve is identical but vertically squashed.
|
|
|
|
@section ptraccel-trackpoint Pointer acceleration on trackpoints
|
|
|
|
The main difference between trackpoint hardware and mice or touchpads is
|
|
that trackpoint speed is a function of pressure rather than moving speed.
|
|
But trackpoint hardware is quite varied in how it reacts to user pressure
|
|
and unlike other devices it cannot easily be normalized for physical
|
|
properties. Measuring pressure objectively across a variety of hardware is
|
|
nontrivial.
|
|
|
|
libinput's pointer acceleration is a function of the total available
|
|
pressure range on a device. See @ref trackpoint_range for details.
|
|
|
|
libinput relies on some system-wide configured properties, specifically the
|
|
@ref udev_config. The property that influences trackpoint acceleration is
|
|
`LIBINPUT_ATTR_TRACKPOINT_RANGE` which specifies the total delta range for
|
|
the trackpoint. See @ref trackpoint_range for details.
|
|
|
|
Additionally, some trackpoints provide the ability to adjust the sensitivity in
|
|
hardware by modifying a sysfs file on the serio node. The udev property
|
|
`POINTINGSTICK_SENSITIVITY` indicates the desired value, a udev
|
|
builtin is expected to apply this to the device, i.e. libinput does not
|
|
handle this property. Once applied, the sensitivity adjusts the deltas
|
|
coming out of the hardware. When the sensitivity changes, the trackpoint
|
|
range changes and thus the `LIBINPUT_ATTR_TRACKPOINT_RANGE` property
|
|
becomes invalid.
|
|
|
|
As of version 1.9, libinput does not parse the `POINTINGSTICK_CONST_ACCEL` property anymore.
|
|
|
|
@image html ptraccel-trackpoint.svg "Pointer acceleration curves for trackpoints"
|
|
|
|
The image above shows the trackpoint acceleration profile in comparison to the
|
|
@ref ptraccel-linear.
|
|
|
|
The constant acceleration factor, usually applied in
|
|
@ref udev_config, shapes the acceleration profile and is pre-applied before
|
|
any user-specific acceleration adjustments.
|
|
|
|
@section ptraccel-profile-flat The flat pointer acceleration profile
|
|
|
|
In a flat profile, the acceleration factor is constant regardless of the
|
|
velocity of the pointer and each delta (dx, dy) results in an accelerated delta
|
|
(dx * factor, dy * factor). This provides 1:1 movement between the device
|
|
and the pointer on-screen.
|
|
|
|
@section ptraccel-tablet Pointer acceleration on tablets
|
|
|
|
Pointer acceleration for relative motion on tablet devices is a flat
|
|
acceleration, with the speed seeting slowing down or speeding up the pointer
|
|
motion by a constant factor. Tablets do not allow for switchable profiles.
|
|
|
|
@section ptraccel-device-speed Speed-dependent acceleration curve
|
|
|
|
When the @ref LIBINPUT_CONFIG_ACCEL_PROFILE_DEVICE_SPEED_CURVE profile is
|
|
selected, it is the caller's responsibility to load an acceleration profile
|
|
into the device that maps the device's movement into an accelerated
|
|
movement.
|
|
|
|
This profile maps input speed in **device units** to an acceleration
|
|
factor. libinput calculates the device's speed based on the deltas and their
|
|
timestamps and applies the factor provided by the acceleration profile to
|
|
the current delta.
|
|
|
|
@note This profile uses data in device units, an acceleration curve loaded
|
|
by the caller only applies to that device and will not behave the same way
|
|
for other devices.
|
|
|
|
@dot
|
|
digraph
|
|
{
|
|
rankdir="LR";
|
|
node [shape="box";]
|
|
subgraph cluster0 {
|
|
history[shape=record,label="<f0> delta(t-1)|<f1> delta(t-2)|<f2> delta(t-3)| <f3> ..."];
|
|
label = "motion history";
|
|
}
|
|
delta[label="delta"];
|
|
velocity[shape="ellipse"];
|
|
factor[shape="ellipse"];
|
|
accel[label="accelerated delta"];
|
|
curve[label="acceleration curve"];
|
|
|
|
delta->velocity;
|
|
delta->factor;
|
|
factor->accel;
|
|
history->velocity;
|
|
|
|
velocity->curve;
|
|
curve->factor;
|
|
}
|
|
@enddot
|
|
|
|
For example, assume the current delta is (2, 4) which maps to a current
|
|
movement velocity of 10 units per microsecond. libinput looks up the custom
|
|
acceleration function for 10 which may return 3. The accelerated delta thus
|
|
becomes (6, 12).
|
|
|
|
The profile itself is a curve defined by a number of points on the curve
|
|
mapping speed to an acceleration factor. Between each two curve points,
|
|
libinput provides linear interpolation, most acceleration profiles will thus
|
|
only need to provide a handful of curve points. The following illustration
|
|
shows the acceleration curve defined for the points (10, 0.25), (20, 0.4)
|
|
and (35, 3.0).
|
|
|
|
@image html ptraccel-curve-example.svg "Interpolation of the acceleration curve for three defined points"
|
|
|
|
As seen in the picture above: given an acceleration factor f(x) and a curve
|
|
defined by the caller for the points
|
|
a, b, and c where a < b < c:
|
|
- if x <= a, f(x) == f(a)
|
|
- if x >= c, f(x) == f(c)
|
|
- if a < x < b: f(x) == the the linear interpolation value between f(a) and f(b)
|
|
- if b < x < c: f(x) == the the linear interpolation value between f(b) and f(c)
|
|
|
|
The behavior of a a curve is implementation-defined until the caller sets
|
|
curve points.
|
|
|
|
*/
|