filter: add scroll movement type to the custom acceleration profile

Adds a dedicated scroll movement type to the custom acceleration profile.
Supported by physical mouse and touchpad.
Other profiles remain the same by using the same unaccelerated filter for the scroll filter.

Signed-off-by: Yinon Burgansky <51504-Yinon@users.noreply.gitlab.freedesktop.org>
This commit is contained in:
Yinon Burgansky 2023-02-18 21:12:13 +02:00
parent 6c88d9a251
commit 93135c2012
25 changed files with 175 additions and 43 deletions

View file

@ -252,6 +252,8 @@ Supported Movement types:
+---------------+---------------------------------+----------------------+
| Motion | Used for pointer motion | All devices |
+---------------+---------------------------------+----------------------+
| Scroll | Used for scroll movement | Mouse, Touchpad |
+---------------+---------------------------------+----------------------+
If a user does not provide the fallback custom acceleration function, a
flat acceleration function is used, i.e. no acceleration.
@ -259,11 +261,12 @@ flat acceleration function is used, i.e. no acceleration.
The fallback acceleration may be used for different types of movements, it is
strongly recommended that this acceleration function is a constant function.
For example, a physical mouse usually has two movement types: pointer
movement and scroll (wheel) movement. As there is no separate movement
type for scroll yet, scroll movement is be accelerated using the Fallback
acceleration function. Pointer movements is accelerated using the Motion
acceleration function. If no Motion acceleration function is set, the
For example, a touchpad has multiple movement types: pointer
movement, scroll movement, zoom movement (pinch), etc. As there is no separate
movement type for zoom yet, zoom movement is accelerated using the Fallback
acceleration function. Pointer movement is accelerated using the Motion
acceleration function, and Scroll movement is accelerated using the Scroll
acceleration function. If no Motion/Scroll acceleration function is set, the
Fallback acceleration function is used.
When using custom acceleration profile, any calls to set the speed have no

View file

@ -113,10 +113,10 @@ post_button_scroll(struct evdev_device *device,
case BUTTONSCROLL_SCROLLING:
{
const struct normalized_coords normalized =
filter_dispatch_constant(device->pointer.filter,
&raw,
device,
time);
filter_dispatch_scroll(device->pointer.filter,
&raw,
device,
time);
evdev_post_scroll(device, time,
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
&normalized);

View file

@ -1176,8 +1176,8 @@ tp_gesture_handle_state_scroll(struct tp_dispatch *tp, uint64_t time)
raw = tp_get_average_touches_delta(tp);
/* scroll is not accelerated */
delta = tp_filter_motion_unaccelerated(tp, &raw, time);
/* scroll is not accelerated by default */
delta = tp_filter_scroll(tp, &raw, time);
if (normalized_is_zero(delta))
return;

View file

@ -93,6 +93,24 @@ tp_filter_motion_unaccelerated(struct tp_dispatch *tp,
&raw, tp, time);
}
struct normalized_coords
tp_filter_scroll(struct tp_dispatch *tp,
const struct device_float_coords *unaccelerated,
uint64_t time)
{
struct device_float_coords raw;
const struct normalized_coords zero = { 0.0, 0.0 };
if (device_float_is_zero(*unaccelerated))
return zero;
/* Convert to device units with x/y in the same resolution */
raw = tp_scale_to_xaxis(tp, *unaccelerated);
return filter_dispatch_scroll(tp->device->pointer.filter,
&raw, tp, time);
}
static inline void
tp_calculate_motion_speed(struct tp_dispatch *tp,
struct tp_touch *t,

View file

@ -607,6 +607,11 @@ tp_filter_motion_unaccelerated(struct tp_dispatch *tp,
const struct device_float_coords *unaccelerated,
uint64_t time);
struct normalized_coords
tp_filter_scroll(struct tp_dispatch *tp,
const struct device_float_coords *unaccelerated,
uint64_t time);
bool
tp_touch_active(const struct tp_dispatch *tp, const struct tp_touch *t);

View file

@ -196,10 +196,10 @@ wheel_flush_scroll(struct fallback_dispatch *dispatch,
.y = dispatch->wheel.lo_res.y * -1,
};
const struct normalized_coords normalized =
filter_dispatch_constant(device->pointer.filter,
&raw,
device,
time);
filter_dispatch_scroll(device->pointer.filter,
&raw,
device,
time);
evdev_post_scroll(device,
time,
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,

View file

@ -201,6 +201,7 @@ struct custom_accelerator {
struct {
struct custom_accel_function *fallback;
struct custom_accel_function *motion;
struct custom_accel_function *scroll;
} funcs;
};
@ -213,6 +214,8 @@ custom_accelerator_get_custom_function(struct custom_accelerator *f,
return f->funcs.fallback;
case LIBINPUT_ACCEL_TYPE_MOTION:
return f->funcs.motion ? f->funcs.motion : f->funcs.fallback;
case LIBINPUT_ACCEL_TYPE_SCROLL:
return f->funcs.scroll ? f->funcs.scroll : f->funcs.fallback;
}
return f->funcs.fallback;
@ -262,6 +265,7 @@ custom_accelerator_destroy(struct motion_filter *filter)
/* destroy all custom movement functions */
custom_accel_function_destroy(f->funcs.fallback);
custom_accel_function_destroy(f->funcs.motion);
custom_accel_function_destroy(f->funcs.scroll);
free(f);
}
@ -284,7 +288,8 @@ custom_accelerator_set_accel_config(struct motion_filter *filter,
(struct custom_accelerator *)filter;
struct custom_accel_function *fallback = NULL,
*motion = NULL;
*motion = NULL,
*scroll = NULL;
if (config->custom.fallback) {
fallback = create_custom_accel_function(config->custom.fallback->step,
@ -302,17 +307,28 @@ custom_accelerator_set_accel_config(struct motion_filter *filter,
goto out;
}
if (config->custom.scroll) {
scroll = create_custom_accel_function(config->custom.scroll->step,
config->custom.scroll->points,
config->custom.scroll->npoints);
if (!scroll)
goto out;
}
custom_accel_function_destroy(f->funcs.fallback);
custom_accel_function_destroy(f->funcs.motion);
custom_accel_function_destroy(f->funcs.scroll);
f->funcs.fallback = fallback;
f->funcs.motion = motion;
f->funcs.scroll = scroll;
return true;
out:
custom_accel_function_destroy(fallback);
custom_accel_function_destroy(motion);
custom_accel_function_destroy(scroll);
return false;
}
@ -365,10 +381,34 @@ custom_accelerator_filter_motion(struct motion_filter *filter,
time);
}
double
custom_accel_profile_scroll(struct motion_filter *filter,
void *data,
double speed_in,
uint64_t time)
{
return custom_accelerator_profile(LIBINPUT_ACCEL_TYPE_SCROLL,
filter,
speed_in);
}
static struct normalized_coords
custom_accelerator_filter_scroll(struct motion_filter *filter,
const struct device_float_coords *unaccelerated,
void *data,
uint64_t time)
{
return custom_accelerator_filter(LIBINPUT_ACCEL_TYPE_SCROLL,
filter,
unaccelerated,
time);
}
struct motion_filter_interface custom_accelerator_interface = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM,
.filter = custom_accelerator_filter_motion,
.filter_constant = custom_accelerator_filter_fallback,
.filter_scroll = custom_accelerator_filter_scroll,
.restart = custom_accelerator_restart,
.destroy = custom_accelerator_destroy,
.set_speed = custom_accelerator_set_speed,

View file

@ -112,6 +112,7 @@ static const struct motion_filter_interface accelerator_interface_flat = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
.filter = accelerator_filter_flat,
.filter_constant = accelerator_filter_noop_flat,
.filter_scroll = accelerator_filter_noop_flat,
.restart = NULL,
.destroy = accelerator_destroy_flat,
.set_speed = accelerator_set_speed_flat,

View file

@ -210,6 +210,7 @@ static const struct motion_filter_interface accelerator_interface_low_dpi = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
.filter = accelerator_filter_low_dpi,
.filter_constant = accelerator_filter_noop,
.filter_scroll = accelerator_filter_noop,
.restart = accelerator_restart,
.destroy = accelerator_destroy,
.set_speed = accelerator_set_speed,

View file

@ -270,6 +270,7 @@ static const struct motion_filter_interface accelerator_interface = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
.filter = accelerator_filter_linear,
.filter_constant = accelerator_filter_noop,
.filter_scroll = accelerator_filter_noop,
.restart = accelerator_restart,
.destroy = accelerator_destroy,
.set_speed = accelerator_set_speed,

View file

@ -38,6 +38,10 @@ struct motion_filter_interface {
struct motion_filter *filter,
const struct device_float_coords *unaccelerated,
void *data, uint64_t time);
struct normalized_coords (*filter_scroll)(
struct motion_filter *filter,
const struct device_float_coords *unaccelerated,
void *data, uint64_t time);
void (*restart)(struct motion_filter *filter,
void *data,
uint64_t time);

View file

@ -147,6 +147,7 @@ static const struct motion_filter_interface accelerator_interface_tablet = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
.filter = tablet_accelerator_filter_flat,
.filter_constant = NULL,
.filter_scroll = NULL,
.restart = NULL,
.destroy = tablet_accelerator_destroy,
.set_speed = tablet_accelerator_set_speed,

View file

@ -110,6 +110,7 @@ static const struct motion_filter_interface accelerator_interface_touchpad_flat
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
.filter = accelerator_filter_touchpad_flat,
.filter_constant = accelerator_filter_noop_touchpad_flat,
.filter_scroll = accelerator_filter_noop_touchpad_flat,
.restart = NULL,
.destroy = accelerator_destroy_touchpad_flat,
.set_speed = accelerator_set_speed_touchpad_flat,

View file

@ -287,6 +287,7 @@ static const struct motion_filter_interface accelerator_interface_x230 = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
.filter = accelerator_filter_x230,
.filter_constant = accelerator_filter_constant_x230,
.filter_scroll = accelerator_filter_constant_x230,
.restart = accelerator_restart_x230,
.destroy = accelerator_destroy_x230,
.set_speed = accelerator_set_speed_x230,

View file

@ -278,6 +278,7 @@ static const struct motion_filter_interface accelerator_interface_touchpad = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
.filter = accelerator_filter_touchpad,
.filter_constant = touchpad_constant_filter,
.filter_scroll = touchpad_constant_filter,
.restart = touchpad_accelerator_restart,
.destroy = touchpad_accelerator_destroy,
.set_speed = touchpad_accelerator_set_speed,

View file

@ -129,6 +129,7 @@ static struct motion_filter_interface accelerator_interface_flat = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
.filter = trackpoint_flat_filter,
.filter_constant = trackpoint_flat_filter_noop,
.filter_scroll = trackpoint_flat_filter_noop,
.restart = NULL,
.destroy = trackpoint_flat_destroy,
.set_speed = trackpoint_flat_set_speed,

View file

@ -174,6 +174,7 @@ static const struct motion_filter_interface accelerator_interface_trackpoint = {
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
.filter = trackpoint_accelerator_filter,
.filter_constant = trackpoint_accelerator_filter_noop,
.filter_scroll = trackpoint_accelerator_filter_noop,
.restart = trackpoint_accelerator_restart,
.destroy = trackpoint_accelerator_destroy,
.set_speed = trackpoint_accelerator_set_speed,

View file

@ -53,6 +53,14 @@ filter_dispatch_constant(struct motion_filter *filter,
return filter->interface->filter_constant(filter, unaccelerated, data, time);
}
struct normalized_coords
filter_dispatch_scroll(struct motion_filter *filter,
const struct device_float_coords *unaccelerated,
void *data, uint64_t time)
{
return filter->interface->filter_scroll(filter, unaccelerated, data, time);
}
void
filter_restart(struct motion_filter *filter,
void *data, uint64_t time)

View file

@ -82,6 +82,28 @@ filter_dispatch_constant(struct motion_filter *filter,
const struct device_float_coords *unaccelerated,
void *data, uint64_t time);
/**
* Apply a scroll filter.
* Depending on the device, and the acceleration profile,
* this filter allows the user to accelerate the scroll movement.
*
* Takes a set of unaccelerated deltas and applies the scroll filter to it.
*
* @param filter The device's motion filter
* @param unaccelerated The unaccelerated delta in the device's dpi
* resolution as specified during filter creation. If a device has uneven
* resolution for x and y, one axis needs to be scaled to match the
* originally provided resolution.
* @param data Custom data
* @param time The time of the delta
*
* @see filter_dispatch
*/
struct normalized_coords
filter_dispatch_scroll(struct motion_filter *filter,
const struct device_float_coords *unaccelerated,
void *data, uint64_t time);
void
filter_restart(struct motion_filter *filter,
void *data, uint64_t time);
@ -180,4 +202,9 @@ custom_accel_profile_motion(struct motion_filter *filter,
void *data,
double speed_in,
uint64_t time);
double
custom_accel_profile_scroll(struct motion_filter *filter,
void *data,
double speed_in,
uint64_t time);
#endif /* FILTER_H */

View file

@ -271,6 +271,7 @@ struct libinput_config_accel {
struct {
struct libinput_config_accel_custom_func *fallback;
struct libinput_config_accel_custom_func *motion;
struct libinput_config_accel_custom_func *scroll;
} custom;
};

View file

@ -4218,6 +4218,7 @@ libinput_config_accel_destroy(struct libinput_config_accel *accel_config)
{
libinput_config_accel_custom_func_destroy(accel_config->custom.fallback);
libinput_config_accel_custom_func_destroy(accel_config->custom.motion);
libinput_config_accel_custom_func_destroy(accel_config->custom.scroll);
free(accel_config);
}
@ -4256,6 +4257,7 @@ libinput_config_accel_set_points(struct libinput_config_accel *config,
switch (accel_type) {
case LIBINPUT_ACCEL_TYPE_FALLBACK:
case LIBINPUT_ACCEL_TYPE_MOTION:
case LIBINPUT_ACCEL_TYPE_SCROLL:
break;
default:
return LIBINPUT_CONFIG_STATUS_INVALID;
@ -4288,6 +4290,10 @@ libinput_config_accel_set_points(struct libinput_config_accel *config,
libinput_config_accel_custom_func_destroy(config->custom.motion);
config->custom.motion = func;
break;
case LIBINPUT_ACCEL_TYPE_SCROLL:
libinput_config_accel_custom_func_destroy(config->custom.scroll);
config->custom.scroll = func;
break;
}
return LIBINPUT_CONFIG_STATUS_SUCCESS;

View file

@ -5364,6 +5364,11 @@ enum libinput_config_accel_type {
* type is always supported.
*/
LIBINPUT_ACCEL_TYPE_MOTION,
/**
* Acceleration type for scroll movement.
* This type is supported by mouse and touchpad.
*/
LIBINPUT_ACCEL_TYPE_SCROLL,
};
/**

View file

@ -2283,22 +2283,24 @@ START_TEST(pointer_accel_config)
enum libinput_config_accel_profile profile;
enum libinput_config_status valid = LIBINPUT_CONFIG_STATUS_SUCCESS,
invalid = LIBINPUT_CONFIG_STATUS_INVALID;
enum libinput_config_accel_type fallback = LIBINPUT_ACCEL_TYPE_FALLBACK,
motion = LIBINPUT_ACCEL_TYPE_MOTION;
enum libinput_config_accel_type accel_types[] = {
LIBINPUT_ACCEL_TYPE_FALLBACK,
LIBINPUT_ACCEL_TYPE_MOTION,
LIBINPUT_ACCEL_TYPE_SCROLL,
};
struct custom_config_test {
enum libinput_config_accel_type accel_type;
double step;
double points[4];
enum libinput_config_status expected_status;
} tests[] = {
{ fallback, 0.5, { 1.0, 2.0, 2.5, 2.6 }, valid },
{ motion, 0.003, { 0.1, 0.3, 0.4, 0.45 }, valid },
{ fallback, 2.7, { 1.0, 3.0, 4.5, 4.5 }, valid },
{ motion, 0, { 1.0, 2.0, 2.5, 2.6 }, invalid },
{ fallback, -1, { 1.0, 2.0, 2.5, 2.6 }, invalid },
{ motion, 1e10, { 1.0, 2.0, 2.5, 2.6 }, invalid },
{ fallback, 1, { 1.0, 2.0, -2.5, 2.6 }, invalid },
{ motion, 1, { 1.0, 2.0, 1e10, 2.6 }, invalid },
{ 0.5, { 1.0, 2.0, 2.5, 2.6 }, valid },
{ 0.003, { 0.1, 0.3, 0.4, 0.45 }, valid },
{ 2.7, { 1.0, 3.0, 4.5, 4.5 }, valid },
{ 0, { 1.0, 2.0, 2.5, 2.6 }, invalid },
{ -1, { 1.0, 2.0, 2.5, 2.6 }, invalid },
{ 1e10, { 1.0, 2.0, 2.5, 2.6 }, invalid },
{ 1, { 1.0, 2.0, -2.5, 2.6 }, invalid },
{ 1, { 1.0, 2.0, 1e10, 2.6 }, invalid },
};
ck_assert(libinput_device_config_accel_is_available(device));
@ -2312,22 +2314,24 @@ START_TEST(pointer_accel_config)
ck_assert_ptr_nonnull(config_custom_changed);
ARRAY_FOR_EACH(tests, t) {
status = libinput_config_accel_set_points(config_custom_changed,
t->accel_type,
t->step,
ARRAY_LENGTH(t->points),
t->points);
ck_assert_int_eq(status, t->expected_status);
ARRAY_FOR_EACH(accel_types, accel_type) {
status = libinput_config_accel_set_points(config_custom_changed,
*accel_type,
t->step,
ARRAY_LENGTH(t->points),
t->points);
ck_assert_int_eq(status, t->expected_status);
status = libinput_device_config_accel_apply(device, config_custom_changed);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
profile = libinput_device_config_accel_get_profile(device);
ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
status = libinput_device_config_accel_apply(device, config_custom_changed);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
profile = libinput_device_config_accel_get_profile(device);
ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
status = libinput_device_config_accel_apply(device, config_custom_default);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
profile = libinput_device_config_accel_get_profile(device);
ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
status = libinput_device_config_accel_apply(device, config_custom_default);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
profile = libinput_device_config_accel_get_profile(device);
ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
}
}
libinput_config_accel_destroy(config_custom_default);

View file

@ -112,7 +112,7 @@ Sets the distance along the x-axis between each point, starting from 0.
Defaults to 1.0.
This only applies to the custom profile.
.TP 8
.B \-\-set\-custom\-type=[fallback|motion]
.B \-\-set\-custom\-type=[fallback|motion|scroll]
Sets the type of the custom acceleration function.
Defaults to fallback.
This only applies to the custom profile.

View file

@ -307,9 +307,11 @@ tools_parse_option(int option,
options->custom_type = LIBINPUT_ACCEL_TYPE_FALLBACK;
else if (streq(optarg, "motion"))
options->custom_type = LIBINPUT_ACCEL_TYPE_MOTION;
else if (streq(optarg, "scroll"))
options->custom_type = LIBINPUT_ACCEL_TYPE_SCROLL;
else {
fprintf(stderr, "Invalid --set-custom-type\n"
"Valid custom types: fallback|motion\n");
"Valid custom types: fallback|motion|scroll\n");
return 1;
}
break;