Add ScrollFactor option to change mouse/touchpad scroll speed

Add xorg option ScrollFactor.
Add xinput option "libinput Scrolling Factor".

This works well in xi2 applications where they receive the raw scroll
value, however applications that use the core x11 protocol only for input
receive a scroll button press. The frequency this scroll button press
event is sent depends on the value of ScrollFactor, so it works in such
applications as well but the scrolling wont be as "smooth" as if they
used xi2.

gtk, qt, chromium (and electron) applications seem to use xi2 while
firefox does not, unless you set the MOZ_USE_XINPUT2=1 environment
variable.

Signed-off-by: dec05eba <dec05eba@protonmail.com>
This commit is contained in:
dec05eba
2025-07-09 15:54:02 +02:00
committed by Enrico Weigelt
parent cda5a982af
commit 9e3544b258
3 changed files with 90 additions and 0 deletions

View File

@@ -154,6 +154,12 @@
/* Scroll pixel distance: CARD32, 1 value, read-only */
#define LIBINPUT_PROP_SCROLL_PIXEL_DISTANCE_DEFAULT "libinput Scrolling Pixel Distance Default"
/* Scroll factor: FLOAT, 1 value, 32 bit */
#define LIBINPUT_PROP_SCROLL_FACTOR "libinput Scrolling Factor"
/* Scroll factor: FLOAT, 1 value, 32 bit, read-only */
#define LIBINPUT_PROP_SCROLL_FACTOR_DEFAULT "libinput Scrolling Factor Default"
/* Click method: BOOL read-only, 2 values in order buttonareas, clickfinger
shows available click methods */
#define LIBINPUT_PROP_CLICK_METHODS_AVAILABLE "libinput Click Methods Available"

View File

@@ -206,6 +206,11 @@ If disabled (the default), the
button is considered logically down while held down and up once physically
released.
.TP 7
.BI "Option \*qScrollFactor\*q \*q" float \*q
Sets the scroll factor for scroll events. A higher value means faster scrolling.
Applications that don't support xi2 input will instead receive scroll button events
less or more frequently depending on the scroll factor value, instead of scrolling "smoother".
.TP 7
.BI "Option \*qScrollMethod\*q \*q" string \*q
Enables a scroll method. Permitted values are
.BR none ,

View File

@@ -52,6 +52,8 @@
#define TOUCH_MAX_SLOTS 15
#define XORG_KEYCODE_OFFSET 8
#define SCROLL_INCREMENT 15
#define SCROLL_FACTOR_MIN 0.0001
#define SCROLL_FACTOR_MAX 1000.0
#define TOUCHPAD_SCROLL_DIST_MIN 10 /* in libinput pixels */
#define TOUCHPAD_SCROLL_DIST_MAX 50 /* in libinput pixels */
@@ -175,6 +177,7 @@ struct xf86libinput {
CARD32 scroll_button; /* xorg button number */
BOOL scroll_buttonlock;
uint32_t scroll_pixel_distance;
float scroll_factor;
float speed;
float matrix[9];
enum libinput_config_scroll_method scroll_method;
@@ -1913,6 +1916,7 @@ calculate_axis_value(struct xf86libinput *driver_data,
value = value/dist * SCROLL_INCREMENT * 8;
}
value *= driver_data->options.scroll_factor;
*value_out = value;
return true;
@@ -3435,6 +3439,20 @@ xf86libinput_parse_scroll_pixel_distance_option(InputInfoPtr pInfo,
return dist;
}
static inline double
xf86libinput_parse_scroll_factor_option(InputInfoPtr pInfo,
struct libinput_device *device)
{
const double scroll_factor_default = 1.0;
double scroll_factor = xf86SetRealOption(pInfo->options, "ScrollFactor", scroll_factor_default);
if (scroll_factor < SCROLL_FACTOR_MIN || scroll_factor > SCROLL_FACTOR_MAX) {
xf86IDrvMsg(pInfo, X_ERROR, "Invalid ScrollFactor %f, expected to be between %f and %f\n",
scroll_factor, SCROLL_FACTOR_MIN, SCROLL_FACTOR_MAX);
scroll_factor = scroll_factor_default;
}
return scroll_factor;
}
static inline unsigned int
xf86libinput_parse_clickmethod_option(InputInfoPtr pInfo,
struct libinput_device *device)
@@ -3774,6 +3792,7 @@ xf86libinput_parse_options(InputInfoPtr pInfo,
options->scroll_button = xf86libinput_parse_scrollbutton_option(pInfo, device);
options->scroll_buttonlock = xf86libinput_parse_scrollbuttonlock_option(pInfo, device);
options->scroll_pixel_distance = xf86libinput_parse_scroll_pixel_distance_option(pInfo, device);
options->scroll_factor = xf86libinput_parse_scroll_factor_option(pInfo, device);
options->click_method = xf86libinput_parse_clickmethod_option(pInfo, device);
#if HAVE_LIBINPUT_CLICKFINGER_BUTTON_MAP
options->clickfinger_button_map = xf86libinput_parse_clickfinger_map_option(pInfo, device);
@@ -4257,6 +4276,8 @@ static Atom prop_scroll_buttonlock;
static Atom prop_scroll_buttonlock_default;
static Atom prop_scroll_pixel_distance;
static Atom prop_scroll_pixel_distance_default;
static Atom prop_scroll_factor;
static Atom prop_scroll_factor_default;
static Atom prop_click_methods_available;
static Atom prop_click_method_enabled;
static Atom prop_click_method_default;
@@ -5247,6 +5268,34 @@ LibinputSetPropertyScrollPixelDistance(DeviceIntPtr dev,
return Success;
}
static inline int
LibinputSetPropertyScrollFactor(DeviceIntPtr dev,
Atom atom,
XIPropertyValuePtr val,
BOOL checkonly)
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
float *scroll_factor;
if (val->format != 32 || val->size != 1 || val->type != prop_float)
return BadMatch;
scroll_factor = (float*)val->data;
if (checkonly) {
if (*scroll_factor < SCROLL_FACTOR_MIN || *scroll_factor > SCROLL_FACTOR_MAX)
return BadValue;
if (!xf86libinput_check_device(dev, atom))
return BadMatch;
} else {
driver_data->options.scroll_factor = *scroll_factor;
}
return Success;
}
static inline int
LibinputSetPropertyRotationAngle(DeviceIntPtr dev,
Atom atom,
@@ -5502,6 +5551,8 @@ LibinputSetProperty(DeviceIntPtr dev, Atom atom,
rc = LibinputSetPropertyHorizScroll(dev, atom, val, checkonly);
else if (atom == prop_scroll_pixel_distance)
rc = LibinputSetPropertyScrollPixelDistance(dev, atom, val, checkonly);
else if (atom == prop_scroll_factor)
rc = LibinputSetPropertyScrollFactor(dev, atom, val, checkonly);
else if (atom == prop_mode_groups) {
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
@@ -5543,6 +5594,7 @@ LibinputSetProperty(DeviceIntPtr dev, Atom atom,
atom == prop_scroll_method_default ||
atom == prop_scroll_methods_available ||
atom == prop_scroll_pixel_distance_default ||
atom == prop_scroll_factor_default ||
atom == prop_sendevents_available ||
atom == prop_sendevents_default ||
atom == prop_serial ||
@@ -6155,6 +6207,32 @@ LibinputInitScrollPixelDistanceProperty(DeviceIntPtr dev,
1, &dist);
}
static void
LibinputInitScrollFactorProperty(DeviceIntPtr dev,
struct xf86libinput *driver_data,
struct libinput_device *device)
{
float scroll_factor = driver_data->options.scroll_factor;
if (!subdevice_has_capabilities(dev, CAP_POINTER))
return;
prop_scroll_factor = LibinputMakeProperty(dev,
LIBINPUT_PROP_SCROLL_FACTOR,
prop_float, 32,
1, &scroll_factor);
if (!prop_scroll_factor)
return;
prop_scroll_factor_default = LibinputMakeProperty(dev,
LIBINPUT_PROP_SCROLL_FACTOR_DEFAULT,
prop_float, 32,
1, &scroll_factor);
if (!prop_scroll_factor_default)
return;
}
static void
LibinputInitClickMethodsProperty(DeviceIntPtr dev,
struct xf86libinput *driver_data,
@@ -6700,6 +6778,7 @@ LibinputInitProperty(DeviceIntPtr dev)
LibinputInitNaturalScrollProperty(dev, driver_data, device);
LibinputInitDisableWhileTypingProperty(dev, driver_data, device);
LibinputInitScrollMethodsProperty(dev, driver_data, device);
LibinputInitScrollFactorProperty(dev, driver_data, device);
LibinputInitClickMethodsProperty(dev, driver_data, device);
LibinputInitClickfingerButtonmapProperty(dev, driver_data, device);
LibinputInitMiddleEmulationProperty(dev, driver_data, device);