diff --git a/include/libinput-properties.h b/include/libinput-properties.h index ad0165e..52ad6c9 100644 --- a/include/libinput-properties.h +++ b/include/libinput-properties.h @@ -123,6 +123,12 @@ /* Scroll button lock: BOOL, 1 value, TRUE for enabled, FALSE otherwise, read-only*/ #define LIBINPUT_PROP_SCROLL_BUTTON_LOCK_DEFAULT "libinput Button Scrolling Button Lock Enabled Default" +/* Scroll pixel distance: CARD32, 1 value (with implementation-defined limits) */ +#define LIBINPUT_PROP_SCROLL_PIXEL_DISTANCE "libinput Scrolling Pixel Distance" + +/* Scroll pixel distance: CARD32, 1 value, read-only */ +#define LIBINPUT_PROP_SCROLL_PIXEL_DISTANCE_DEFAULT "libinput Scrolling Pixel Distance 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" diff --git a/man/libinput.man b/man/libinput.man index c9fec4e..6ed4cdd 100644 --- a/man/libinput.man +++ b/man/libinput.man @@ -160,6 +160,16 @@ Enables a scroll method. Permitted values are Not all devices support all options, if an option is unsupported, the default scroll option for this device is used. .TP 7 +.BI "Option \*qScrollPixelDistance\*q \*q" int \*q +Sets the movement distance, in "pixels", required to trigger one logical +wheel click. This option only applies to the scroll methods +.BI twofinger, +.BI edge, +.BI button. +See section +.B SCROLL PIXEL DISTANCE +for more details. +.TP 7 .BI "Option \*qSendEventsMode\*q \*q" (disabled|enabled|disabled-on-external-mouse) \*q Sets the send events mode to disabled, enabled, or "disable when an external mouse is connected". @@ -279,6 +289,10 @@ Indicates which scroll methods are available on this device. 3 boolean values (8 bit, 0 or 1), in order "two-finger", "edge", "button". Indicates which scroll method is currently enabled on this device. .TP 7 +.BI "libinput Scroll Pixel Distance" +1 32-bit value (nonzero, with additional implementation-defined range checks). +Changes the movement distance required to trigger one logical wheel click. +.TP 7 .BI "libinput Send Events Modes Available" 2 boolean values (8 bit, 0 or 1), in order "disabled" and "disabled-on-external-mouse". Indicates which send-event modes are available @@ -396,6 +410,17 @@ it takes left-handed-ness into account. .TP This feature is provided by this driver, not by libinput. +.SH SCROLL PIXEL DISTANCE +The X server does not support per-pixel scrolling but it does support +smooth scrolling. All scroll events however are based around a logical +unit of scrolling (traditionally corresponding to a wheel click). +It is thus not possible to scroll by 10 pixels, but it is possible for a +driver to scroll by 1/10th of a logical wheel click. +.PP +libinput provides scroll data in pixels. The \fBScrollPixelDistance\fR +option defines the amount of movement equivalent to one wheel click. For +example, a value of 50 means the user has to move a finger by 50 pixels to +generate one logical click event and each pixel is 1/50th of a wheel click. .SH BUGS This driver does not work with \fBOption \*qDevice\*q\fR set to an event node in \fI/dev/input/by-id\fR and \fI/dev/input/by-path\fR. This can be diff --git a/src/xf86libinput.c b/src/xf86libinput.c index 7e3584b..9c9bc88 100644 --- a/src/xf86libinput.c +++ b/src/xf86libinput.c @@ -52,6 +52,9 @@ #define TABLET_NUM_BUTTONS 7 /* we need scroll buttons */ #define TOUCH_MAX_SLOTS 15 #define XORG_KEYCODE_OFFSET 8 +#define SCROLL_INCREMENT 15 +#define TOUCHPAD_SCROLL_DIST_MIN 10 /* in libinput pixels */ +#define TOUCHPAD_SCROLL_DIST_MAX 50 /* in libinput pixels */ #define streq(a, b) (strcmp(a, b) == 0) #define strneq(a, b, n) (strncmp(a, b, n) == 0) @@ -146,6 +149,7 @@ struct xf86libinput { CARD32 sendevents; CARD32 scroll_button; /* xorg button number */ BOOL scroll_buttonlock; + uint32_t scroll_pixel_distance; float speed; float matrix[9]; enum libinput_config_scroll_method scroll_method; @@ -1621,7 +1625,17 @@ calculate_axis_value(struct xf86libinput *driver_data, if (source == LIBINPUT_POINTER_AXIS_SOURCE_WHEEL) { value = get_wheel_scroll_value(driver_data, event, axis); } else { + double dist = driver_data->options.scroll_pixel_distance; + assert(dist != 0.0); + value = libinput_event_pointer_get_axis_value(event, axis); + /* We need to scale this value into our scroll increment range + * because that one is constant for the lifetime of the + * device. The user may change the ScrollPixelDistance + * though, so where we have a dist of 10 but an increment of + * 15, we need to scale from 0..10 into 0..15. + */ + value = value/dist * SCROLL_INCREMENT; } *value_out = value; @@ -2826,6 +2840,39 @@ xf86libinput_parse_scrollbuttonlock_option(InputInfoPtr pInfo, return buttonlock; } +static inline bool +xf86libinput_want_scroll_distance_option(struct libinput_device *device) +{ + uint32_t methods = + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN | + LIBINPUT_CONFIG_SCROLL_2FG | + LIBINPUT_CONFIG_SCROLL_EDGE; + + if ((libinput_device_config_scroll_get_methods(device) & methods) == 0) + return false; + + return true; +} + +static inline uint32_t +xf86libinput_parse_scroll_pixel_distance_option(InputInfoPtr pInfo, + struct libinput_device *device) +{ + uint32_t dflt = SCROLL_INCREMENT; + uint32_t dist; + + if (!xf86libinput_want_scroll_distance_option(device)) + return dflt; + + dist = xf86SetIntOption(pInfo->options, "ScrollPixelDistance", dflt); + if (dist < TOUCHPAD_SCROLL_DIST_MIN || dist > TOUCHPAD_SCROLL_DIST_MAX) { + xf86IDrvMsg(pInfo, X_ERROR, + "Invalid ScrollPixelDistance %d\n", dist); + dist = dflt; + } + return dist; +} + static inline unsigned int xf86libinput_parse_clickmethod_option(InputInfoPtr pInfo, struct libinput_device *device) @@ -3107,6 +3154,7 @@ xf86libinput_parse_options(InputInfoPtr pInfo, options->scroll_method = xf86libinput_parse_scroll_option(pInfo, device); 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->click_method = xf86libinput_parse_clickmethod_option(pInfo, device); options->middle_emulation = xf86libinput_parse_middleemulation_option(pInfo, device); options->disable_while_typing = xf86libinput_parse_disablewhiletyping_option(pInfo, device); @@ -3420,8 +3468,8 @@ xf86libinput_pre_init(InputDriverPtr drv, * affect touchpad scroll speed. For wheels it doesn't matter as * we're using the discrete value only. */ - driver_data->scroll.v.dist = 15; - driver_data->scroll.h.dist = 15; + driver_data->scroll.v.dist = SCROLL_INCREMENT; + driver_data->scroll.h.dist = SCROLL_INCREMENT; if (!is_subdevice) { if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) @@ -3563,6 +3611,8 @@ static Atom prop_scroll_button; static Atom prop_scroll_button_default; 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_click_methods_available; static Atom prop_click_method_enabled; static Atom prop_click_method_default; @@ -4380,6 +4430,34 @@ LibinputSetPropertyHorizScroll(DeviceIntPtr dev, return Success; } +static inline int +LibinputSetPropertyScrollPixelDistance(DeviceIntPtr dev, + Atom atom, + XIPropertyValuePtr val, + BOOL checkonly) +{ + InputInfoPtr pInfo = dev->public.devicePrivate; + struct xf86libinput *driver_data = pInfo->private; + uint32_t dist; + + if (val->format != 32 || val->type != XA_CARDINAL || val->size != 1) + return BadMatch; + + dist = *(BOOL*)val->data; + if (checkonly) { + if (dist < TOUCHPAD_SCROLL_DIST_MIN || + dist > TOUCHPAD_SCROLL_DIST_MAX) + return BadValue; + + if (!xf86libinput_check_device(dev, atom)) + return BadMatch; + } else { + driver_data->options.scroll_pixel_distance = dist; + } + + return Success; +} + static inline int LibinputSetPropertyRotationAngle(DeviceIntPtr dev, Atom atom, @@ -4557,6 +4635,8 @@ LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, rc = LibinputSetPropertyDragLockButtons(dev, atom, val, checkonly); else if (atom == prop_horiz_scroll) rc = LibinputSetPropertyHorizScroll(dev, atom, val, checkonly); + else if (atom == prop_scroll_pixel_distance) + rc = LibinputSetPropertyScrollPixelDistance(dev, atom, val, checkonly); else if (atom == prop_mode_groups) { InputInfoPtr pInfo = dev->public.devicePrivate; struct xf86libinput *driver_data = pInfo->private; @@ -4588,6 +4668,7 @@ LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, atom == prop_scroll_methods_available || atom == prop_scroll_button_default || atom == prop_scroll_buttonlock_default || + atom == prop_scroll_pixel_distance_default || atom == prop_click_method_default || atom == prop_click_methods_available || atom == prop_middle_emulation_default || @@ -5114,6 +5195,32 @@ LibinputInitScrollMethodsProperty(DeviceIntPtr dev, } } +static void +LibinputInitScrollPixelDistanceProperty(DeviceIntPtr dev, + struct xf86libinput *driver_data, + struct libinput_device *device) +{ + CARD32 dist = driver_data->options.scroll_pixel_distance; + + if (!subdevice_has_capabilities(dev, CAP_POINTER)) + return; + + if (!xf86libinput_want_scroll_distance_option(device)) + return; + + prop_scroll_pixel_distance = LibinputMakeProperty(dev, + LIBINPUT_PROP_SCROLL_PIXEL_DISTANCE, + XA_CARDINAL, 32, + 1, &dist); + if (!prop_scroll_pixel_distance) + return; + + prop_scroll_pixel_distance_default = LibinputMakeProperty(dev, + LIBINPUT_PROP_SCROLL_PIXEL_DISTANCE_DEFAULT, + XA_CARDINAL, 32, + 1, &dist); +} + static void LibinputInitClickMethodsProperty(DeviceIntPtr dev, struct xf86libinput *driver_data, @@ -5555,6 +5662,7 @@ LibinputInitProperty(DeviceIntPtr dev) LibinputInitDragLockProperty(dev, driver_data); LibinputInitHorizScrollProperty(dev, driver_data); + LibinputInitScrollPixelDistanceProperty(dev, driver_data, device); LibinputInitPressureCurveProperty(dev, driver_data); LibinputInitTabletAreaRatioProperty(dev, driver_data); }