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_middle_emulation;
sway_cmd input_cmd_natural_scroll; sway_cmd input_cmd_natural_scroll;
sway_cmd input_cmd_pointer_accel; sway_cmd input_cmd_pointer_accel;
sway_cmd input_cmd_pointer_accel_custom;
sway_cmd input_cmd_rotation_angle; sway_cmd input_cmd_rotation_angle;
sway_cmd input_cmd_scroll_factor; sway_cmd input_cmd_scroll_factor;
sway_cmd input_cmd_repeat_delay; sway_cmd input_cmd_repeat_delay;

View file

@ -139,6 +139,12 @@ struct input_config_tool {
enum sway_tablet_tool_mode mode; 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 * options for input devices
*/ */
@ -158,6 +164,7 @@ struct input_config {
int middle_emulation; int middle_emulation;
int natural_scroll; int natural_scroll;
float pointer_accel; float pointer_accel;
struct accel_custom pointer_accel_custom;
float rotation_angle; float rotation_angle;
float scroll_factor; float scroll_factor;
int repeat_delay; int repeat_delay;

View file

@ -24,6 +24,7 @@ static const struct cmd_handler input_handlers[] = {
{ "middle_emulation", input_cmd_middle_emulation }, { "middle_emulation", input_cmd_middle_emulation },
{ "natural_scroll", input_cmd_natural_scroll }, { "natural_scroll", input_cmd_natural_scroll },
{ "pointer_accel", input_cmd_pointer_accel }, { "pointer_accel", input_cmd_pointer_accel },
{ "pointer_accel_custom", input_cmd_pointer_accel_custom },
{ "repeat_delay", input_cmd_repeat_delay }, { "repeat_delay", input_cmd_repeat_delay },
{ "repeat_rate", input_cmd_repeat_rate }, { "repeat_rate", input_cmd_repeat_rate },
{ "rotation_angle", input_cmd_rotation_angle }, { "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; ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
} else if (strcasecmp(argv[0], "flat") == 0) { } else if (strcasecmp(argv[0], "flat") == 0) {
ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; 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 { } else {
return cmd_results_new(CMD_INVALID, return cmd_results_new(CMD_INVALID,
"Expected 'accel_profile <adaptive|flat>'"); "Expected 'accel_profile <adaptive|flat|custom>'"
);
} }
return cmd_results_new(CMD_SUCCESS, NULL); 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); 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, memcpy(dst->calibration_matrix.matrix, src->calibration_matrix.matrix,
sizeof(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++) { for (int i = 0; i < src->tools->length; i++) {
struct input_config_tool *src_tool = src->tools->items[i]; struct input_config_tool *src_tool = src->tools->items[i];
for (int j = 0; j < dst->tools->length; j++) { 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; 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, static bool configure_send_events(struct libinput_device *device,
struct input_config *ic) { struct input_config *ic) {
if (ic->mapped_to_output && 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) { if (ic->accel_profile != INT_MIN) {
changed |= set_accel_profile(device, ic->accel_profile); 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) { if (ic->natural_scroll != INT_MIN) {
changed |= set_natural_scroll(device, ic->natural_scroll); 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 ## 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. Sets the pointer acceleration profile for the specified input device.
*input* <identifier> calibration_matrix <6 space-separated floating point values> *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>] *input* <identifier> pointer_accel [<-1|1>]
Changes the pointer acceleration for the specified input device. 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> *input* <identifier> rotation_angle <angle>
Sets the rotation angle of the device to the given clockwise angle in 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). 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 : The pointer-acceleration in use
|- accel_profile |- accel_profile
: string : 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 |- natural_scroll
: string : string
: Whether natural scrolling is enabled. It can be _enabled_ or _disabled_ : Whether natural scrolling is enabled. It can be _enabled_ or _disabled_