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.
parent f82eeae2
Pipeline #3487 passed with stages
in 6 minutes and 14 seconds
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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))
......
......@@ -95,6 +95,7 @@ enum quirk {
QUIRK_ATTR_RESOLUTION_HINT,
QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
QUIRK_ATTR_USE_VELOCITY_AVERAGING,
};
/**
......
......@@ -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);
......
......@@ -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;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment