input/mouse: add accel_profile custom

Support libinput LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM to define a custom
mouse pointer acceleration curve. Implements #8488.
This commit is contained in:
EBADBEEF 2025-03-04 11:38:44 -08:00
parent 69466ec651
commit a1e93eedb3
9 changed files with 87 additions and 3 deletions

View file

@ -263,6 +263,7 @@ sway_cmd input_cmd_map_to_region;
sway_cmd input_cmd_middle_emulation;
sway_cmd input_cmd_natural_scroll;
sway_cmd input_cmd_pointer_accel;
sway_cmd input_cmd_pointer_accel_custom;
sway_cmd input_cmd_rotation_angle;
sway_cmd input_cmd_scroll_factor;
sway_cmd input_cmd_repeat_delay;

View file

@ -139,6 +139,12 @@ struct input_config_tool {
enum sway_tablet_tool_mode mode;
};
struct accel_custom {
double step;
size_t npoints;
double points[64]; /* LIBINPUT_ACCEL_NPOINTS_MAX */
};
/**
* options for input devices
*/
@ -158,6 +164,7 @@ struct input_config {
int middle_emulation;
int natural_scroll;
float pointer_accel;
struct accel_custom pointer_accel_custom;
float rotation_angle;
float scroll_factor;
int repeat_delay;

View file

@ -24,6 +24,7 @@ static const struct cmd_handler input_handlers[] = {
{ "middle_emulation", input_cmd_middle_emulation },
{ "natural_scroll", input_cmd_natural_scroll },
{ "pointer_accel", input_cmd_pointer_accel },
{ "pointer_accel_custom", input_cmd_pointer_accel_custom },
{ "repeat_delay", input_cmd_repeat_delay },
{ "repeat_rate", input_cmd_repeat_rate },
{ "rotation_angle", input_cmd_rotation_angle },

View file

@ -18,9 +18,17 @@ struct cmd_results *input_cmd_accel_profile(int argc, char **argv) {
ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
} else if (strcasecmp(argv[0], "flat") == 0) {
ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
} else if (strcasecmp(argv[0], "custom") == 0) {
#if HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM
ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM;
#else
return cmd_results_new(CMD_INVALID,
"Config 'accel_profile custom' not supported (requires libinput >= 1.23.0).");
#endif
} else {
return cmd_results_new(CMD_INVALID,
"Expected 'accel_profile <adaptive|flat>'");
"Expected 'accel_profile <adaptive|flat|custom>'"
);
}
return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -27,3 +27,36 @@ struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) {
return cmd_results_new(CMD_SUCCESS, NULL);
}
#if HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#define ACCEL_CUSTOM_MAX (1 + ARRAY_SIZE(((struct input_config *)0)->pointer_accel_custom.points))
struct cmd_results *input_cmd_pointer_accel_custom(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "pointer_accel_custom", EXPECTED_AT_LEAST, 3))) {
return error;
}
if ((error = checkarg(argc, "pointer_accel_custom", EXPECTED_AT_MOST, ACCEL_CUSTOM_MAX))) {
return error;
}
struct input_config *ic = config->handler_context.input_config;
if (!ic) {
return cmd_results_new(CMD_FAILURE, "No input device defined.");
}
for(int i=0; i<argc; ++i) {
double dbl = parse_double(argv[i]);
if (isnan(dbl) || dbl < 0.0) {
return cmd_results_new(CMD_INVALID,
"Invalid pointer_accel_custom value; expected non-negative double.");
}
if (i == 0) {
ic->pointer_accel_custom.step = dbl;
} else {
ic->pointer_accel_custom.points[i-1] = dbl;
}
}
ic->pointer_accel_custom.npoints = argc - 1;
return cmd_results_new(CMD_SUCCESS, NULL);
}
#endif

View file

@ -170,6 +170,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
memcpy(dst->calibration_matrix.matrix, src->calibration_matrix.matrix,
sizeof(src->calibration_matrix.matrix));
}
if (src->pointer_accel_custom.npoints) {
memcpy(&dst->pointer_accel_custom, &src->pointer_accel_custom, sizeof(src->pointer_accel_custom));
}
for (int i = 0; i < src->tools->length; i++) {
struct input_config_tool *src_tool = src->tools->items[i];
for (int j = 0; j < dst->tools->length; j++) {

View file

@ -229,6 +229,23 @@ static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
return changed;
}
#if HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM
static bool set_pointer_accel_custom(struct libinput_device *dev, struct accel_custom *custom) {
sway_log(SWAY_DEBUG, "pointer_accel_config(npoints %lu, step %f)", custom->npoints, custom->step);
if (custom->npoints == 0) {
return false;
}
struct libinput_config_accel *accel_config =
libinput_config_accel_create(LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
log_status(libinput_config_accel_set_points(accel_config, LIBINPUT_ACCEL_TYPE_MOTION,
custom->step, custom->npoints, custom->points));
log_status(libinput_device_config_accel_apply(dev, accel_config));
libinput_config_accel_destroy(accel_config);
/* there is no way to read back the custom points/step from libinput */
return false;
}
#endif
static bool configure_send_events(struct libinput_device *device,
struct input_config *ic) {
if (ic->mapped_to_output &&
@ -285,6 +302,11 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device
}
if (ic->accel_profile != INT_MIN) {
changed |= set_accel_profile(device, ic->accel_profile);
#if HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM
if (ic->accel_profile == LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM) {
set_pointer_accel_custom(device, &ic->pointer_accel_custom);
}
#endif
}
if (ic->natural_scroll != INT_MIN) {
changed |= set_natural_scroll(device, ic->natural_scroll);

View file

@ -134,7 +134,7 @@ The following commands may only be used in the configuration file.
## LIBINPUT CONFIGURATION
*input* <identifier> accel_profile adaptive|flat
*input* <identifier> accel_profile adaptive|flat|custom
Sets the pointer acceleration profile for the specified input device.
*input* <identifier> calibration_matrix <6 space-separated floating point values>
@ -187,6 +187,14 @@ The following commands may only be used in the configuration file.
*input* <identifier> pointer_accel [<-1|1>]
Changes the pointer acceleration for the specified input device.
*input* <identifier> pointer_accel_custom <step> <point0 point1 ... pointN>
Specifies custom mouse pointer acceleration curve that is used when
accel_profile is set to _custom_. Values are floating point numbers. The
behaviour of the custom acceleration profile is defined by libinput and
described in libinput *doc/user/pointer-acceleration.rst*. For example,
'pointer_accel_custom 1.0 0.0 1.0' means step=1.0 and points=[0.0 1.0], which
is equivalent to the 'flat' profile. Requires libinput >= 1.23.0.
*input* <identifier> rotation_angle <angle>
Sets the rotation angle of the device to the given clockwise angle in
degrees. The angle must be between 0.0 (inclusive) and 360.0 (exclusive).

View file

@ -1194,7 +1194,8 @@ following properties will be included for devices that support them:
: The pointer-acceleration in use
|- accel_profile
: string
: The acceleration profile in use. It can be _none_, _flat_, or _adaptive_
: The acceleration profile in use. It can be _none_, _flat_, _adaptive_, or
_custom_
|- natural_scroll
: string
: Whether natural scrolling is enabled. It can be _enabled_ or _disabled_