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

High-resolution scrolling #741

Open
rightaditya opened this issue Jan 10, 2024 · 36 comments · May be fixed by #794
Open

High-resolution scrolling #741

rightaditya opened this issue Jan 10, 2024 · 36 comments · May be fixed by #794
Labels

Comments

@rightaditya
Copy link
Contributor

This is a feature request for high-resolution scrolling via the trackball module.

Because the trackball module is (relatively) high-DPI, it should theoretically be possible for it to provide high-resolution scroll events. Changing scrollSpeedDivisor from the default of 8 to 1 sends 8 times the events, and of course the default interpretation by the OS is to scroll 8 times as much for a given physical distance.

Scroll speed can't always be adjusted sufficiently (if it can at all) to account for this; plus simply reducing scroll speed in the OS (when it's an option, that is) might not truly indicate to the OS that a fine-grained level of scrolling is possible; I'm not 100% sure on this but it even at lower scroll speeds it might still default to scrolling in larger discrete steps (e.g. never going lower than one line, even if a view can support scrolling fractions of lines).

AFAICT the "right" way to do this is to use the resolution multiplier control in the USB HID protocol (see, e.g., https://usb.org/sites/default/files/hut1_13.pdf). This functionality was developed in part by Microsoft, so it's how Windows does it, and AIUI the Linux support for high-resolution scrolling follows it as well, including some software-side conventions adopted in Windows (specifically, the 120 value assigned to a "standard" scroll detent). FWICT if a resolution multiplier is specified, the Linux kernel will just use that as a divisor for the scroll "amount", and clients that support the corresponding libinput events will handle the scroll accordingly (and there is a legacy event for those that don't).

(The only way I could find to change this value other than through the kernel—which does it via reading the resolution multiplier from the device—is using libinput-config, but that works globally and so affects all scroll devices.)

@rightaditya
Copy link
Contributor Author

Just adding that I'd be happy to work on this myself, but would need some guidance as it's been ~15 years since I've done any kind of programming at this low a level (and never with USB).

@mondalaci
Copy link
Member

Thanks for letting me know about the resolution multiplier control of USB! I didn't know about it. Assuming it works cross-OS, we should pick a fine-grained value that allows per-pixel scrolling and make the UHK firmware multiple scroll values accordingly.

@kareltucek Can you implement this or do we need Benedek for the USB part?

@kareltucek
Copy link
Collaborator

I fear we will need Benedek for this, as this is likely to violate the boot protocol compatibility.

@mondalaci mondalaci added the usb label Jan 10, 2024
@mondalaci
Copy link
Member

I'm summoning @benedekkupper for a short comment about this issue. This is not a priority.

@rightaditya
Copy link
Contributor Author

In case it's of use or interest: Peter Hutterer, who's been involved in the implementation of high-resolution scrolling throughout the Linux stack, has written a couple blog posts about how things work 1 2.

Footnotes

  1. https://who-t.blogspot.com/2018/12/high-resolution-wheel-scrolling-on.html

  2. https://who-t.blogspot.com/2020/04/high-resolution-wheel-scrolling-in.html

@benedekkupper
Copy link
Contributor

The boot protocol mode of the mouse is s farce, we should actually either disable the mouse boot support, or implement the report layout changing. Since until now noone noticed that it's broken, it's a safe bet to disable it.

Regarding the implementation it seems to me that we need to add an HID feature report to the mouse interface, with this resolution multiplier usage as the single element. The questions to clarify is:

  1. what is the supported range of this value
  2. what should be the default value
  3. how this value is used in the mouse input report calculation
  4. whether this value needs to be stored in non-volatile memory on the device, or the OS takes care of it

@mondalaci
Copy link
Member

@benedekkupper I don't have solid answers, but regarding 1 to 3, can we have sensible defaults? Then we could tweak them. I don't understand question 4, so please elaborate.

@rightaditya
Copy link
Contributor Author

I had a bit of time the last few weekends to look into this, and I have an implementation working (branched from the v11.1.1 tag) here. I've only tested it on Linux thus far.

For a more visual demonstration, here are some screen recordings:

@mondalaci
Copy link
Member

@rightaditya I'm very interested in this and your screencast is very promising, but I don't experience any change when testing your branch. Would you please open a PR and possibly provide instructions for testing? I'm on the latest Linux Mint.

@rightaditya
Copy link
Contributor Author

@mondalaci Sure, I take it you'd prefer the PR be rebased to master first (rather than the v11.1.1 tag)?

As for testing—yeah, there are a couple of caveats (for Linux). The first is that not every application actually listens to the high-res wheel events, and so there will be no difference in those cases. Firefox is (for me) the most notable of these, followed closely by GNOME Terminal (even though both can scroll smoothly with my laptop's touchpad). Chromium, GNOME Web (aka Epiphany), and GNOME Files (aka Nautilus) all do use the high-res wheel events, though for some reason the former two feel like they have some kind of lag involved. But Nautilus works quite smoothly, and my recordings are from it.

I'm not too sure how much of an issue this might be, but one potential issue I can think of is the whole X11/Wayland mess. All of my tests have been with GNOME on Wayland (on Manjaro). I'm not totally sure if/how the high-res stuff gets handled on X11. evdev should still produce the relevant events, I think, since the kernel is really where they're ultimately coming from, but I don't know what happens with them beyond that. The patches to the kernel date back to before Wayland was as highly-used as it is now, so I think it should still work, possibly without libinput. Even if libinput turns out to be required, it's possible for Xorg to use libinput, and I think this is done by default in some distros/DEs.

So I guess that means:

  1. Try it in an app that uses the high-res events (Nautilus, Chromium, Epiphany, and I'm sure there must be others).
  2. If that doesn't work, try it in the same app(s) but on Wayland rather than X11. I think the most recent release of Linux Mint has added experimental Wayland support to Cinnamon.
  3. If that doesn't work, try it in the same app but on GNOME on Wayland. Even running it in a live USB environment should work to avoid disturbing an installed system too much.

I'm sure there are other app/DE combinations that will work but haven't tested anything else just yet.

The final caveat is that, even in Nautilus, the scrolling is a little janky due to the wheel value accumulation that libinput applies to high-res scroll events. Essentially it waits for a value of 60 (which is equal to half a normal scroll detent) to be accumulated before issuing scroll events, and has a 500ms timeout on this. They do this to avoid small scroll events being issued when high-res wheels are pushed down to press a button, or just from being bumped accidentally. I'm running a patched version of libinput to get around this (it's just a one-line sed call to change the accumulation value from 60 to 1—I can point you to the relevant line if desired). There is a discussion going on about this on their Gitlab. My recordings were made with this patched version of libinput.

@mondalaci
Copy link
Member

@rightaditya Thanks for elaborating; I really appreciate it! I'll test this with all three OSes and I'll try to test the suggested applications and environments.

Yes, I'd prefer the PR to be rebased to master.

@rightaditya rightaditya linked a pull request Jul 25, 2024 that will close this issue
5 tasks
@mhantsch
Copy link
Contributor

Would this change also enable hires-scrolling using the touchpad, or is it currently only addressing the trackball? I mostly use the touchpad, and I've mapped mod+touchpad to scrolling. When I compare my laptop's built-in touchpad scrolling to UHK touchpad scrolling, the difference between hires and non-hires scrolling becomes really obvious.

If needed, I can test this with Linux (Pop_OS!, Wayland) and Windows 11.

@rightaditya
Copy link
Contributor Author

@mhantsch I don't have the touchpad module, so I haven't tested it. But there's nothing in my branch that limits the changes to the trackball. I suspect it should work for the touchpad module too, since its resolution is high enough to use for controlling the cursor. (It won't do anything for the little ball on the key cluster, since that uses a much lower-resolution sensor.)

If you want to give it a shot, I've just uploaded binaries here. Just beware the potential caveats on Linux I mentioned above. For me in GNOME on Wayland, it works in Nautilus, Epiphany, and Chromium, but not in Firefox and GNOME Terminal.

@mhantsch
Copy link
Contributor

@rightaditya Try to set MOZ_USE_XINPUT2=1 before launching Firefox and see if that makes a difference. I just checked my setup notes, and they say I added this:

echo "MOZ_USE_XINPUT2=1" >/etc/environment.d/99moz-maexxx.conf 

when I set up my Laptop. Don't ask me how I found out about this, I'm just trying to be good at documenting for my future self.

@rightaditya
Copy link
Contributor Author

@mhantsch I remember trying that setting to no effect quite some time ago (months? years?). I don't think it does anything under Wayland.

@mhantsch
Copy link
Contributor

@rightaditya I run Firefox under Wayland (Pop_OS! 22.04, a variant of Ubuntu) and it made scrolling smooth in both Firefox and Thunderbird, at least when using the built-in Laptop touchpad. I can scroll my Firefox page by pixel.

I'll try your build in the next day or two.

@mondalaci
Copy link
Member

On Linux Mint 21.3, scrolling is much smoother in Nemo and Gnome Terminal, but there's no difference in Chrome and Firefox. I'll try Linux Mint 22 as soon as it's possible to upgrade.

On Windows 11, scrolling is much smoother in browsers, especially in Edge and Chrome. I can't notice a difference in Explorer.

On the latest OSX, I can't notice any difference in Safari, Chrome, and the built-in file manager.

Where it's supported, hi-res scrolling already makes a huge difference, and I reckon the firmware can be optimized to better use of it regarding mouse keys and modules. @kareltucek should be able to comment on the details when he gets home from vacation.

@benedekkupper Feel free to look into the USB implementation and suggest possible improvements, although this issue is currently not a priority.

Excellent work, @rightaditya!

@rightaditya
Copy link
Contributor Author

I run Firefox under Wayland (Pop_OS! 22.04, a variant of Ubuntu) and it made scrolling smooth in both Firefox and Thunderbird, at least when using the built-in Laptop touchpad. I can scroll my Firefox page by pixel.

@mhantsch Huh, that's interesting. Setting that environment variable makes no difference for me, whether for the UHK trackball or my laptop's touchpad (the latter scrolls 1:1 either way).

@rightaditya
Copy link
Contributor Author

On Linux Mint 21.3, scrolling is much smoother in Nemo and Gnome Terminal, but there's no difference in Chrome and Firefox. I'll try Linux Mint 22 as soon as it's possible to upgrade.

My guess is that X11/Wayland accounts for at least some of the discrepancies with my results (difference for Chromium but not GNOME Terminal). Unfortunately I couldn't test under X11, likely because of a broken X11 config on my system. I don't imagine it'd affect anything though, since your results show that it does at least have an effect for some applications under X11 (I'm assuming that's the case for you based on Mint's Wayland port/readiness status).

On Windows 11, scrolling is much smoother in browsers, especially in Edge and Chrome. I can't notice a difference in Explorer.

Just tested this and got the same results as you in Edge and Explorer. I've also now got the firmware responding to individual axis settings as configurable by registry keys according to

On the latest OSX, I can't notice any difference in Safari, Chrome, and the built-in file manager.

It's totally possible that their HID driver doesn't support the resolution multiplier feature, in which case this won't work, at least OOTB. The good news is that the firmware seems to be behaving correctly and not activating high-res mode unless the relevant HID request is sent. (Otherwise you would've seen the scrolling become 120x more sensitive with the build from my branch.)

Excellent work, @rightaditya!

Thank you!

@mhantsch
Copy link
Contributor

@mhantsch Huh, that's interesting. Setting that environment variable makes no difference for me

I might have set it while I was still running under X11. At some point in time, I switched my login from X11 to Wayland, but I might have chosen that setting before. It definitely made a difference when I first configured it.

Anyway, let me run some tests on what we have now.

@mhantsch
Copy link
Contributor

mhantsch commented Aug 5, 2024

If you want to give it a shot, I've just uploaded binaries

I finally got to test your build, and I don't see any difference on Pop_OS! 22.04. I tried Firefox, Chrome, the Files browser and a number of other apps that scroll smoothly with the built-in trackpad of my Laptop, but still exhibit jumpy scrolling with the UHK. I tried the trackball, trackpoint and touchpad modules. Everything seems to behave the same way as with the regular UHK firmware.

Except for one thing: Mouse Scroll actions do not work anymore when triggered from keys.

image

When I tap the corresponding key, the mouse scroll action no longer works (when using your firmware).

@rightaditya
Copy link
Contributor Author

I finally got to test your build, and I don't see any difference on Pop_OS! 22.04.

That's weird... any chance you could give it a shot in a fresh environment (live USB would do)? Since we know it's worked (as much as it can) on Mint 21.3 and Manjaro, either of those would be good choices, but I expect the results should be similar for others (I'm particularly thinking of Ubuntu—and maybe more so Ubuntu GNOME—but I'd be surprised if things were different on, e.g., Fedora or Arch). Windows 11 would also be a good candidate.

Except for one thing: Mouse Scroll actions do not work anymore when triggered from keys.

That's definitely not great. I'm unfortunately out of town at the moment and thus AFUHK, so I can't try to reproduce this myself until I'm back. If you manage to try things out in a fresh environment, please try the mouse scroll actions there as well.

@mhantsch
Copy link
Contributor

mhantsch commented Aug 8, 2024

Let me try it on a Windows laptop, but I didn't have it with me when I tried your firmware. I'm still surprised I wouldn't see any change on Pop_OS! (since it's based on Ubuntu, it's usually pretty standard).

@rightaditya
Copy link
Contributor Author

I'm still surprised I wouldn't see any change on Pop_OS!

As am I, but the surprisal is muted somewhat given that we got different outcomes with MOZ_USE_XINPUT2=1.

@mhantsch
Copy link
Contributor

@rightaditya I now tried it under Windows, and yes, butterly smooth scrolling in browsers, Outlook etc. when scrolling with the UHK Touchpad module. Very nice.

Regarding the Mouse Scroll Action: with your software, it still scrolls, but only by 1 pixel per tap. With the regular firmware it scrolls by the same amount as 1 mouse wheel notch.

I haven't change any of my UHK configuration other than updating to your firmware.

So I think for Windows this is working well, just the Mouse Scroll Action needs to be adapted.

For Linux I am not yet satisfied. I'll do some more experiments when I get a bit more time. I need to switch back to X11 and see how that behaves as opposed to Wayland.

@rightaditya
Copy link
Contributor Author

@mhantsch Thanks for testing!

I now tried it under Windows, and yes, butterly smooth scrolling in browsers, Outlook etc. when scrolling with the UHK Touchpad module. Very nice.

It should be even smoother if you adjust the speed/acceleration settings :) Just beware that changing them affects the whole trackball module, so it affects cursor speed as well. I found setting the base speed to 0.2, speed to 0.8, acceleration to 0.9, and scroll speed divisor to 12 to be reasonably close to the default settings (0.5, 0.5, 1, 8) for the cursor while increasing granularity of scrolling, especially when scrolling smoothly.

Regarding the Mouse Scroll Action: with your software, it still scrolls, but only by 1 pixel per tap.

That makes clear what I missed, thanks. Fixing this will require updates to my firmware. I'm still out of town and won't be back to my UHK for another week, so I won't be able to test anything until then. I think by default it makes sense to have the scroll keys (and scrolling via macros) have the same behaviour as stock, but it might also be useful to allow high-res control. I'll have to play around with this when I get back.

For Linux I am not yet satisfied. I'll do some more experiments when I get a bit more time. I need to switch back to X11 and see how that behaves as opposed to Wayland.

Yeah, I'm still surprised that you got the results you did. I think I know why scroll keys don't work for you—since I didn't scale those values accordingly in the firmware, the OS ends up spitting out tiny values, which must be accumulated to a minimum value before libinput lets them through. If I'm right, the scroll key should work on Linux if you hold it down (after which it will proceed the same larger chunks as you get with trackball scrolling, though of course much slower than reasonable).

You can try setting mouseKeys.scroll.initialSpeed, mouseKeys.scroll.baseSpeed (and possibly mouseKeys.scroll.{acceleratedSpeed,deceleratedSpeed}—I haven't figured out what exactly these two do) in the meanwhile. But they're limited to a maximum value of 255, which will still yield a slower scroll than the stock firmware.

I don't use the scroll keys much, if at all, so I'm curious: when you want to scroll further than you'd get with a single press, do you tend to hold them down, or mash the keys (or both, varying by situation; etc.)?

@mhantsch
Copy link
Contributor

mhantsch commented Sep 4, 2024

I'm curious: when you want to scroll further than you'd get with a single press, do you tend to hold them down, or mash the keys (or both, varying by situation; etc.)?

@rightaditya Depends on the situation: normally I hit the key once or twice, and if that's not far enough I hold it down to keep going for a while.

@rightaditya
Copy link
Contributor Author

@mhantsch I've just uploaded a fix (that works for me, anyway). You can download the build here. Let me know how it goes—hopefully that fixes it for you too.

@mhantsch
Copy link
Contributor

@rightaditya I finally tried your latest build, and yes, under Windows this works beautifully.

  1. Scrolling with touchpad module is butterly smooth.
  2. Mouse scroll action (bound to a key) now also scrolls properly.

Will test this on Linux another day.

@mhantsch
Copy link
Contributor

mhantsch commented Oct 6, 2024

@rightaditya @mondalaci I tested the build now under Windows, Linux, and MacOS. On Windows and on MacOS the scrolling is hires and smooth. On Linux, I don't see any difference from the regular firmware, it still scrolls in steps.

The issue with Mouse scroll action has been resolved. Mouse scroll actions triggered by keys work normally.

Because this build is an improvement at least for Win+Mac, I think the change should be merged.

It might be my particular Linux setup that prevents hires scrolling for whatever reason. I can hires-scroll with the built-in Laptop touchpad, but for whatever reason, not with the UHK. I will keep investigating.

@mhantsch
Copy link
Contributor

mhantsch commented Oct 6, 2024

And btw, it makes no difference on Linux whether I test this under X11 or Wayland; I just don't get hires scrolling.

I am a little lost how I can better trace this, or track down why it's not doing hires scrolling. Any suggestions gladly appreciated!

@rightaditya
Copy link
Contributor Author

@mhantsch I'm definitely no expert, but let's see what we can figure out... I guess the first thing to check is whether the kernel is even issuing high-res scroll events. You can use evtest for this. For me the UHK device for the trackball is the second of the four presented. I think this should be consistent but you can try the other devices if you get no outputs. If the kernel is issuing high-res scroll events you should see REL_WHEEL_HI_RES (REL_HWHEEL_HI_RES for horizontal scroll) events in the output, with corresponding values that change depending on how much scrolling you're doing. When total accumulated values on an axis add up to 120 (or -120) there should then also be a REL_WHEEL (REL_HWHEEL for horizontal) event issued.

On Windows and on MacOS the scrolling is hires and smooth.

I'm surprised about MacOS given @mondalaci found no change! 🤔

@mondalaci
Copy link
Member

I just wanted to merge this, but then I noticed that mouse key movement is crazy fast on Linux and Windows 11 (but not on macOS). This must be fixed before the merge.

@rightaditya
Copy link
Contributor Author

@mondalaci I've just pushed a fix. Binary here in case you want to verify that way quickly. My Windows install is misbehaving at the moment so I wasn't able to test it there, but I did verify both the broken behaviour before the fix and the restored behaviour afterwards on my Linux install. Scrolling via mouse keys is still high-res.

I'm surprised your macOS test showed no difference, though. The keyboard should've been sending the same increased values to it. I coded the high-res support to only be enabled if it seems clear that the OS is enabling it, so maybe your macOS isn't doing what I accounted for and so the high-res support stays disabled. Maybe there's some configuration somewhere since @mhantsch found the high-res scrolling to work on macOS. If I ever get a Mac I'll see if I can look into it further, but no one should hold their breath for this ;)

@rightaditya
Copy link
Contributor Author

For anyone interested, Linux scrolling can be made smoother still by altering libinput's scroll accumulation threshold. Unfortunately they don't have this as a configurable option (yet) and so making this change requires recompiling it. Fortunately it's a super-easy change to make. Without it, there's a slight delay before scrolling starts when there hasn't been any scrolling for some timeout or when changing scroll directions; in the latter case especially it can feel pretty janky next to the otherwise very smooth scrolling. I've set up a package in the AUR that should help for anyone who's on an Arch-derived distro.

Another recommendation (this one regardless of OS) is to alter the speed settings for the trackball a bit as I described in this comment. It's technically possible to go even smoother still, but IMO that would make regular movement difficult to use. Properly supporting this I think would require separate settings for scrolling vs. movement, and TBH the settings I found are already very smooth.

@mhantsch
Copy link
Contributor

Yes, I overlooked the bug in the mouse key movement.

I can confirm that this new build rightaditya/uhkfirmware: 11.2.0 #highres-2024-10-15 fixes the problem, and works fine on Windows 11.

I will test later on Linux and MacOS.

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

Successfully merging a pull request may close this issue.

5 participants