From 5e819a9df3835469d1ffe842edc63bb7c11b57b6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 28 Nov 2016 14:09:06 +1000 Subject: [PATCH xf86-input-libinput] Calculate the required scroll distance based on the angle For a mouse with a click angle of 15 degrees things are unchanged. For devices with angles less than 10, the current code scrolled way too fast. Because the angle wasn't used anywhere, each tick would count as full scroll wheel event, a slight movement of the wheel would thus scroll as much as a large movement on a normal mouse. Fix this by taking the actual click angle of the device into account. We calculate some multiple of the angle that's close enough to the default 15 degrees of the wheel and then require that many click events to hit the full scroll distance. For example, a mouse with a click angle of 3 degrees now requires 5 clicks to trigger a full legacy scroll button event. XI2.1 clients get the intermediate events (i.e. in this case five times one-fifth of the scroll distance) and can thus scroll smoothly, or more specifically in smaller events than usual. https://bugs.freedesktop.org/show_bug.cgi?id=92772 Signed-off-by: Peter Hutterer --- src/xf86libinput.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/xf86libinput.c b/src/xf86libinput.c index 747e84b..c558092 100644 --- a/src/xf86libinput.c +++ b/src/xf86libinput.c @@ -124,8 +124,12 @@ struct xf86libinput { uint32_t capabilities; struct { + /* The distances set in the XI 2.1 ScrollClass */ int vdist; int hdist; + + double vdist_factor; + double hdist_factor; } scroll; struct { @@ -1320,6 +1324,53 @@ xf86libinput_handle_key(InputInfoPtr pInfo, struct libinput_event_keyboard *even xf86PostKeyboardEvent(dev, key, is_press); } +static inline double +get_scroll_factor(struct xf86libinput *driver_data, + struct libinput_event_pointer *event, + enum libinput_pointer_axis axis) +{ + double *factor; + double f; + double angle; + int discrete; + + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + factor = &driver_data->scroll.hdist_factor; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + factor = &driver_data->scroll.vdist_factor; + break; + default: + return 0.0; + } + + /* We assume the scroll click angle of the device never changes */ + if (*factor != 0.0) + return *factor; + + /* Calculate the angle per single scroll event */ + angle = libinput_event_pointer_get_axis_value(event, axis); + discrete = libinput_event_pointer_get_axis_value_discrete(event, axis); + angle /= discrete; + + /* We only do magic for click angles smaller than 10 degrees */ + if (angle >= 10) { + *factor = 1.0; + return 1.0; + } + + /* Figure out something that gets close to 15 degrees (the general + * wheel default) with a number of clicks. This formula gives us + * between 14 and and 18 degrees for the range of 1-9. + */ + f = 13/(int)angle + 1; + + *factor = f; + + return f; +} + static void xf86libinput_handle_axis(InputInfoPtr pInfo, struct libinput_event_pointer *event) { @@ -1329,6 +1380,7 @@ xf86libinput_handle_axis(InputInfoPtr pInfo, struct libinput_event_pointer *even double value; enum libinput_pointer_axis axis; enum libinput_pointer_axis_source source; + double scroll_factor; if ((driver_data->capabilities & CAP_POINTER) == 0) return; @@ -1349,7 +1401,8 @@ xf86libinput_handle_axis(InputInfoPtr pInfo, struct libinput_event_pointer *even if (libinput_event_pointer_has_axis(event, axis)) { if (source == LIBINPUT_POINTER_AXIS_SOURCE_WHEEL) { value = libinput_event_pointer_get_axis_value_discrete(event, axis); - value *= driver_data->scroll.vdist; + scroll_factor = get_scroll_factor(driver_data, event, axis); + value *= driver_data->scroll.vdist/scroll_factor; } else { value = libinput_event_pointer_get_axis_value(event, axis); } @@ -1363,7 +1416,8 @@ xf86libinput_handle_axis(InputInfoPtr pInfo, struct libinput_event_pointer *even if (libinput_event_pointer_has_axis(event, axis)) { if (source == LIBINPUT_POINTER_AXIS_SOURCE_WHEEL) { value = libinput_event_pointer_get_axis_value_discrete(event, axis); - value *= driver_data->scroll.hdist; + scroll_factor = get_scroll_factor(driver_data, event, axis); + value *= driver_data->scroll.vdist/scroll_factor; } else { value = libinput_event_pointer_get_axis_value(event, axis); } @@ -2928,8 +2982,8 @@ xf86libinput_pre_init(InputDriverPtr drv, pInfo->private = driver_data; driver_data->pInfo = pInfo; - driver_data->scroll.vdist = 15; - driver_data->scroll.hdist = 15; + driver_data->scroll.vdist = 100; + driver_data->scroll.hdist = 100; driver_data->path = path; driver_data->shared_device = shared_device; xorg_list_append(&driver_data->shared_device_link, -- 2.9.3