mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-04 17:50:15 +01:00
filter: add a custom low-dpi acceleration
Motion normalization does not work well for devices below the default 1000dpi rate. A 400dpi mouse's minimum movement generates a 2.5 normalized motion, causing it to skip pixels at low speeds even when unaccelerated. Likewise, we don't want 1000dpi mice to be normalized to a 400dpi mouse, it feels sluggish even at higher acceleration speeds. Instead, add a custom acceleration method for lower-dpi mice. At low-speeds, one device unit results in a one-pixel movement. Depending on the DPI factor, the acceleration kicks in earlier and goes to higher acceleration so faster movements with a low-dpi mouse feel approximately the same as the same movement on a higher-dpi mouse. https://bugzilla.redhat.com/show_bug.cgi?id=1231304 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
4df1a9b66e
commit
3928f32281
3 changed files with 68 additions and 8 deletions
17
src/evdev.c
17
src/evdev.c
|
|
@ -1828,6 +1828,19 @@ evdev_configure_mt_device(struct evdev_device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
evdev_init_accel(struct evdev_device *device)
|
||||
{
|
||||
accel_profile_func_t profile;
|
||||
|
||||
if (device->dpi < DEFAULT_MOUSE_DPI)
|
||||
profile = pointer_accel_profile_linear_low_dpi;
|
||||
else
|
||||
profile = pointer_accel_profile_linear;
|
||||
|
||||
return evdev_device_init_pointer_acceleration(device, profile);
|
||||
}
|
||||
|
||||
static int
|
||||
evdev_configure_device(struct evdev_device *device)
|
||||
{
|
||||
|
|
@ -1923,9 +1936,7 @@ evdev_configure_device(struct evdev_device *device)
|
|||
udev_tags & EVDEV_UDEV_TAG_POINTINGSTICK) {
|
||||
if (libevdev_has_event_code(evdev, EV_REL, REL_X) &&
|
||||
libevdev_has_event_code(evdev, EV_REL, REL_Y) &&
|
||||
evdev_device_init_pointer_acceleration(
|
||||
device,
|
||||
pointer_accel_profile_linear) == -1)
|
||||
evdev_init_accel(device) == -1)
|
||||
return -1;
|
||||
|
||||
device->seat_caps |= EVDEV_DEVICE_POINTER;
|
||||
|
|
|
|||
54
src/filter.c
54
src/filter.c
|
|
@ -264,8 +264,16 @@ accelerator_filter(struct motion_filter *filter,
|
|||
double velocity; /* units/ms */
|
||||
double accel_value; /* unitless factor */
|
||||
struct normalized_coords accelerated;
|
||||
struct normalized_coords unnormalized;
|
||||
double dpi_factor = accel->dpi_factor;
|
||||
|
||||
feed_trackers(accel, unaccelerated, time);
|
||||
/* For low-dpi mice, use device units, everything else uses
|
||||
1000dpi normalized */
|
||||
dpi_factor = min(1.0, dpi_factor);
|
||||
unnormalized.x = unaccelerated->x * dpi_factor;
|
||||
unnormalized.y = unaccelerated->y * dpi_factor;
|
||||
|
||||
feed_trackers(accel, &unnormalized, time);
|
||||
velocity = calculate_velocity(accel, time);
|
||||
accel_value = calculate_acceleration(accel,
|
||||
data,
|
||||
|
|
@ -273,10 +281,10 @@ accelerator_filter(struct motion_filter *filter,
|
|||
accel->last_velocity,
|
||||
time);
|
||||
|
||||
accelerated.x = accel_value * unaccelerated->x;
|
||||
accelerated.y = accel_value * unaccelerated->y;
|
||||
accelerated.x = accel_value * unnormalized.x;
|
||||
accelerated.y = accel_value * unnormalized.y;
|
||||
|
||||
accel->last = *unaccelerated;
|
||||
accel->last = unnormalized;
|
||||
|
||||
accel->last_velocity = velocity;
|
||||
|
||||
|
|
@ -377,10 +385,46 @@ create_pointer_accelerator_filter(accel_profile_func_t profile,
|
|||
return &filter->base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom acceleration function for mice < 1000dpi.
|
||||
* At slow motion, a single device unit causes a one-pixel movement.
|
||||
* The threshold/max accel depends on the DPI, the smaller the DPI the
|
||||
* earlier we accelerate and the higher the maximum acceleration is. Result:
|
||||
* at low speeds we get pixel-precision, at high speeds we get approx. the
|
||||
* same movement as a high-dpi mouse.
|
||||
*
|
||||
* Note: data fed to this function is in device units, not normalized.
|
||||
*/
|
||||
double
|
||||
pointer_accel_profile_linear_low_dpi(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in, /* in device units */
|
||||
uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel_filter =
|
||||
(struct pointer_accelerator *)filter;
|
||||
|
||||
double s1, s2;
|
||||
double max_accel = accel_filter->accel; /* unitless factor */
|
||||
const double threshold = accel_filter->threshold; /* units/ms */
|
||||
const double incline = accel_filter->incline;
|
||||
double factor;
|
||||
double dpi_factor = accel_filter->dpi_factor;
|
||||
|
||||
max_accel /= dpi_factor;
|
||||
|
||||
s1 = min(1, 0.3 + speed_in * 10);
|
||||
s2 = 1 + (speed_in - threshold * dpi_factor) * incline;
|
||||
|
||||
factor = min(max_accel, s2 > 1 ? s2 : s1);
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
double
|
||||
pointer_accel_profile_linear(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in,
|
||||
double speed_in, /* 1000-dpi normalized */
|
||||
uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel_filter =
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@ create_pointer_accelerator_filter(accel_profile_func_t filter,
|
|||
*/
|
||||
|
||||
double
|
||||
pointer_accel_profile_linear_low_dpi(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in,
|
||||
uint64_t time);
|
||||
double
|
||||
pointer_accel_profile_linear(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue