whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

commit 044ee890286153a1aefb40cb8b6659921aecb38b
parent 5bd4af34a09a381a0f8b1552684650698937e6b0
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Mon, 29 Oct 2018 11:25:24 -0700

HID: input: simplify/fix high-res scroll event handling

Commit 1ff2e1a44e02 ("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>

Diffstat:
Mdrivers/hid/hid-input.c | 43+++++++++++++++++++++----------------------
1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c @@ -1855,31 +1855,30 @@ EXPORT_SYMBOL_GPL(hidinput_disconnect); void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter, int hi_res_value) { - int low_res_scroll_amount; - /* Some wheels will rest 7/8ths of a notch from the previous notch - * after slow movement, so we want the threshold for low-res events to - * be in the middle of the notches (e.g. after 4/8ths) as opposed to on - * the notches themselves (8/8ths). - */ - int threshold = counter->resolution_multiplier / 2; + int low_res_value, remainder, multiplier; input_report_rel(counter->dev, REL_WHEEL_HI_RES, hi_res_value * counter->microns_per_hi_res_unit); - counter->remainder += hi_res_value; - if (abs(counter->remainder) >= threshold) { - /* Add (or subtract) 1 because we want to trigger when the wheel - * is half-way to the next notch (i.e. scroll 1 notch after a - * 1/2 notch movement, 2 notches after a 1 1/2 notch movement, - * etc.). - */ - low_res_scroll_amount = - counter->remainder / counter->resolution_multiplier - + (hi_res_value > 0 ? 1 : -1); - input_report_rel(counter->dev, REL_WHEEL, - low_res_scroll_amount); - counter->remainder -= - low_res_scroll_amount * counter->resolution_multiplier; - } + /* + * Update the low-res remainder with the high-res value, + * but reset if the direction has changed. + */ + remainder = counter->remainder; + if ((remainder ^ hi_res_value) < 0) + remainder = 0; + remainder += hi_res_value; + + /* + * Then just use the resolution multiplier to see if + * we should send a low-res (aka regular wheel) event. + */ + multiplier = counter->resolution_multiplier; + low_res_value = remainder / multiplier; + remainder -= low_res_value * multiplier; + counter->remainder = remainder; + + if (low_res_value) + input_report_rel(counter->dev, REL_WHEEL, low_res_value); } EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll);