Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Scroll Wheel] Emulate discrete scrolling from v120 events #6881

Merged
merged 1 commit into from
Jul 18, 2024

Conversation

Agent00Ming
Copy link
Contributor

Describe your PR, what does it fix/add?

Fixes #6681. Adds an accurate emulation of discrete scrolling when given scroll wheel events that are fractions of 120. It is configurable to be force enabled (2) / disabled (0) but it defaults to automatic detection (input:emulate_discrete_scroll 1)

Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.)

No clue how this will interact with horizontal scroll wheels because I don't have a mouse that can do that. Should not affect normal, non-highres, scroll wheel behaviour.

Is it ready for merging, or does it need work?

Needs some more testing and could use some touch-ups. Tested with an old wireless mouse that does scrolling in multiples of 30 degrees and a normal wired mouse.

@vaxerski
Copy link
Member

will this work with 6608?

@Agent00Ming
Copy link
Contributor Author

It should, I originally wrote it and tested on aq branch and it worked fine, but since the logic can be entirely contained in hyprland source, I backported the patches to main.

@Agent00Ming Agent00Ming force-pushed the hires-discrete-emulation branch 3 times, most recently from 31d2f63 to 4ccbb4d Compare July 15, 2024 12:21
@Agent00Ming Agent00Ming marked this pull request as ready for review July 15, 2024 13:57
@Agent00Ming
Copy link
Contributor Author

@Ciel-MC for insanely high res mouse. @CNR0706 @noahfraiture for bug reports.

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

Hi, just did some testing on the branch, in xwayland(minecraft tested, latest and 1.7), the scrolling seems roughly 5x too fast, if I set the scrolling sense to 0.2 on 1.20, it would almost always scroll 1 slot in the hotbar for every physical stepped scroll on the mouse, but it's still not perfect as if you scroll a few times, it will jump by two every now and then, and on 1.7 which does not have scrolling sensitivity, it currently mostly scrolls by 5 slots, but sometimes 6 and rarely 4, this behavior is consistent between a G502(standard 15deg hires) and a MX Master 3s (1deg hires).

@Agent00Ming
Copy link
Contributor Author

What happens when you tweak the Hyprland input:scroll_factor? Also get a Hyprland log with
logpatch.txt, ty.

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

What happens when you tweak the Hyprland input:scroll_factor? Also get a Hyprland log with logpatch.txt, ty.

How do you want me to tweak it? I'll put on the patch now

@Agent00Ming
Copy link
Contributor Author

try changing the scroll factor to 0.25, 0.67, 1.0 or 1.5

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

I was wondering why the patch wouldn't apply when I noticed I didn't switch branch yet, so I'm just using some past version of the main branch .-. I'll actually try the branch now

Well, the patch failed anyway cause there was a stray comment XD no worries I applied it manually

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

What happens when you tweak the Hyprland input:scroll_factor? Also get a Hyprland log with logpatch.txt, ty.

Alright actually tried out the patch, the G502 is very close to perfect, with it single scrolling most of the time, and only double scrolling every ~6/7 times, here's the logs for that
g502.log

