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>
+---------------+---------------------------------+----------------------+
| 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.
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
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);
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;
&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,
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);
.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,
struct {
struct custom_accel_function *fallback;
struct custom_accel_function *motion;
+ struct custom_accel_function *scroll;
} funcs;
};
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;
/* 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);
}
(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,
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;
}
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,
.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,
.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,
.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,
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);
.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,
.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,
.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,
.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,
.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,
.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,
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)
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);
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 */
struct {
struct libinput_config_accel_custom_func *fallback;
struct libinput_config_accel_custom_func *motion;
+ struct libinput_config_accel_custom_func *scroll;
} custom;
};
{
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);
}
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;
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;
* 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,
};
/**
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));
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);
-
- 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);
+ 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_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);
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.
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;