Add quirk to control velocity averaging, disable it by default

libinput applies averaging to the velocity of most pointer devices. Averaging
the velocity makes the motion look smooth and may be of benefit to bad input
devices. For good devices, however, it comes at the unfortunate price of
decreased accuaracy.

This change turns velocity averaging off by default (sets ntrackers to 2 instead
of 16) and allows for it to be turned back on via a quirk, for bad devices which
require it.
This commit is contained in:
Kim Lindberger 2018-08-17 15:12:58 +02:00
parent f82eeae299
commit 99334e11bf
No known key found for this signature in database
GPG key ID: 2DED2151F4671A2B
15 changed files with 96 additions and 34 deletions

View file

@ -2660,6 +2660,8 @@ tp_init_accel(struct tp_dispatch *tp)
struct evdev_device *device = tp->device;
int res_x, res_y;
struct motion_filter *filter;
int dpi = device->dpi;
bool use_v_avg = device->use_velocity_averaging;
res_x = tp->device->abs.absinfo_x->resolution;
res_y = tp->device->abs.absinfo_y->resolution;
@ -2677,11 +2679,14 @@ tp_init_accel(struct tp_dispatch *tp)
if (tp->device->model_flags & EVDEV_MODEL_LENOVO_X230 ||
tp->device->model_flags & EVDEV_MODEL_LENOVO_X220_TOUCHPAD_FW81)
filter = create_pointer_accelerator_filter_lenovo_x230(tp->device->dpi);
filter = create_pointer_accelerator_filter_lenovo_x230(dpi, use_v_avg);
else if (libevdev_get_id_bustype(device->evdev) == BUS_BLUETOOTH)
filter = create_pointer_accelerator_filter_touchpad(device->dpi, ms2us(50), ms2us(10));
filter = create_pointer_accelerator_filter_touchpad(dpi,
ms2us(50),
ms2us(10),
use_v_avg);
else
filter = create_pointer_accelerator_filter_touchpad(device->dpi, 0, 0);
filter = create_pointer_accelerator_filter_touchpad(dpi, 0, 0, use_v_avg);
if (!filter)
return false;

View file

@ -956,11 +956,14 @@ evdev_init_accel(struct evdev_device *device,
if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT)
filter = create_pointer_accelerator_filter_flat(device->dpi);
else if (device->tags & EVDEV_TAG_TRACKPOINT)
filter = create_pointer_accelerator_filter_trackpoint(device->trackpoint_multiplier);
filter = create_pointer_accelerator_filter_trackpoint(device->trackpoint_multiplier,
device->use_velocity_averaging);
else if (device->dpi < DEFAULT_MOUSE_DPI)
filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi);
filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi,
device->use_velocity_averaging);
else
filter = create_pointer_accelerator_filter_linear(device->dpi);
filter = create_pointer_accelerator_filter_linear(device->dpi,
device->use_velocity_averaging);
if (!filter)
return false;
@ -1208,6 +1211,29 @@ evdev_get_trackpoint_multiplier(struct evdev_device *device)
return multiplier;
}
static inline bool
evdev_need_velocity_averaging(struct evdev_device *device)
{
struct quirks_context *quirks;
struct quirks *q;
bool use_velocity_averaging = false; /* default off unless we have quirk */
quirks = evdev_libinput_context(device)->quirks;
q = quirks_fetch_for_device(quirks, device->udev_device);
if (q) {
quirks_get_bool(q,
QUIRK_ATTR_USE_VELOCITY_AVERAGING,
&use_velocity_averaging);
quirks_unref(q);
}
if (use_velocity_averaging)
evdev_log_info(device,
"velocity averaging is turned on\n");
return use_velocity_averaging;
}
static inline int
evdev_read_dpi_prop(struct evdev_device *device)
{
@ -1716,6 +1742,8 @@ evdev_configure_device(struct evdev_device *device)
if (udev_tags & EVDEV_UDEV_TAG_TOUCHPAD) {
if (udev_tags & EVDEV_UDEV_TAG_TABLET)
evdev_tag_tablet_touchpad(device);
/* whether velocity should be averaged, false by default */
device->use_velocity_averaging = evdev_need_velocity_averaging(device);
dispatch = evdev_mt_touchpad_create(device);
evdev_log_info(device, "device is a touchpad\n");
return dispatch;
@ -1727,6 +1755,8 @@ evdev_configure_device(struct evdev_device *device)
evdev_tag_trackpoint(device, device->udev_device);
device->dpi = evdev_read_dpi_prop(device);
device->trackpoint_multiplier = evdev_get_trackpoint_multiplier(device);
/* whether velocity should be averaged, false by default */
device->use_velocity_averaging = evdev_need_velocity_averaging(device);
device->seat_caps |= EVDEV_DEVICE_POINTER;

View file

@ -175,6 +175,7 @@ struct evdev_device {
bool is_suspended;
int dpi; /* HW resolution */
double trackpoint_multiplier; /* trackpoint constant multiplier */
bool use_velocity_averaging; /* whether averaging should be applied on velocity calculation */
struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
struct ratelimit nonpointer_rel_limit; /* ratelimit for REL_* events from non-pointer devices */
uint32_t model_flags;

View file

@ -236,14 +236,14 @@ struct motion_filter_interface accelerator_interface_low_dpi = {
};
static struct pointer_accelerator_low_dpi *
create_default_filter(int dpi)
create_default_filter(int dpi, bool use_velocity_averaging)
{
struct pointer_accelerator_low_dpi *filter;
filter = zalloc(sizeof *filter);
filter->last_velocity = 0.0;
trackers_init(&filter->trackers);
trackers_init(&filter->trackers, use_velocity_averaging ? 16 : 2);
filter->threshold = DEFAULT_THRESHOLD;
filter->accel = DEFAULT_ACCELERATION;
@ -254,11 +254,11 @@ create_default_filter(int dpi)
}
struct motion_filter *
create_pointer_accelerator_filter_linear_low_dpi(int dpi)
create_pointer_accelerator_filter_linear_low_dpi(int dpi, bool use_velocity_averaging)
{
struct pointer_accelerator_low_dpi *filter;
filter = create_default_filter(dpi);
filter = create_default_filter(dpi, use_velocity_averaging);
if (!filter)
return NULL;

View file

@ -310,14 +310,14 @@ struct motion_filter_interface accelerator_interface = {
};
static struct pointer_accelerator *
create_default_filter(int dpi)
create_default_filter(int dpi, bool use_velocity_averaging)
{
struct pointer_accelerator *filter;
filter = zalloc(sizeof *filter);
filter->last_velocity = 0.0;
trackers_init(&filter->trackers);
trackers_init(&filter->trackers, use_velocity_averaging ? 16 : 2);
filter->threshold = DEFAULT_THRESHOLD;
filter->accel = DEFAULT_ACCELERATION;
@ -328,11 +328,11 @@ create_default_filter(int dpi)
}
struct motion_filter *
create_pointer_accelerator_filter_linear(int dpi)
create_pointer_accelerator_filter_linear(int dpi, bool use_velocity_averaging)
{
struct pointer_accelerator *filter;
filter = create_default_filter(dpi);
filter = create_default_filter(dpi, use_velocity_averaging);
if (!filter)
return NULL;

View file

@ -71,7 +71,7 @@ struct pointer_trackers {
struct pointer_delta_smoothener *smoothener;
};
void trackers_init(struct pointer_trackers *trackers);
void trackers_init(struct pointer_trackers *trackers, int ntrackers);
void trackers_free(struct pointer_trackers *trackers);
void

View file

@ -331,7 +331,7 @@ struct motion_filter_interface accelerator_interface_x230 = {
* Don't touch this.
*/
struct motion_filter *
create_pointer_accelerator_filter_lenovo_x230(int dpi)
create_pointer_accelerator_filter_lenovo_x230(int dpi, bool use_velocity_averaging)
{
struct pointer_accelerator_x230 *filter;
@ -340,7 +340,7 @@ create_pointer_accelerator_filter_lenovo_x230(int dpi)
filter->profile = touchpad_lenovo_x230_accel_profile;
filter->last_velocity = 0.0;
trackers_init(&filter->trackers);
trackers_init(&filter->trackers, use_velocity_averaging ? 16 : 2);
filter->threshold = X230_THRESHOLD;
filter->accel = X230_ACCELERATION; /* unitless factor */

View file

@ -318,7 +318,8 @@ struct motion_filter_interface accelerator_interface_touchpad = {
struct motion_filter *
create_pointer_accelerator_filter_touchpad(int dpi,
uint64_t event_delta_smooth_threshold,
uint64_t event_delta_smooth_value)
uint64_t event_delta_smooth_value,
bool use_velocity_averaging)
{
struct touchpad_accelerator *filter;
struct pointer_delta_smoothener *smoothener;
@ -326,7 +327,7 @@ create_pointer_accelerator_filter_touchpad(int dpi,
filter = zalloc(sizeof *filter);
filter->last_velocity = 0.0;
trackers_init(&filter->trackers);
trackers_init(&filter->trackers, use_velocity_averaging ? 16 : 2);
filter->threshold = 130;
filter->dpi = dpi;

View file

@ -182,7 +182,7 @@ struct motion_filter_interface accelerator_interface_trackpoint = {
};
struct motion_filter *
create_pointer_accelerator_filter_trackpoint(double multiplier)
create_pointer_accelerator_filter_trackpoint(double multiplier, bool use_velocity_averaging)
{
struct trackpoint_accelerator *filter;
struct pointer_delta_smoothener *smoothener;
@ -207,7 +207,7 @@ create_pointer_accelerator_filter_trackpoint(double multiplier)
filter->multiplier = multiplier;
trackers_init(&filter->trackers);
trackers_init(&filter->trackers, use_velocity_averaging ? 16 : 2);
filter->base.interface = &accelerator_interface_trackpoint;

View file

@ -91,10 +91,8 @@ filter_get_type(struct motion_filter *filter)
}
void
trackers_init(struct pointer_trackers *trackers)
trackers_init(struct pointer_trackers *trackers, int ntrackers)
{
const int ntrackers = 16;
trackers->trackers = zalloc(ntrackers *
sizeof(*trackers->trackers));
trackers->ntrackers = ntrackers;

View file

@ -108,21 +108,22 @@ struct motion_filter *
create_pointer_accelerator_filter_flat(int dpi);
struct motion_filter *
create_pointer_accelerator_filter_linear(int dpi);
create_pointer_accelerator_filter_linear(int dpi, bool use_velocity_averaging);
struct motion_filter *
create_pointer_accelerator_filter_linear_low_dpi(int dpi);
create_pointer_accelerator_filter_linear_low_dpi(int dpi, bool use_velocity_averaging);
struct motion_filter *
create_pointer_accelerator_filter_touchpad(int dpi,
uint64_t event_delta_smooth_threshold,
uint64_t event_delta_smooth_value);
uint64_t event_delta_smooth_value,
bool use_velocity_averaging);
struct motion_filter *
create_pointer_accelerator_filter_lenovo_x230(int dpi);
create_pointer_accelerator_filter_lenovo_x230(int dpi, bool use_velocity_averaging);
struct motion_filter *
create_pointer_accelerator_filter_trackpoint(double multiplier);
create_pointer_accelerator_filter_trackpoint(double multiplier, bool use_velocity_averaging);
struct motion_filter *
create_pointer_accelerator_filter_tablet(int xres, int yres);

View file

@ -267,6 +267,7 @@ quirk_get_name(enum quirk q)
case QUIRK_ATTR_RESOLUTION_HINT: return "AttrResolutionHint";
case QUIRK_ATTR_TRACKPOINT_MULTIPLIER: return "AttrTrackpointMultiplier";
case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD: return "AttrThumbPressureThreshold";
case QUIRK_ATTR_USE_VELOCITY_AVERAGING: return "AttrUseVelocityAveraging";
default:
abort();
}
@ -643,6 +644,7 @@ parse_attr(struct quirks_context *ctx,
struct quirk_dimensions dim;
struct quirk_range range;
unsigned int v;
bool b;
double d;
if (streq(key, quirk_get_name(QUIRK_ATTR_SIZE_HINT))) {
@ -716,6 +718,17 @@ parse_attr(struct quirks_context *ctx,
p->type = PT_DOUBLE;
p->value.d = d;
rc = true;
} else if (streq(key, quirk_get_name(QUIRK_ATTR_USE_VELOCITY_AVERAGING))) {
p->id = QUIRK_ATTR_USE_VELOCITY_AVERAGING;
if (streq(value, "1"))
b = true;
else if (streq(value, "0"))
b = false;
else
goto out;
p->type = PT_BOOL;
p->value.b = b;
rc = true;
} else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD))) {
p->id = QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD;
if (!safe_atou(value, &v))

View file

@ -95,6 +95,7 @@ enum quirk {
QUIRK_ATTR_RESOLUTION_HINT,
QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
QUIRK_ATTR_USE_VELOCITY_AVERAGING,
};
/**

View file

@ -222,6 +222,7 @@ main(int argc, char **argv)
double custom_deltas[1024];
double speed = 0.0;
int dpi = 1000;
bool use_averaging = false;
const char *filter_type = "linear";
accel_profile_func_t profile = NULL;
double tp_multiplier = 1.0;
@ -314,19 +315,25 @@ main(int argc, char **argv)
}
if (streq(filter_type, "linear")) {
filter = create_pointer_accelerator_filter_linear(dpi);
filter = create_pointer_accelerator_filter_linear(dpi,
use_averaging);
profile = pointer_accel_profile_linear;
} else if (streq(filter_type, "low-dpi")) {
filter = create_pointer_accelerator_filter_linear_low_dpi(dpi);
filter = create_pointer_accelerator_filter_linear_low_dpi(dpi,
use_averaging);
profile = pointer_accel_profile_linear_low_dpi;
} else if (streq(filter_type, "touchpad")) {
filter = create_pointer_accelerator_filter_touchpad(dpi, 0, 0);
filter = create_pointer_accelerator_filter_touchpad(dpi,
0, 0,
use_averaging);
profile = touchpad_accel_profile_linear;
} else if (streq(filter_type, "x230")) {
filter = create_pointer_accelerator_filter_lenovo_x230(dpi);
filter = create_pointer_accelerator_filter_lenovo_x230(dpi,
use_averaging);
profile = touchpad_lenovo_x230_accel_profile;
} else if (streq(filter_type, "trackpoint")) {
filter = create_pointer_accelerator_filter_trackpoint(tp_multiplier);
filter = create_pointer_accelerator_filter_trackpoint(tp_multiplier,
use_averaging);
profile = trackpoint_accel_profile;
} else {
fprintf(stderr, "Invalid filter type %s\n", filter_type);

View file

@ -639,6 +639,7 @@ tools_list_device_quirks(struct quirks_context *ctx,
QUIRK_ATTR_RESOLUTION_HINT,
QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
QUIRK_ATTR_USE_VELOCITY_AVERAGING,
};
enum quirk *q;
@ -722,6 +723,10 @@ tools_list_device_quirks(struct quirks_context *ctx,
snprintf(buf, sizeof(buf), "%s=%0.2f\n", name, d);
callback(userdata, buf);
break;
case QUIRK_ATTR_USE_VELOCITY_AVERAGING:
snprintf(buf, sizeof(buf), "%s=1", name);
callback(userdata, buf);
break;
}
}