The MX Master 3s though, is actually a big downgrade from main, with the scroll wheel being extremely fast on both regular desktop usage and in game, here are two figure to show the problem
mx3s.log
image
(if I let it scroll freely, free speed is a modest ~60-70k on g502, can't help but notice those numbers are almost 15 times apart 🤨 )

Given the differences, I don't think there is a need to test the scrolling scale factor, so that is not tested.

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

What happens when you tweak the Hyprland input:scroll_factor? Also get a Hyprland log with logpatch.txt, ty.

Alright actually tried out the patch, the G502 is very close to perfect, with it single scrolling most of the time, and only double scrolling every ~6/7 times, here's the logs for that g502.log

The MX Master 3s though, is actually a big downgrade from main, with the scroll wheel being extremely fast on both regular desktop usage and in game, here are two figure to show the problem mx3s.log image (if I let it scroll freely, free speed is a modest ~60-70k on g502, can't help but notice those numbers are almost 15 times apart 🤨 )

Given the differences, I don't think there is a need to test the scrolling scale factor, so that is not tested.

If I go to the most recent main, where the mx master 3s' scroll behaves correctly, I get ~80k px/s peak, which is almost spot on for a 15x at 1.2mil projected pixels, so I think we've found the suspect.

@Agent00Ming
Copy link
Contributor Author

Agent00Ming commented Jul 15, 2024

mx3s log looks weird... try setting input:emulate_discrete_scroll to 0 or 2 and see if there's any improvement
0 (disabled) should be identical to main and 2 forces all wheel events to get converted

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

mx3s log looks weird... try setting input:emulate_discrete_scroll to 0 or 2 and see if there's any improvement 0 (disabled) should be identical to main and 2 forces all wheel events to get converted

As expected, 0 does very well, expect being ~5x faster in game, while 2 is completely borked with the scrolling speed everywhere

Also yeah I don't think it takes a dev to notice something is not quite right for a single scroll, lol that entire log are two separate scrolls only, separated by an empty line

@Agent00Ming
Copy link
Contributor Author

also, can you get a libinput record of your mx master to see how the events are reported?

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

also, can you get a libinput record of your mx master to see how the events are reported?

  - evdev:
    - [  0,      0,   2,   8,      -2] # EV_REL / REL_WHEEL                -2
    - [  0,      0,   2,  11,    -240] # EV_REL / REL_WHEEL_HI_RES       -240
    - [  0,      0,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +0ms
  - evdev:
    - [  0,   6995,   2,   8,     -14] # EV_REL / REL_WHEEL               -14
    - [  0,   6995,   2,  11,   -1680] # EV_REL / REL_WHEEL_HI_RES      -1680
    - [  0,   6995,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +6ms
  - evdev:
    - [  0, 787005,   2,   8,      -2] # EV_REL / REL_WHEEL                -2
    - [  0, 787005,   2,  11,    -240] # EV_REL / REL_WHEEL_HI_RES       -240
    - [  0, 787005,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +781ms
  - evdev:
    - [  0, 817002,   2,   8,      -2] # EV_REL / REL_WHEEL                -2
    - [  0, 817002,   2,  11,    -240] # EV_REL / REL_WHEEL_HI_RES       -240
    - [  0, 817002,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +30ms
  - evdev:
    - [  0, 825002,   2,   8,      -3] # EV_REL / REL_WHEEL                -3
    - [  0, 825002,   2,  11,    -360] # EV_REL / REL_WHEEL_HI_RES       -360
    - [  0, 825002,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +8ms
  - evdev:
    - [  0, 832002,   2,   8,      -2] # EV_REL / REL_WHEEL                -2
    - [  0, 832002,   2,  11,    -240] # EV_REL / REL_WHEEL_HI_RES       -240
    - [  0, 832002,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +7ms
  - evdev:
    - [  0, 840002,   2,   8,      -4] # EV_REL / REL_WHEEL                -4
    - [  0, 840002,   2,  11,    -480] # EV_REL / REL_WHEEL_HI_RES       -480
    - [  0, 840002,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +8ms
  - evdev:
    - [  0, 847007,   2,   8,      -3] # EV_REL / REL_WHEEL                -3
    - [  0, 847007,   2,  11,    -360] # EV_REL / REL_WHEEL_HI_RES       -360
    - [  0, 847007,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +7ms
  - evdev:
    - [  1, 117006,   2,   8,       2] # EV_REL / REL_WHEEL                 2
    - [  1, 117006,   2,  11,     240] # EV_REL / REL_WHEEL_HI_RES        240
    - [  1, 117006,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +270ms
  - evdev:
    - [  1, 620010,   2,   8,      -2] # EV_REL / REL_WHEEL                -2
    - [  1, 620010,   2,  11,    -240] # EV_REL / REL_WHEEL_HI_RES       -240
    - [  1, 620010,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +503ms
  - evdev:
    - [  1, 687014,   2,   8,      -2] # EV_REL / REL_WHEEL                -2
    - [  1, 687014,   2,  11,    -240] # EV_REL / REL_WHEEL_HI_RES 
      -240
    - [  1, 687014,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +67ms
  - evdev:
    - [  1, 710008,   2,   8,      -2] # EV_REL / REL_WHEEL                -2
    - [  1, 710008,   2,  11,    -240] # EV_REL / REL_WHEEL_HI_RES       -240
    - [  1, 710008,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +23ms
  - evdev:
    - [  1, 717008,   2,   8,      -3] # EV_REL / REL_WHEEL                -3
    - [  1, 717008,   2,  11,    -360] # EV_REL / REL_WHEEL_HI_RES       -360
    - [  1, 717008,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +7ms
  - evdev:
    - [  1, 725008,   2,   8,      -4] # EV_REL / REL_WHEEL                -4
    - [  1, 725008,   2,  11,    -480] # EV_REL / REL_WHEEL_HI_RES       -480
    - [  1, 725008,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +8ms
  - evdev:
    - [  1, 732008,   2,   8,      -4] # EV_REL / REL_WHEEL                -4
    - [  1, 732008,   2,  11,    -480] # EV_REL / REL_WHEEL_HI_RES       -480
    - [  1, 732008,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +7ms
  # Current time is 23:30:20

Interesting... it would seem like how Hyprland works under 2 is how it should according to libinput, apparently. But since this is a pretty quirky mouse, I also had add this tweak

mouse:*:name:Logitech USB Receiver Mouse:
    MOUSE_WHEEL_CLICK_ANGLE=1
    MOUSE_WHEEL_CLICK_COUNT=360
    MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL=26
    MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL=14

under /etc/udev/hwdb.d/71-logitech-mice.hwdb so that could play a part as well...

@Agent00Ming
Copy link
Contributor Author

and what does wev report when you scroll with input:emulate_discrete_scroll on 0 and then on 2?

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

Oh and, if it provides you any closure, if I just delete the factor of 15 on that line, the wheel appears to work in regular app,s but is still utterly broken in Minecraft, which you can either take at a good thing because half of the issue is solved, or as a bad thing because I have never had only minecraft be extremely fast(even previous main only has the 5x speed, not the hypersonic speed.

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

and what does wev report when you scroll with input:emulate_discrete_scroll on 0 and then on 2?

[13:      wl_pointer] axis: time: 35555721; axis: 0 (vertical), value: 1.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 1
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35555766; axis: 0 (vertical), value: 2.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 2
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35555796; axis: 0 (vertical), value: 2.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 2
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35555819; axis: 0 (vertical), value: 2.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 2
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35555826; axis: 0 (vertical), value: 3.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 3
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35555834; axis: 0 (vertical), value: 3.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 3
[13:      wl_pointer] frame

This is a single step on 2, 0 behaves like mainline, but if you want to see:

[13:      wl_pointer] axis: time: 35600385; axis: 0 (vertical), value: 2.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 1
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35600445; axis: 0 (vertical), value: 2.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 1
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35600468; axis: 0 (vertical), value: 3.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 1
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35600475; axis: 0 (vertical), value: 2.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 1
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35600483; axis: 0 (vertical), value: 3.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 1
[13:      wl_pointer] frame
[13:      wl_pointer] axis: time: 35600490; axis: 0 (vertical), value: 4.000000
[13:      wl_pointer] axis_source: 0 (wheel)
[13:      wl_pointer] axis_stop: axis: 0 (vertical), discrete: 1
[13:      wl_pointer] frame

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

Oh and, if it provides you any closure, if I just delete the factor of 15 on that line, the wheel appears to work in regular app,s but is still utterly broken in Minecraft, which you can either take at a good thing because half of the issue is solved, or as a bad thing because I have never had only minecraft be extremely fast(even previous main only has the 5x speed, not the hypersonic speed.

Oh and yes, that does cripple the G502's scrolling speed, suggesting that this multiplier needs to change per device

@Agent00Ming
Copy link
Contributor Author

Agent00Ming commented Jul 15, 2024

it honestly looks like the WHEEL_HI_RES values are off by a factor of 120 (should be divided by 120), try tinkering around with the hwdb overrides. I'm assuming you put the 360 click count because it should have that precision but it's being interpreted as 360 discrete events for a full rotation instead of the 360 degrees of high-res events.

the reason it "works" with 0 or on main is because crazy high values or crazy low values are collapsed by value/abs(value) into +-1

@Ciel-MC
Copy link

Ciel-MC commented Jul 15, 2024

it honestly looks like the WHEEL_HI_RES values are off by a factor of 120 (should be divided by 120), try tinkering around with the hwdb overrides. I'm assuming you put the 360 click count because it should have that precision but it's being interpreted as 360 discrete events for a full rotation instead of the 360 degrees of high-res events.

the reason it "works" with 0 or on main is because crazy high values or crazy low values are collapsed by value/abs(value) into +-1

Did a bit more further digging, it does seem like it would be a libinput issue, still not certain though. Anyway, now the only issue is the occasional double scroll on the g502

@xor-bits
Copy link

Seems to work perfectly on default settings with G502, G502 LS and G502 X Plus. Horizontal scroll works fine too.

@Agent00Ming
Copy link
Contributor Author

Agent00Ming commented Jul 15, 2024

Anyway, now the only issue is the occasional double scroll on the g502

are you sure it's not because of slightly ticking the wheel in the opposite direction when you are scrolling? it doesn't seem like it's a rounding error because I only deal with integers inside of the accumulator

I managed to repro it once here but it's not really consistent
[WARN] DEBUG_SCROLL: DISCRETE COUNTED
[WARN] DEBUG_SCROLL: 30
[WARN] DEBUG_SCROLL: 60
[WARN] DEBUG_SCROLL: 90
[WARN] DEBUG_SCROLL: 120
[WARN] DEBUG_SCROLL: DISCRETE COUNTED
[WARN] DEBUG_SCROLL: 30
[WARN] DEBUG_SCROLL: ACCUMULATOR RESET
[WARN] DEBUG_SCROLL: 60
[WARN] DEBUG_SCROLL: ACCUMULATOR RESET <--- logitech driver bug?
[WARN] DEBUG_SCROLL: 90                <
[WARN] DEBUG_SCROLL: 240               <
[WARN] DEBUG_SCROLL: DISCRETE COUNTED  <
[WARN] DEBUG_SCROLL: DISCRETE COUNTED  <
[WARN] DEBUG_SCROLL: 90
[WARN] DEBUG_SCROLL: 180
[WARN] DEBUG_SCROLL: DISCRETE COUNTED
[WARN] DEBUG_SCROLL: 120
[WARN] DEBUG_SCROLL: DISCRETE COUNTED
[WARN] DEBUG_SCROLL: 60
[WARN] DEBUG_SCROLL: 120
[WARN] DEBUG_SCROLL: DISCRETE COUNTED
[WARN] DEBUG_SCROLL: 60
[WARN] DEBUG_SCROLL: 120
[WARN] DEBUG_SCROLL: DISCRETE COUNTED

@Ciel-MC
Copy link

Ciel-MC commented Jul 16, 2024

Anyway, now the only issue is the occasional double scroll on the g502

are you sure it's not because of slightly ticking the wheel in the opposite direction when you are scrolling? it doesn't seem like it's a rounding error because I only deal with integers inside of the accumulator

I don't think so, it's overscrolling which I'm not sure how any accident can cause that? Maybe it's too sensitive to events? But even if I scroll very steadily I may get 2 steps

I managed to repro it once here but it's not really consistent

I reported to libinput and they informed me that it is the fault of the kernel, and I checked and indeed my specific Master 3s is not supported, so I am recompiling the linux with a patch now and see how it goes

@Agent00Ming
Copy link
Contributor Author

Agent00Ming commented Jul 16, 2024

I mean, with input:scroll_factor at 1.0 and input:emulate_discrete_scroll at 1, it's essentially 1:1 with what libinput gives us. Whatever is reported to us is counted as what it is... unless you hit the 501ms scroll, you shouldn't get weird any weird overscrolling. (I hate how some apps only use pixel scrolling, some only use discrete, some use both, some accept the v120 but don't actually ignore the discrete events like they should.)

@Agent00Ming
Copy link
Contributor Author

There technically is a possible rounding error in the interval * scroll factor but it's so insignificant that you'd have to scroll continuously for a while to get a single 'unintentional' double scroll. It's fixable by switching the scroll factor to affect the discrete value instead of the interval and then clamping/rounding that to clean divisors of 120 but that's more work for something that you won't even notice for 99.9999% of the time (source: I made it up).

An interesting interaction of input:emulate_discrete_scroll 2 is that you can make normal scroll wheels (increments of 120) scroll less for the same amount of physical wheel clicks too by changing input:scroll_factor to something less than 1.0. For example, changing input:scroll_factor to 0.25 would make the normal scroll wheel only send 1 discrete every 4 scroll wheel clicks.

The seat change is to mitigate a bug with some apps thinking that an empty axis event with axis_stop() is from a touchpad or something (why do they not look at the axis source?) and doing the momentum scrolling thing... We still send the 'empty' event because v120 is still attempted to be sent in case the application supports it.

The ceil/floor rounding was changed back to normal rounding if the absolute value is more than 1 because turning 1.25 discrete into 2 is a bit jarring. If it is less than 1 (but not 0) then it's clamped to 1 to avoid rounding 0.49 discrete to 0 (buggy behaviour and breaks scrolling entirely in some apps).

 * seat: avoid sending axis_stop() when source is wheel

 * fix rounding for absolute discrete values greater than 1
@Agent00Ming
Copy link
Contributor Author

This should be ready for review. @vaxerski

@Ciel-MC
Copy link

Ciel-MC commented Jul 17, 2024

I agree, outside of games, as Ive been screwing around with the kernel to try and get my shit fixed, the system seems pretty stable, so Id say it’s good to go

Copy link
Member

@vaxerski vaxerski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

@vaxerski vaxerski merged commit 8e15f91 into hyprwm:main Jul 18, 2024
11 checks passed
@mrmbernardi
Copy link

I'm using a G502 with hyprland 0.43.0-1 and I still get frequent double scrolls and the scroll just generally not being in sync with the mouse wheel. Is there a new issue tracking this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Hyprland 0.41.1] Logitech G903 scroll speed too high in XWayland clients and Alacritty.
5 participants