mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 06:50:05 +01:00
filter: split the mouse acceleration out into a separate file
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
f02c9b9734
commit
d8e8b74b06
3 changed files with 329 additions and 295 deletions
|
|
@ -153,6 +153,7 @@ src_libfilter = [
|
||||||
'src/filter.c',
|
'src/filter.c',
|
||||||
'src/filter-flat.c',
|
'src/filter-flat.c',
|
||||||
'src/filter-low-dpi.c',
|
'src/filter-low-dpi.c',
|
||||||
|
'src/filter-mouse.c',
|
||||||
'src/filter-touchpad.c',
|
'src/filter-touchpad.c',
|
||||||
'src/filter-touchpad-x230.c',
|
'src/filter-touchpad-x230.c',
|
||||||
'src/filter-tablet.c',
|
'src/filter-tablet.c',
|
||||||
|
|
|
||||||
326
src/filter-mouse.c
Normal file
326
src/filter-mouse.c
Normal file
|
|
@ -0,0 +1,326 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2006-2009 Simon Thum
|
||||||
|
* Copyright © 2012 Jonas Ådahl
|
||||||
|
* Copyright © 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "filter.h"
|
||||||
|
#include "libinput-util.h"
|
||||||
|
#include "filter-private.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default parameters for pointer acceleration profiles.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DEFAULT_THRESHOLD v_ms2us(0.4) /* in units/us */
|
||||||
|
#define MINIMUM_THRESHOLD v_ms2us(0.2) /* in units/us */
|
||||||
|
#define DEFAULT_ACCELERATION 2.0 /* unitless factor */
|
||||||
|
#define DEFAULT_INCLINE 1.1 /* unitless factor */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the acceleration factor for the given delta with the timestamp.
|
||||||
|
*
|
||||||
|
* @param accel The acceleration filter
|
||||||
|
* @param unaccelerated The raw delta in the device's dpi
|
||||||
|
* @param data Caller-specific data
|
||||||
|
* @param time Current time in µs
|
||||||
|
*
|
||||||
|
* @return A unitless acceleration factor, to be applied to the delta
|
||||||
|
*/
|
||||||
|
static inline double
|
||||||
|
calculate_acceleration_factor(struct pointer_accelerator *accel,
|
||||||
|
const struct device_float_coords *unaccelerated,
|
||||||
|
void *data,
|
||||||
|
uint64_t time)
|
||||||
|
{
|
||||||
|
double velocity; /* units/us in device-native dpi*/
|
||||||
|
double accel_factor;
|
||||||
|
|
||||||
|
feed_trackers(&accel->trackers, unaccelerated, time);
|
||||||
|
velocity = calculate_velocity(&accel->trackers, time);
|
||||||
|
accel_factor = calculate_acceleration_simpsons(&accel->base,
|
||||||
|
accel->profile,
|
||||||
|
data,
|
||||||
|
velocity,
|
||||||
|
accel->last_velocity,
|
||||||
|
time);
|
||||||
|
accel->last_velocity = velocity;
|
||||||
|
|
||||||
|
return accel_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic filter that calculates the acceleration factor and applies it to
|
||||||
|
* the coordinates.
|
||||||
|
*
|
||||||
|
* @param filter The acceleration filter
|
||||||
|
* @param unaccelerated The raw delta in the device's dpi
|
||||||
|
* @param data Caller-specific data
|
||||||
|
* @param time Current time in µs
|
||||||
|
*
|
||||||
|
* @return An accelerated tuple of coordinates representing accelerated
|
||||||
|
* motion, still in device units.
|
||||||
|
*/
|
||||||
|
static struct device_float_coords
|
||||||
|
accelerator_filter_generic(struct motion_filter *filter,
|
||||||
|
const struct device_float_coords *unaccelerated,
|
||||||
|
void *data, uint64_t time)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *accel =
|
||||||
|
(struct pointer_accelerator *) filter;
|
||||||
|
double accel_value; /* unitless factor */
|
||||||
|
struct device_float_coords accelerated;
|
||||||
|
|
||||||
|
accel_value = calculate_acceleration_factor(accel,
|
||||||
|
unaccelerated,
|
||||||
|
data,
|
||||||
|
time);
|
||||||
|
|
||||||
|
accelerated.x = accel_value * unaccelerated->x;
|
||||||
|
accelerated.y = accel_value * unaccelerated->y;
|
||||||
|
|
||||||
|
return accelerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct normalized_coords
|
||||||
|
accelerator_filter_pre_normalized(struct motion_filter *filter,
|
||||||
|
const struct device_float_coords *unaccelerated,
|
||||||
|
void *data, uint64_t time)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *accel =
|
||||||
|
(struct pointer_accelerator *) filter;
|
||||||
|
struct normalized_coords normalized;
|
||||||
|
struct device_float_coords converted, accelerated;
|
||||||
|
|
||||||
|
/* Accelerate for normalized units and return normalized units.
|
||||||
|
API requires device_floats, so we just copy the bits around */
|
||||||
|
normalized = normalize_for_dpi(unaccelerated, accel->dpi);
|
||||||
|
converted.x = normalized.x;
|
||||||
|
converted.y = normalized.y;
|
||||||
|
|
||||||
|
accelerated = accelerator_filter_generic(filter,
|
||||||
|
&converted,
|
||||||
|
data,
|
||||||
|
time);
|
||||||
|
normalized.x = accelerated.x;
|
||||||
|
normalized.y = accelerated.y;
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic filter that does nothing beyond converting from the device's
|
||||||
|
* native dpi into normalized coordinates.
|
||||||
|
*
|
||||||
|
* @param filter The acceleration filter
|
||||||
|
* @param unaccelerated The raw delta in the device's dpi
|
||||||
|
* @param data Caller-specific data
|
||||||
|
* @param time Current time in µs
|
||||||
|
*
|
||||||
|
* @return An accelerated tuple of coordinates representing normalized
|
||||||
|
* motion
|
||||||
|
*/
|
||||||
|
static struct normalized_coords
|
||||||
|
accelerator_filter_noop(struct motion_filter *filter,
|
||||||
|
const struct device_float_coords *unaccelerated,
|
||||||
|
void *data, uint64_t time)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *accel =
|
||||||
|
(struct pointer_accelerator *) filter;
|
||||||
|
|
||||||
|
return normalize_for_dpi(unaccelerated, accel->dpi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
accelerator_restart(struct motion_filter *filter,
|
||||||
|
void *data,
|
||||||
|
uint64_t time)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *accel =
|
||||||
|
(struct pointer_accelerator *) filter;
|
||||||
|
|
||||||
|
reset_trackers(&accel->trackers, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
accelerator_destroy(struct motion_filter *filter)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *accel =
|
||||||
|
(struct pointer_accelerator *) filter;
|
||||||
|
|
||||||
|
free_trackers(&accel->trackers);
|
||||||
|
free(accel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
accelerator_set_speed(struct motion_filter *filter,
|
||||||
|
double speed_adjustment)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *accel_filter =
|
||||||
|
(struct pointer_accelerator *)filter;
|
||||||
|
|
||||||
|
assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
|
||||||
|
|
||||||
|
/* Note: the numbers below are nothing but trial-and-error magic,
|
||||||
|
don't read more into them other than "they mostly worked ok" */
|
||||||
|
|
||||||
|
/* delay when accel kicks in */
|
||||||
|
accel_filter->threshold = DEFAULT_THRESHOLD -
|
||||||
|
v_ms2us(0.25) * speed_adjustment;
|
||||||
|
if (accel_filter->threshold < MINIMUM_THRESHOLD)
|
||||||
|
accel_filter->threshold = MINIMUM_THRESHOLD;
|
||||||
|
|
||||||
|
/* adjust max accel factor */
|
||||||
|
accel_filter->accel = DEFAULT_ACCELERATION + speed_adjustment * 1.5;
|
||||||
|
|
||||||
|
/* higher speed -> faster to reach max */
|
||||||
|
accel_filter->incline = DEFAULT_INCLINE + speed_adjustment * 0.75;
|
||||||
|
|
||||||
|
filter->speed_adjustment = speed_adjustment;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
pointer_accel_profile_linear(struct motion_filter *filter,
|
||||||
|
void *data,
|
||||||
|
double speed_in, /* in device units (units/µs) */
|
||||||
|
uint64_t time)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *accel_filter =
|
||||||
|
(struct pointer_accelerator *)filter;
|
||||||
|
const double max_accel = accel_filter->accel; /* unitless factor */
|
||||||
|
const double threshold = accel_filter->threshold; /* units/us */
|
||||||
|
const double incline = accel_filter->incline;
|
||||||
|
double factor; /* unitless */
|
||||||
|
|
||||||
|
/* Normalize to 1000dpi, because the rest below relies on that */
|
||||||
|
speed_in = speed_in * DEFAULT_MOUSE_DPI/accel_filter->dpi;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Our acceleration function calculates a factor to accelerate input
|
||||||
|
deltas with. The function is a double incline with a plateau,
|
||||||
|
with a rough shape like this:
|
||||||
|
|
||||||
|
accel
|
||||||
|
factor
|
||||||
|
^
|
||||||
|
| /
|
||||||
|
| _____/
|
||||||
|
| /
|
||||||
|
|/
|
||||||
|
+-------------> speed in
|
||||||
|
|
||||||
|
The two inclines are linear functions in the form
|
||||||
|
y = ax + b
|
||||||
|
where y is speed_out
|
||||||
|
x is speed_in
|
||||||
|
a is the incline of acceleration
|
||||||
|
b is minimum acceleration factor
|
||||||
|
|
||||||
|
for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
|
||||||
|
speed.
|
||||||
|
hence 1 = a * 0.07 + 0.3
|
||||||
|
0.7 = a * 0.07 => a := 10
|
||||||
|
deceleration function is thus:
|
||||||
|
y = 10x + 0.3
|
||||||
|
|
||||||
|
Note:
|
||||||
|
* 0.07u/ms as threshold is a result of trial-and-error and
|
||||||
|
has no other intrinsic meaning.
|
||||||
|
* 0.3 is chosen simply because it is above the Nyquist frequency
|
||||||
|
for subpixel motion within a pixel.
|
||||||
|
*/
|
||||||
|
if (v_us2ms(speed_in) < 0.07) {
|
||||||
|
factor = 10 * v_us2ms(speed_in) + 0.3;
|
||||||
|
/* up to the threshold, we keep factor 1, i.e. 1:1 movement */
|
||||||
|
} else if (speed_in < threshold) {
|
||||||
|
factor = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Acceleration function above the threshold:
|
||||||
|
y = ax' + b
|
||||||
|
where T is threshold
|
||||||
|
x is speed_in
|
||||||
|
x' is speed
|
||||||
|
and
|
||||||
|
y(T) == 1
|
||||||
|
hence 1 = ax' + 1
|
||||||
|
=> x' := (x - T)
|
||||||
|
*/
|
||||||
|
factor = incline * v_us2ms(speed_in - threshold) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cap at the maximum acceleration factor */
|
||||||
|
factor = min(max_accel, factor);
|
||||||
|
|
||||||
|
return factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct motion_filter_interface accelerator_interface = {
|
||||||
|
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||||
|
.filter = accelerator_filter_pre_normalized,
|
||||||
|
.filter_constant = accelerator_filter_noop,
|
||||||
|
.restart = accelerator_restart,
|
||||||
|
.destroy = accelerator_destroy,
|
||||||
|
.set_speed = accelerator_set_speed,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pointer_accelerator *
|
||||||
|
create_default_filter(int dpi)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *filter;
|
||||||
|
|
||||||
|
filter = zalloc(sizeof *filter);
|
||||||
|
filter->last_velocity = 0.0;
|
||||||
|
|
||||||
|
init_trackers(&filter->trackers);
|
||||||
|
|
||||||
|
filter->threshold = DEFAULT_THRESHOLD;
|
||||||
|
filter->accel = DEFAULT_ACCELERATION;
|
||||||
|
filter->incline = DEFAULT_INCLINE;
|
||||||
|
filter->dpi = dpi;
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct motion_filter *
|
||||||
|
create_pointer_accelerator_filter_linear(int dpi)
|
||||||
|
{
|
||||||
|
struct pointer_accelerator *filter;
|
||||||
|
|
||||||
|
filter = create_default_filter(dpi);
|
||||||
|
if (!filter)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
filter->base.interface = &accelerator_interface;
|
||||||
|
filter->profile = pointer_accel_profile_linear;
|
||||||
|
|
||||||
|
return &filter->base;
|
||||||
|
}
|
||||||
297
src/filter.c
297
src/filter.c
|
|
@ -36,6 +36,8 @@
|
||||||
#include "libinput-util.h"
|
#include "libinput-util.h"
|
||||||
#include "filter-private.h"
|
#include "filter-private.h"
|
||||||
|
|
||||||
|
#define MOTION_TIMEOUT ms2us(1000)
|
||||||
|
|
||||||
struct normalized_coords
|
struct normalized_coords
|
||||||
filter_dispatch(struct motion_filter *filter,
|
filter_dispatch(struct motion_filter *filter,
|
||||||
const struct device_float_coords *unaccelerated,
|
const struct device_float_coords *unaccelerated,
|
||||||
|
|
@ -88,21 +90,6 @@ filter_get_type(struct motion_filter *filter)
|
||||||
return filter->interface->type;
|
return filter->interface->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Default parameters for pointer acceleration profiles.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DEFAULT_THRESHOLD v_ms2us(0.4) /* in units/us */
|
|
||||||
#define MINIMUM_THRESHOLD v_ms2us(0.2) /* in units/us */
|
|
||||||
#define DEFAULT_ACCELERATION 2.0 /* unitless factor */
|
|
||||||
#define DEFAULT_INCLINE 1.1 /* unitless factor */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pointer acceleration filter constants
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MOTION_TIMEOUT ms2us(1000)
|
|
||||||
|
|
||||||
void
|
void
|
||||||
init_trackers(struct pointer_trackers *trackers)
|
init_trackers(struct pointer_trackers *trackers)
|
||||||
{
|
{
|
||||||
|
|
@ -310,283 +297,3 @@ calculate_acceleration_simpsons(struct motion_filter *filter,
|
||||||
|
|
||||||
return factor; /* unitless factor */
|
return factor; /* unitless factor */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the acceleration factor for the given delta with the timestamp.
|
|
||||||
*
|
|
||||||
* @param accel The acceleration filter
|
|
||||||
* @param unaccelerated The raw delta in the device's dpi
|
|
||||||
* @param data Caller-specific data
|
|
||||||
* @param time Current time in µs
|
|
||||||
*
|
|
||||||
* @return A unitless acceleration factor, to be applied to the delta
|
|
||||||
*/
|
|
||||||
static inline double
|
|
||||||
calculate_acceleration_factor(struct pointer_accelerator *accel,
|
|
||||||
const struct device_float_coords *unaccelerated,
|
|
||||||
void *data,
|
|
||||||
uint64_t time)
|
|
||||||
{
|
|
||||||
double velocity; /* units/us in device-native dpi*/
|
|
||||||
double accel_factor;
|
|
||||||
|
|
||||||
feed_trackers(&accel->trackers, unaccelerated, time);
|
|
||||||
velocity = calculate_velocity(&accel->trackers, time);
|
|
||||||
accel_factor = calculate_acceleration_simpsons(&accel->base,
|
|
||||||
accel->profile,
|
|
||||||
data,
|
|
||||||
velocity,
|
|
||||||
accel->last_velocity,
|
|
||||||
time);
|
|
||||||
accel->last_velocity = velocity;
|
|
||||||
|
|
||||||
return accel_factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic filter that calculates the acceleration factor and applies it to
|
|
||||||
* the coordinates.
|
|
||||||
*
|
|
||||||
* @param filter The acceleration filter
|
|
||||||
* @param unaccelerated The raw delta in the device's dpi
|
|
||||||
* @param data Caller-specific data
|
|
||||||
* @param time Current time in µs
|
|
||||||
*
|
|
||||||
* @return An accelerated tuple of coordinates representing accelerated
|
|
||||||
* motion, still in device units.
|
|
||||||
*/
|
|
||||||
static struct device_float_coords
|
|
||||||
accelerator_filter_generic(struct motion_filter *filter,
|
|
||||||
const struct device_float_coords *unaccelerated,
|
|
||||||
void *data, uint64_t time)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *accel =
|
|
||||||
(struct pointer_accelerator *) filter;
|
|
||||||
double accel_value; /* unitless factor */
|
|
||||||
struct device_float_coords accelerated;
|
|
||||||
|
|
||||||
accel_value = calculate_acceleration_factor(accel,
|
|
||||||
unaccelerated,
|
|
||||||
data,
|
|
||||||
time);
|
|
||||||
|
|
||||||
accelerated.x = accel_value * unaccelerated->x;
|
|
||||||
accelerated.y = accel_value * unaccelerated->y;
|
|
||||||
|
|
||||||
return accelerated;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct normalized_coords
|
|
||||||
accelerator_filter_pre_normalized(struct motion_filter *filter,
|
|
||||||
const struct device_float_coords *unaccelerated,
|
|
||||||
void *data, uint64_t time)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *accel =
|
|
||||||
(struct pointer_accelerator *) filter;
|
|
||||||
struct normalized_coords normalized;
|
|
||||||
struct device_float_coords converted, accelerated;
|
|
||||||
|
|
||||||
/* Accelerate for normalized units and return normalized units.
|
|
||||||
API requires device_floats, so we just copy the bits around */
|
|
||||||
normalized = normalize_for_dpi(unaccelerated, accel->dpi);
|
|
||||||
converted.x = normalized.x;
|
|
||||||
converted.y = normalized.y;
|
|
||||||
|
|
||||||
accelerated = accelerator_filter_generic(filter,
|
|
||||||
&converted,
|
|
||||||
data,
|
|
||||||
time);
|
|
||||||
normalized.x = accelerated.x;
|
|
||||||
normalized.y = accelerated.y;
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic filter that does nothing beyond converting from the device's
|
|
||||||
* native dpi into normalized coordinates.
|
|
||||||
*
|
|
||||||
* @param filter The acceleration filter
|
|
||||||
* @param unaccelerated The raw delta in the device's dpi
|
|
||||||
* @param data Caller-specific data
|
|
||||||
* @param time Current time in µs
|
|
||||||
*
|
|
||||||
* @return An accelerated tuple of coordinates representing normalized
|
|
||||||
* motion
|
|
||||||
*/
|
|
||||||
static struct normalized_coords
|
|
||||||
accelerator_filter_noop(struct motion_filter *filter,
|
|
||||||
const struct device_float_coords *unaccelerated,
|
|
||||||
void *data, uint64_t time)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *accel =
|
|
||||||
(struct pointer_accelerator *) filter;
|
|
||||||
|
|
||||||
return normalize_for_dpi(unaccelerated, accel->dpi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
accelerator_restart(struct motion_filter *filter,
|
|
||||||
void *data,
|
|
||||||
uint64_t time)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *accel =
|
|
||||||
(struct pointer_accelerator *) filter;
|
|
||||||
|
|
||||||
reset_trackers(&accel->trackers, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
accelerator_destroy(struct motion_filter *filter)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *accel =
|
|
||||||
(struct pointer_accelerator *) filter;
|
|
||||||
|
|
||||||
free_trackers(&accel->trackers);
|
|
||||||
free(accel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
accelerator_set_speed(struct motion_filter *filter,
|
|
||||||
double speed_adjustment)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *accel_filter =
|
|
||||||
(struct pointer_accelerator *)filter;
|
|
||||||
|
|
||||||
assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
|
|
||||||
|
|
||||||
/* Note: the numbers below are nothing but trial-and-error magic,
|
|
||||||
don't read more into them other than "they mostly worked ok" */
|
|
||||||
|
|
||||||
/* delay when accel kicks in */
|
|
||||||
accel_filter->threshold = DEFAULT_THRESHOLD -
|
|
||||||
v_ms2us(0.25) * speed_adjustment;
|
|
||||||
if (accel_filter->threshold < MINIMUM_THRESHOLD)
|
|
||||||
accel_filter->threshold = MINIMUM_THRESHOLD;
|
|
||||||
|
|
||||||
/* adjust max accel factor */
|
|
||||||
accel_filter->accel = DEFAULT_ACCELERATION + speed_adjustment * 1.5;
|
|
||||||
|
|
||||||
/* higher speed -> faster to reach max */
|
|
||||||
accel_filter->incline = DEFAULT_INCLINE + speed_adjustment * 0.75;
|
|
||||||
|
|
||||||
filter->speed_adjustment = speed_adjustment;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
pointer_accel_profile_linear(struct motion_filter *filter,
|
|
||||||
void *data,
|
|
||||||
double speed_in, /* in device units (units/µs) */
|
|
||||||
uint64_t time)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *accel_filter =
|
|
||||||
(struct pointer_accelerator *)filter;
|
|
||||||
const double max_accel = accel_filter->accel; /* unitless factor */
|
|
||||||
const double threshold = accel_filter->threshold; /* units/us */
|
|
||||||
const double incline = accel_filter->incline;
|
|
||||||
double factor; /* unitless */
|
|
||||||
|
|
||||||
/* Normalize to 1000dpi, because the rest below relies on that */
|
|
||||||
speed_in = speed_in * DEFAULT_MOUSE_DPI/accel_filter->dpi;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Our acceleration function calculates a factor to accelerate input
|
|
||||||
deltas with. The function is a double incline with a plateau,
|
|
||||||
with a rough shape like this:
|
|
||||||
|
|
||||||
accel
|
|
||||||
factor
|
|
||||||
^
|
|
||||||
| /
|
|
||||||
| _____/
|
|
||||||
| /
|
|
||||||
|/
|
|
||||||
+-------------> speed in
|
|
||||||
|
|
||||||
The two inclines are linear functions in the form
|
|
||||||
y = ax + b
|
|
||||||
where y is speed_out
|
|
||||||
x is speed_in
|
|
||||||
a is the incline of acceleration
|
|
||||||
b is minimum acceleration factor
|
|
||||||
|
|
||||||
for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
|
|
||||||
speed.
|
|
||||||
hence 1 = a * 0.07 + 0.3
|
|
||||||
0.7 = a * 0.07 => a := 10
|
|
||||||
deceleration function is thus:
|
|
||||||
y = 10x + 0.3
|
|
||||||
|
|
||||||
Note:
|
|
||||||
* 0.07u/ms as threshold is a result of trial-and-error and
|
|
||||||
has no other intrinsic meaning.
|
|
||||||
* 0.3 is chosen simply because it is above the Nyquist frequency
|
|
||||||
for subpixel motion within a pixel.
|
|
||||||
*/
|
|
||||||
if (v_us2ms(speed_in) < 0.07) {
|
|
||||||
factor = 10 * v_us2ms(speed_in) + 0.3;
|
|
||||||
/* up to the threshold, we keep factor 1, i.e. 1:1 movement */
|
|
||||||
} else if (speed_in < threshold) {
|
|
||||||
factor = 1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* Acceleration function above the threshold:
|
|
||||||
y = ax' + b
|
|
||||||
where T is threshold
|
|
||||||
x is speed_in
|
|
||||||
x' is speed
|
|
||||||
and
|
|
||||||
y(T) == 1
|
|
||||||
hence 1 = ax' + 1
|
|
||||||
=> x' := (x - T)
|
|
||||||
*/
|
|
||||||
factor = incline * v_us2ms(speed_in - threshold) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cap at the maximum acceleration factor */
|
|
||||||
factor = min(max_accel, factor);
|
|
||||||
|
|
||||||
return factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct motion_filter_interface accelerator_interface = {
|
|
||||||
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
|
||||||
.filter = accelerator_filter_pre_normalized,
|
|
||||||
.filter_constant = accelerator_filter_noop,
|
|
||||||
.restart = accelerator_restart,
|
|
||||||
.destroy = accelerator_destroy,
|
|
||||||
.set_speed = accelerator_set_speed,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct pointer_accelerator *
|
|
||||||
create_default_filter(int dpi)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *filter;
|
|
||||||
|
|
||||||
filter = zalloc(sizeof *filter);
|
|
||||||
filter->last_velocity = 0.0;
|
|
||||||
|
|
||||||
init_trackers(&filter->trackers);
|
|
||||||
|
|
||||||
filter->threshold = DEFAULT_THRESHOLD;
|
|
||||||
filter->accel = DEFAULT_ACCELERATION;
|
|
||||||
filter->incline = DEFAULT_INCLINE;
|
|
||||||
filter->dpi = dpi;
|
|
||||||
|
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct motion_filter *
|
|
||||||
create_pointer_accelerator_filter_linear(int dpi)
|
|
||||||
{
|
|
||||||
struct pointer_accelerator *filter;
|
|
||||||
|
|
||||||
filter = create_default_filter(dpi);
|
|
||||||
if (!filter)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
filter->base.interface = &accelerator_interface;
|
|
||||||
filter->profile = pointer_accel_profile_linear;
|
|
||||||
|
|
||||||
return &filter->base;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue