Skip to content

Commit 044ee89

Browse files
committed
HID: input: simplify/fix high-res scroll event handling
Commit 1ff2e1a ("HID: input: Create a utility class for counting scroll events") created the helper function hid_scroll_counter_handle_scroll() to handle high-res scroll events and also expose them as regular wheel events. But the resulting algorithm was unstable, and causes scrolling to be very unreliable. When you hit the half-way mark of the highres multiplier, small highres movements will incorrectly translate into big traditional wheel movements, causing odd jitters. Simplify the code and make the output stable. NOTE! I'm pretty sure this will need further tweaking. But this at least turns a unusable mouse wheel on my Logitech MX Anywhere 2S into a usable one. Cc: Jiri Kosina <jikos@kernel.org> Cc: Harry Cutts <hcutts@chromium.org> Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com> Cc: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 5bd4af3 commit 044ee89

File tree

1 file changed

+21
-22
lines changed

1 file changed

+21
-22
lines changed

drivers/hid/hid-input.c

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,31 +1855,30 @@ EXPORT_SYMBOL_GPL(hidinput_disconnect);
18551855
void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter,
18561856
int hi_res_value)
18571857
{
1858-
int low_res_scroll_amount;
1859-
/* Some wheels will rest 7/8ths of a notch from the previous notch
1860-
* after slow movement, so we want the threshold for low-res events to
1861-
* be in the middle of the notches (e.g. after 4/8ths) as opposed to on
1862-
* the notches themselves (8/8ths).
1863-
*/
1864-
int threshold = counter->resolution_multiplier / 2;
1858+
int low_res_value, remainder, multiplier;
18651859

18661860
input_report_rel(counter->dev, REL_WHEEL_HI_RES,
18671861
hi_res_value * counter->microns_per_hi_res_unit);
18681862

1869-
counter->remainder += hi_res_value;
1870-
if (abs(counter->remainder) >= threshold) {
1871-
/* Add (or subtract) 1 because we want to trigger when the wheel
1872-
* is half-way to the next notch (i.e. scroll 1 notch after a
1873-
* 1/2 notch movement, 2 notches after a 1 1/2 notch movement,
1874-
* etc.).
1875-
*/
1876-
low_res_scroll_amount =
1877-
counter->remainder / counter->resolution_multiplier
1878-
+ (hi_res_value > 0 ? 1 : -1);
1879-
input_report_rel(counter->dev, REL_WHEEL,
1880-
low_res_scroll_amount);
1881-
counter->remainder -=
1882-
low_res_scroll_amount * counter->resolution_multiplier;
1883-
}
1863+
/*
1864+
* Update the low-res remainder with the high-res value,
1865+
* but reset if the direction has changed.
1866+
*/
1867+
remainder = counter->remainder;
1868+
if ((remainder ^ hi_res_value) < 0)
1869+
remainder = 0;
1870+
remainder += hi_res_value;
1871+
1872+
/*
1873+
* Then just use the resolution multiplier to see if
1874+
* we should send a low-res (aka regular wheel) event.
1875+
*/
1876+
multiplier = counter->resolution_multiplier;
1877+
low_res_value = remainder / multiplier;
1878+
remainder -= low_res_value * multiplier;
1879+
counter->remainder = remainder;
1880+
1881+
if (low_res_value)
1882+
input_report_rel(counter->dev, REL_WHEEL, low_res_value);
18841883
}
18851884
EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll);

0 commit comments

Comments
 (0)