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

[Feature Request] Hi-res scrolling #17585

Open
3 of 4 tasks
b- opened this issue Jul 7, 2022 · 54 comments
Open
3 of 4 tasks

[Feature Request] Hi-res scrolling #17585

b- opened this issue Jul 7, 2022 · 54 comments

Comments

@b-
Copy link

b- commented Jul 7, 2022

Feature Request Type

  • Core functionality
  • Add-on hardware support (eg. audio, RGB, OLED screen, etc.)
  • Alteration (enhancement/optimization) of existing feature(s)
  • New behavior

Description

Windows and Linux support a "resolution modifier" report for scrolling, which allows finer scrolling instead of just "ticks." Specifically, one can do smooth per-pixel scrolling. It also seems to use fewer resources, possibly because of the larger descriptors.

Unfortunately, it seems that there's virtually no public code or documentation available. The following is everything I've managed to gather in terms of documentation and examples:

This almost certainly requires MOUSE_EXTENDED_REPORT to be enabled based on my testing.

I started mocking up something here: https://github.com/b-/qmk_firmware/tree/resolution_multiplier

However this is the first time I've ever gotten this close to USB or to HID descriptors.

I haven't tested my above code yet, either, though I will as soon as I get the chance.

Anyway, I'm posting this here to help me keep track of this, and of my progress (or lack thereof). I expect to edit this post frequently.

@pandages
Copy link

pandages commented Jul 8, 2022

I think this is a really cool concept. Is it for using a rotary encoder as a mouse-style scrollwheel? Could it potentially be mapped to any keys?

@drashna
Copy link
Member

drashna commented Jul 8, 2022

Taking a look at "wheel.doc", I'm not sure how practical this is. Namely, this appears to need custom drivers to support it (namely for registry settings). And those dirvers need to be signed, or the overall security of the system degraded (driver signing disabled, which requires secure boot to be disabled).

It's definitely possible to implement, but I'm not sure that it is worth the effort here.

@b-
Copy link
Author

b- commented Jul 8, 2022

I can say with confidence this works without drivers other than what's bundled with Windows and Linux.

hid-remapper allows one to set a custom scroll multiplier and it works without drivers just fine (tested on Windows 10 and 11, and on KDE Plasma). This what I'm stealing the HID collection tree from, so if I can simply do what it's doing this would work just fine.

@b-
Copy link
Author

b- commented Jul 8, 2022

I think this is a really cool concept. Is it for using a rotary encoder as a mouse-style scrollwheel? Could it potentially be mapped to any keys?

QMK already has scroll wheel support via mouse keys. You can just add MOUSEKEY_ENABLE = yes to your rules.mk and use KC_MS_WH_UP and KC_MS_WH_DOWN as keycodes for mouse wheel scrolling.

My goal here is to add a resolution multiplier for wheel scrolling, as that will allow finer precision than an ordinary scroll wheel allows for (and this works without drivers on Windows Vista and up, or Linux).

My motivation is for DRAG_SCROLL on my Ploopy Classic to work at a finer precision.

Another idea is to put some kind of tiny trackball on top of a mouse, much like Apple's discontinued Mighty Mouse.

I mean, you can already do all of these things with QMK as is, but currently you either need to set the DPI very low (or use an encoder with big notches), because by default on Windows one single scroll wheel notch moves three lines.

By setting the resolution multiplier to 40 (120/3) Windows will instead scroll one line for every wheel notch (or KC_MS_WH_DOWN). Setting it even lower will scroll less than one line per notch, which is supported in many applications such as web browsers and image editors.

@b-
Copy link
Author

b- commented Jul 8, 2022

Microsoft's own mice that took advantage of this had "notchless" scroll wheels whose encoders were much more sensitive than what's standard today.

Example: https://www.cnet.com/reviews/microsoft-wireless-laser-mouse-7000-2008-review/

@b-
Copy link
Author

b- commented Aug 31, 2022

I bought a Microsoft Surface Precision Mouse to see how Microsoft implements hi-res scrolling, and gathered some data here. This is on a Windows 11 machine, with the mouse attached over USB.

First, I installed the relevant drivers for the mouse, and then disabled "flick" scrolling in the new settings panel for the mouse. I also inverted the scroll wheel for preference, but I don't think that's particularly relevant.

Then I unplugged the mouse, and opened the USB port in Wireshark (with the other devices filtered out on the USBPcap level).

Once the capture began, I plugged in the mouse, holding it upside down to prevent any tracking activity. Then I played with the scroll wheel, scrolling down a little bit, then up a little bit, then down a little bit again (varying the speed as I went along). I added comments to the packet capture to mark the end of the initialization handshake, and each scroll direction change.

What I saw that I found particularly curious is that this mouse actually doesn't send a count descriptor in its wheel reports. It instead varies the resolution multiplier with the direction and magnitude of the wheel motion, and that's the only information about the wheel. Still, I'd think it's enough.

Although I also should note that when I tried using the mouse on my Pinebook Pro in KDE Plasma (Wayland), neither Firefox nor Chrome nor native Qt apps had any hi-res scrolling support out of the box. I didn't try testing further.

The spec says the mouse really shouldn't send hi-res scrolling information until the host sends a command to switch into a fancy enhanced mode, so perhaps libinput doesn't have support for this mouse yet to send that command?

I also tried in Chromium and Firefox on Windows Subsystem for Linux, in Wayland, and hi-res scrolling was supported. I think WSL uses libinput as well (but of course Windows is abstracting the input packets), and I know for certain that libinput does normally support hi-res scrolling where allowed.

Attached is my wireshark capture.
hrscroll-surface_precision_mouse-with-comments.zip

@jfedor2
Copy link

jfedor2 commented Sep 6, 2022

Hi guys. I think I should be able to help.

As you've already noticed there's some stuff in the report descriptor that's required for this to work. I'd recommend you start with the exact same descriptor HID Remapper uses (the relevant top level collection, you can change the report ID) and only start tweaking it to your needs once you confirm hi-res scroll is working. There's some stuff that's not part of the spec that Windows expects anyway, like the resolution multiplier using 2 bits even if 1 would be enough. Also the logical collection semantics might not be obvious if you're new to HID report descriptors.

The important part is the feature report, which is different from input/output reports. It's a sort of configuration variable that the host can read and write. I don't know if QMK currently uses feature reports for anything.

In our case the feature report will contain two values - the multipliers for horizontal and vertical scroll. In theory there can be multiple levels of the multiplier, but since in practice the operating systems choose the highest value anyway, I think it makes sense to only have two levels, 1x (legacy behavior) and the maximum, which is 120x. This is what it looks like in the report descriptor:

Logical Minimum (0)
Logical Maximum (1)
Physical Minimum (1)
Physical Maximum (120)

What this means is that if the relevant bits in the feature report are set to 0 (which should be the default), the multiplier will be 1x. If they are set to 1, it will be 120x. When it's 120x, it means 120 units of scroll correspond to 1 normal/legacy scroll "tick", giving you higher resolution.

To recap you need:

  1. The relevant parts in the report descriptor.
  2. The ability to receive and send feature reports.
  3. Adjust what you send in the normal input reports in the horizontal/vertical scroll fields, depending on the values set by the host in the feature report.

An operating system that doesn't know about high resolution scroll will not touch the resolution multiplier in the feature report and will expect 1 unit=1 legacy tick. An operating system that knows about high resolution scroll will write 1 (or whatever the logical maximum is) to the resolution multiplier values in the feature report and will then expect 120 units=1 legacy tick (or whatever the physical maximum is).

It's also a good idea to detect USB mounting event and reset the resolution multiplier to the default of 1x, otherwise you run into issues when you reboot from an OS that knows about hi-res scroll to one that doesn't.

I'm not familiar with QMK source code, but I'll be happy to answer any questions you might have about HID so please don't hesitate to ask for clarification on any of this.

@github-actions
Copy link

github-actions bot commented Dec 7, 2022

This issue has been automatically marked as stale because it has not had activity in the last 90 days. It will be closed in the next 30 days unless it is tagged properly or other activity occurs.
For maintainers: Please label with bug, in progress, on hold, discussion or to do to prevent the issue from being re-flagged.

@github-actions github-actions bot added the stale Issues or pull requests that have become inactive without resolution. label Dec 7, 2022
@github-actions github-actions bot removed the stale Issues or pull requests that have become inactive without resolution. label Dec 8, 2022
@b-
Copy link
Author

b- commented Jan 3, 2023

Hey, thanks for working on this! A lot has gotten in the way of me making more progress, and it's hard to debug this sort of thing when you consider that everything I know about USB and HID I learned from working on this :) but I'll see if I can poke at your branch at some point anyway.

Just a random thought: what if you swap the wheel and AC pan entries in the descriptor? I wouldn't expect that to fix anything, but if it changes the axis upon which we get rogue outputs it might point us in the right direction? (Pun not intended, I promise!)

@b-
Copy link
Author

b- commented Jan 4, 2023

Wow! That's awesome!! Thank you!

I expected it to be about as picky as you're seeing -- that's about what I've experienced with @jfedor2/hid-remapper

Most mouse driver software that implements hires scrolling seems to turn it on and off based on what window your input is going into. Logitech is horribly picky about this and has a very limited whitelist of .exe files that it enables hires scrolling on. Microsoft Intellipoint Mouse and Keyboard Center lets you pick which apps let you do this, though.

Honestly part of my interest in a "hardware" hires scroll thing like this is to help put pressure on Microsoft to better implement their spec :)

@qmk qmk deleted a comment Mar 14, 2023
@qmk qmk deleted a comment Mar 14, 2023
@iicurtis
Copy link

I don't really understand HID setup, so I am hoping someone can help clarify some things. Looking at the Microsoft wheel.docx, they give the following collection hierarchy:

Mouse Application Collection
    Mouse Logical Collection
        Pointer Physical Collection
            Buttons (Input Report 0x01)
            X (Input Report 0x01)
            Y (Input Report 0x01)
            Logical Collection
                Resolution Multiplier (Feature Report 0x02)
                Wheel (Input Report 0x01)
            End Logical Collection
            Logical Collection
                Resolution Multiplier (Feature Report 0x02)
                AC Pan (Input Report 0x01)
            End Logical Collection
        End Physical Collection
    End Logical Collection
End Application Collection

However, the current QMK hierarchy is noticeably different. Instead of Application -> Logical -> Physical, the QMK hierarchy goes Application -> Physical.

Mouse Application Collection
    Pointer Physical Collection
        Buttons (Input Report 0x01)
        X (Input Report 0x01)
        Y (Input Report 0x01)
        Wheel (Input Report 0x01)
        AC Pan (Input Report 0x01)
    End Physical Collection
End Application Collection

I attempted to modify usb_descriptor.c to add an additional logical map and the corresponding Resolution Multiplier collections, but I am now realizing this was a bit too naive. My mouse breaks after updating the HID report structure, which probably needs to be reflected elsewhere.

  • Do we need the additional logical map or can I add directly to the physical collection?
  • Once the logical collections are added, what else needs to be updated?

@BanchouBoo
Copy link

Someone was working on a PR for this feature but I can't seem to find it anymore, what happened to it?

@DejayRezme
Copy link

DejayRezme commented Dec 26, 2023

I just wanted to add my user experience with an apple magic mouse I used a while at work:

It was the best scrolling experience I've ever had! It is a touch mouse of course with a smooth trackpad on top. But you could very smoothly scroll the window vertically 1:1 and it felt like the perfect mouse wheel. No indents or "3 lines at a time". Just smooth fast responsive scrolling. And you could "fling" the window content for fast scrolling and then stop it again like it was a weighted wheel. And you could precisely scroll and lift your finger without the scrolling jerking or drifting.
I still miss that mouse... it's one of those little things that you don't know you want until you try it (like a third dedicated mouse button for your ring finger).

So this could also be implemented with two of those "Cirque GlidePoint Circle Trackpads" one for mouse pointer and one for scrolling.

PS: I got part of this functionality back with a firefox extension called "ScrollAnywhere" that uses the middle mouse button (ring finger for me) to grab and drag / flick instead of the super awkward thing windows does. But this is not going to work if your middle mouse click is pressing the mouse wheel down.

@thejevans
Copy link

@b- I just got a Ploopy Adept hoping to have precision/hi-res scrolling, and I'm saddened to see it's not an option. I'm fairly green with QMK, but this is a priority for me, so I'm happy to help any way I can. Are you stuck on anything in particular?

@b-
Copy link
Author

b- commented Feb 20, 2024

@b- I just got a Ploopy Adept hoping to have precision/hi-res scrolling, and I'm saddened to see it's not an option. I'm fairly green with QMK, but this is a priority for me, so I'm happy to help any way I can. Are you stuck on anything in particular?

As you may have noticed I haven't touched this in a long while. However, I would love help solving this once and for all!

I want to warn you, though, I was kind of stuck on everything! I understand USB HID descriptors and the like at a cursory level, having learned virtually everything I know about it from trying to solve this. I also am not very experienced in C/C++, either.

That said, the main blockers (at least for me) were that I was getting "weird" cursor movement and it appeared that some input buffer on Windows was getting filled without being properly flushed. The pointer would fly into the corner as soon as I touched the ball, and then the computer would start making short beeps (not alert sounds, but actual beeps) a few times a second.

This happened just from moving the cursor around while hidpi was enabled in the firmware. I think I mostly used a patch from someone else's comment in this thread or something like that, but I recall encountering similar issues when I tried to crudely craft the descriptor and reports myself.

I assume that some of the messages being generated were malformed, and I don't really remember where I left off with troubleshooting that. I have a hunch that the descriptor and reports weren't matching or something, but I'm not sure and I don't really have any backups of what I was trying besides anything remaining on some lingering branch at https://github.com/b-/qmk_firmware.

I know I was looking at Wireshark messages, and I even purchased a Microsoft Sufrace Precision mouse that does support hidpi scrolling to record and compare its own descriptor and reports, but I don't remember where I went from there.

(It doesn't help that I lost my job around the time I stopped working on this and have still been unable to find full time employment since then. But I suppose that gives me more time now to potentially pick it back up...)

If you come up with anything interesting please ping me, either here and/or on the QMK Discord server (my Discord username is @bri9). I'd be more than excited to test with my old Ploopy Classic.

Oh, and I'm sure I already mentioned it more than once in this issue thread, but @jfedor2 has an excellent repository for a different HID device firmware, hid-remapper, with a working and customizable scroll multiplier. This might be a good reference?

Good luck!

@evan-goode
Copy link

Hi, I'm also interested in getting this working eventually, though I don't have much time to work on it right now. Like @b- I also tried implementing this feature a couple years ago, but I can't remember what I was stuck on.

I recall these articles by Peter Hutterer (libinput developer) were helpful to me:

Sorry for the noise!

@BanchouBoo
Copy link

Someone was working on a PR for this feature but I can't seem to find it anymore, what happened to it?

Realized I still had a local copy of the PR so I checked the log to find the username of the person working on it, some light searching led me to this post on reddit. @drashna did anything ever come of this? If desired I could upload it, but wouldn't want to do so without getting permission first.

image

@justinjradi
Copy link

justinjradi commented Jul 4, 2024

Hey. I'm not familiar with QMK, but I just implemented this using both ST's USB Library and TinyUSB. It seems to be working fine for the hosts I've been able to test on (Windows 10 and 11) but I'm still kinda confused. Here's my report descriptor for reference:

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x02,        // Usage (Mouse)
0xA1, 0x01,        // Collection (Application)
0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
0x09, 0x02,        //   Usage (Mouse)
0xA1, 0x02,        //   Collection (Logical)
0x85, 0x01,        //     Report ID (1)
0x09, 0x01,        //     Usage (Pointer)
0xA1, 0x00,        //     Collection (Physical)
0x05, 0x09,        //       Usage Page (Button)
0x19, 0x01,        //       Usage Minimum (0x01)
0x29, 0x05,        //       Usage Maximum (0x05)
0x15, 0x00,        //       Logical Minimum (0)
0x25, 0x01,        //       Logical Maximum (1)
0x95, 0x05,        //       Report Count (5)
0x75, 0x01,        //       Report Size (1)
0x81, 0x02,        //       Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01,        //       Report Count (1)
0x75, 0x03,        //       Report Size (3)
0x81, 0x01,        //       Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //       Usage Page (Generic Desktop Ctrls)
0x09, 0x30,        //       Usage (X)
0x09, 0x31,        //       Usage (Y)
0x95, 0x02,        //       Report Count (2)
0x75, 0x08,        //       Report Size (8)
0x15, 0x81,        //       Logical Minimum (-127)
0x25, 0x7F,        //       Logical Maximum (127)
0x81, 0x06,        //       Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xA1, 0x02,        //       Collection (Logical)
0x85, 0x02,        //         Report ID (2)
0x09, 0x48,        //         Usage (Resolution Multiplier)
0x95, 0x01,        //         Report Count (1)
0x75, 0x02,        //         Report Size (2)
0x15, 0x00,        //         Logical Minimum (0)
0x25, 0x01,        //         Logical Maximum (1)
0x35, 0x01,        //         Physical Minimum (1)
0x45, 0x78,        //         Physical Maximum (120)
0xB1, 0x02,        //         Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x01,        //         Report ID (1)
0x09, 0x38,        //         Usage (Wheel)
0x35, 0x00,        //         Physical Minimum (0)
0x45, 0x00,        //         Physical Maximum (0)
0x95, 0x01,        //         Report Count (1)
0x75, 0x08,        //         Report Size (8)
0x15, 0x81,        //         Logical Minimum (-127)
0x25, 0x7F,        //         Logical Maximum (127)
0x81, 0x06,        //         Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              //       End Collection
0xA1, 0x02,        //       Collection (Logical)
0x85, 0x02,        //         Report ID (2)
0x09, 0x48,        //         Usage (Resolution Multiplier)
0x95, 0x01,        //         Report Count (1)
0x75, 0x02,        //         Report Size (2)
0x15, 0x00,        //         Logical Minimum (0)
0x25, 0x01,        //         Logical Maximum (1)
0x35, 0x01,        //         Physical Minimum (1)
0x45, 0x78,        //         Physical Maximum (120)
0xB1, 0x02,        //         Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x35, 0x00,        //         Physical Minimum (0)
0x45, 0x00,        //         Physical Maximum (0)
0x75, 0x04,        //         Report Size (4)
0xB1, 0x01,        //         Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x01,        //         Report ID (1)
0x05, 0x0C,        //         Usage Page (Consumer)
0x0A, 0x38, 0x02,  //         Usage (AC Pan)
0x95, 0x01,        //         Report Count (1)
0x75, 0x08,        //         Report Size (8)
0x15, 0x81,        //         Logical Minimum (-127)
0x25, 0x7F,        //         Logical Maximum (127)
0x81, 0x06,        //         Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              //       End Collection
0xC0,              //     End Collection
0xC0,              //   End Collection
0xC0,              // End Collection

// 144 bytes

Other than making sure that you follow the correct collection hierarchy in the report descriptor, the key to getting it to work is to use the feature reports correctly. Again, here's the format of the feature report:

typedef struct __attribute__((packed))
{
	uint8_t report_ID;
	uint8_t scroll_resolution : 2;
	uint8_t pan_resolution : 2;
	uint8_t padding : 4;
} ResMultiplierReport;

Since the resolution multiplier usages have a logical range of 0 to 1, I interpret them as really just saying whether the wheels are in high-resolution mode. I haven't played around with them too much, but I think the physical maximums are the actual resolution.

Here's the important part: In addition to preparing for a Set_Report request with the feature report, you also need to configure your device to respond to a Get_Report request for the feature report. The Get_Report request preceeds the Set_Report request. I think this is totally undocumented and I only figured it out by analyzing the Wireshark capture that Bri shared. I highly recommend everyone take a look at the capture themselves.

What I'm still confused about is why? If there was just one Get_Report request, I'd think it's the host just asking for the capabilities of the device, and then the Set_Report requests that follow are just configuring the device. But for some reason every Set_Report request seems to be preceded by a Get_Report request. In all my testing so far, all the Set_Report requests I've seen just echo what my device sent in response to the Get_Report request. How many times have I said Get_Report and Set_Report by now?

Right now, I just have the feature report I respond with hard coded with both scroll_resolution and pan_resolution set. But if and when the host sets values other than what I initially reported, am I supposed to echo that or just respond with the same thing I was sending before?

A couple more notes:

  • I tried adding AC Zoom in the same manner, but it didn't work. I don't think Microsoft's mouse driver supports it :(
  • It looks like Wireshark has a bug where it interprets the wheel and AC pan data as resolution multipliers, so don't be confused if you see that.

@eynsai
Copy link
Contributor

eynsai commented Aug 14, 2024

Hi everyone. I'm not sure what the progress on this is, but I wanted to report that, with the help of the descriptor from @justinjradi, I was able to get a simple smooth scrolling example working. Please see this commit for the details.

I also initially ran into the same angry computer beeping issue that @b- mentioned, but I think that this can be fixed by just throttling the rate at which mouse reports are sent to a reasonable rate (e.g. 60Hz). Where exactly you do this is pretty application-dependent, but I did this by using a simple timer check in my drag-scroll implementation:

static void pointing_device_task_charybdis(report_mouse_t* mouse_report) {
    static int16_t scroll_buffer_x = 0;
    static int16_t scroll_buffer_y = 0;
    static uint32_t last_scroll_time = 0;
    scroll_buffer_x -= mouse_report->x;
    scroll_buffer_y -= mouse_report->y;
    mouse_report->x = 0;
    mouse_report->y = 0;
    if (timer_elapsed32(last_scroll_time) < 16) {
        return;
    }
    last_scroll_time = timer_read32();
    mouse_report->h = scroll_buffer_x;
    mouse_report->v = scroll_buffer_y;
    scroll_buffer_x = 0;
    scroll_buffer_y = 0;
}

report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
    if (is_keyboard_master()) {
        pointing_device_task_charybdis(&mouse_report);
        mouse_report = pointing_device_task_user(mouse_report);
    }
    return mouse_report;
}

A few things that ought to be improved, not necessarily by me:

  • Clean things up and add a #DEFINE to turn the entire smooth scrolling feature on and off.
  • Currently, smooth scrolling is set to a constant 1:120 resolution, and this is hard-coded into the USB HID description as an on/off switch. Is it possible to modify the description to allow this resolution to be adjusted dynamically by the keyboard?
    • Update: It looks like the OS will always select the highest possible resolution modifier, and the keyboard has no way to control this. However, it is possible to increase the resolution beyond a 1:120 ratio using an exponent. For example, by adding HID_RI_UNIT_EXPONENT(8, 0x01) to the resolution multiplier report descriptor, you can achieve a ratio of 1:1200, which should be enough to allow pixel-perfect scrolling on even extremely high-resolution displays.
  • See if it's possible to increase the number of bits allocated to the wheel report, since smooth scrolling means you can hit the int8 ceiling pretty easily.
    • Update: Yes, you can increase the report size for the wheel to 16 bits.
  • Provide some function(s) that let user/kb code control smooth scrolling behavior.
  • Integrate smooth scrolling better into existing pointing device code, so that end-users can turn on the feature without their scrolling sensitivity being slashed by a factor of 120.
    • Update: This isn't practical, as most existing mouse wheel code outputs -1/0/1 in the mouse report and would have to be completely rewritten to take advantage of smooth scrolling.
  • Add support to platforms other than ChibiOS.

I am a complete novice when it comes to the nitty-gritty of QMK, and I've also never touched USB HID before this in my life. So any support in polishing this feature up would be immensely appreciated. Maybe we can also push for this to be integrated into the official QMK repo? Although I'm not sure how that really works, I've never contributed to an open source project before.

@filyp
Copy link

filyp commented Aug 19, 2024

@morgannewellsun I pulled your changes and confirm they work wonderfully, you're a wizard

@IsaacElenbaas
Copy link
Contributor

Thanks so much! Great timing - I got my first trackball without a scroll wheel recently and only had to survive two or three weeks without smooth scrolling.

A few things:

  • Note that that commit won't apply cleanly to the current QMK master, for others planning to use it. 0f341df is the latest upstream commit on @morgannewellsun's branch. (I think I can bear my trackball being a few months back from the latest and greatest haha)
  • Even after adding buffer variable overflow protection and playing with lower DPI and such I was having up and down wiggling if I tried to scroll quickly. evtest showed reports with pretty random signs in the int8 range; limiting to 8 bits to feed the report values fixed it. Might be a Linux thing.
  • For anyone with a Ploopy device, you will definitely want #define PLOOPY_DRAGSCROLL_SEMAPHORE 0 with this (by default they eat all but every fourth scroll report).

@eynsai
Copy link
Contributor

eynsai commented Aug 20, 2024

@IsaacElenbaas When you're talking about the wiggling issues when scrolling quickly, are you using 8 bits or 16 bits for the wheel reports?

@filyp
Copy link

filyp commented Aug 20, 2024

Another issue I still have (on ploopy trackball) is that scrolling only starts after a threshold of 60 is crossed. So the start of scrolling always looks like:

event6   POINTER_SCROLL_WHEEL    +3008.498s	vert 7.50/60.0* horiz 0.00/0.0 (wheel)
event6   POINTER_SCROLL_WHEEL    +3008.499s	vert 0.12/1.0* horiz 0.00/0.0 (wheel)
event6   POINTER_SCROLL_WHEEL    +3008.500s	vert 0.12/1.0* horiz 0.00/0.0 (wheel)
...

@diggit
Copy link

diggit commented Aug 22, 2024

@evan-goode I can confirm this libinput behavior, it's same with non QMK device.

@IsaacElenbaas
Copy link
Contributor

IsaacElenbaas commented Aug 23, 2024

@evan-goode I jinxed it by invoking the hardcoded deadzones 😭
Here's a bash script to patch libinput if you don't want it to buffer the start of a scroll - just follow the prompts and hit q if meson brings up a menu. The script needs Pacman, only tested on Arch.
(E: this was also @filyp's issue above, I didn't realize that wasn't evdev output)

unsmoothen.txt

You only need to patch libinput, but I left the kernel patch in there if anyone wants to use it for trackpads/tablets like I do. You don't need to restart X like it says to have the scroll deadzone removed, I assume not Wayland either.

@eynsai
Copy link
Contributor

eynsai commented Aug 30, 2024

Update: I discovered that all you need to do to enable high-resolution scrolling is to modify the HID report descriptor.

None of the other stuff involving feature report datastructures, report IDs, responding to HID get and set, etc... none of it is actually necessary to get high-resolution scrolling. It seems like that stuff is only needed if you want the keyboard to know whether or not the OS supports high-resolution scrolling. To be honest, I have no idea what I'm doing when it comes to the USB stuff in QMK, so I'm not going to bother with adding that functionality.

Other than that... I cleaned things up, added some documentation and a couple example implementations for high-resolution drag scrolling, and opened a PR (my first ever 🤪). It branches off 0.26.0 so it should be much more up-to-date.

@jfedor2
Copy link

jfedor2 commented Aug 30, 2024

It seems like that stuff is only needed if you want the keyboard to know whether or not the OS supports high-resolution scrolling.

The keyboard needs to know that though.

Otherwise it will scroll 120x times too fast if the OS didn't enable high-resolution scrolling. (Or whatever it thinks the multiplier is.)

@eynsai
Copy link
Contributor

eynsai commented Aug 30, 2024

It seems like that stuff is only needed if you want the keyboard to know whether or not the OS supports high-resolution scrolling.

The keyboard needs to know that though.

Otherwise it will scroll 120x times too fast if the OS didn't enable high-resolution scrolling. (Or whatever it thinks the multiplier is.)

I totally agree, but unfortunately with the newest version of QMK, there seem to have been some changes to the way USB reports are handled... the code looks nothing like the stuff that I was hacking on, and to be honest I simply don't know how to work with any of it.

Also, my understanding is that implementing the ability for the keyboard to be aware of the OS's selection regarding high-resolution scrolling would need to be done independently for each platform, which is a ton of work, not to mention testing. I don't even have non-ChibiOS platforms to test with... It would also make this whole feature much more delicate and prone to breaking in the future. For my personal use, I'm OK with having the keyboard blindly assume that the OS has enabled high-resolution scrolling - maybe I'll have a key to toggle high-resolution scrolling on/off if it's really necessary. Of course, if anyone who's got more experience working with USB HID stuff can put together a better alternative, that would be even better.

@eynsai
Copy link
Contributor

eynsai commented Sep 1, 2024

Keyboard awareness of host OS's choice regarding hires scrolling has been added to ChibiOS, LUFA, and VUSB, although only ChibiOS has been tested.

@chrishoage
Copy link
Contributor

chrishoage commented Sep 2, 2024

I've been playing with the pull request this weekend and it works beautifully on both Linux and Windows.

I'm really struggling to get it to function on macOS. The best I can tell is that macOS just does not support high resolution scrolling in the same way that Linux and Windows does.

Can anyone confirm this?

Or is this user error on my part and there is something necessary needed in order to make it work?

Edit: To clarify, I'm certain that the OS is reporting that hires scroll is off, what is unclear to me is if there is a way to tell macOS that this is a "hires" mouse (beyond the hid descriptor from the report descriptor)

@eynsai
Copy link
Contributor

eynsai commented Sep 2, 2024

I'm really struggling to get it to function on macOS. The best I can tell is that macOS just does not support high resolution scrolling in the same way that Linux and Windows does.

I don't have any macOS devices, so I can't do any testing, but I'd be interested in learning more about what the issue is.

When POINTING_DEVICE_HIRES_SCROLL_ENABLE is defined, is there no difference in behavior compared to when it's undefined? Or is there weird/different/erroneous behavior?

Also, if you'd be willing to do a quick test: with POINTING_DEVICE_HIRES_SCROLL_ENABLE defined and the keyboard connected to macOS, what does is_hires_scroll_on() return? (I think this function can be used by including quantum.h.)

@chrishoage
Copy link
Contributor

Also, if you'd be willing to do a quick test: with POINTING_DEVICE_HIRES_SCROLL_ENABLE defined and the keyboard connected to macOS, what does is_hires_scroll_on() return? (I think this function can be used by including quantum.h.)

Sorry, I realized after I wrote my message that it was ambiguous. I edited my comment right before you commented.

To summarize: The os does not report "hires_scroll_on". My question is if there is something more that is required on macOS in order to enable this? (Or if it is just one more thing apple chooses not to implement)

@eynsai
Copy link
Contributor

eynsai commented Sep 2, 2024

To summarize: The os does not report "hires_scroll_on". My question is if there is something more that is required on macOS in order to enable this? (Or if it is just one more thing apple chooses not to implement)

I'm not 100% sure, but my guess is that it's just Apple not playing nice. If is_hires_scroll_on() is returning false, that means either (1) the OS is not sending resolution multiplier feature reports at all or (2) the OS is sending resolution multiplier feature reports that select the non-hires mode.

I don't have any experience using macOS, but my gut feeling is that this isn't the kind of thing that Apple would let users tinker with via a setting...

I'm not sure if there's third-party software that might be able to fix things - I've seen MOS mentioned in a few places. They claim to offer "smooth scrolling" but it seems like they use that term to refer to interpolation of inputs from a normal scroll wheel. But it also seems like there are some other settings provided - maybe it could help?

@chrishoage
Copy link
Contributor

I don't have any experience using macOS

I'd like to be clear my post wasn't directed at you specifically, but more anyone in this thread (or coming from google in the future) had any ideas.

I do greatly appreciate your help!

I'm not sure if there's third-party software that might be able to fix things - I've seen MOS mentioned in a few places.

I have tried:

  • mos
    • Offers "smooth scrolling" not "hires" scrolling. E.g. animates between scroll values smoothly
  • BetterMouse
    • Does appear to support "hires" scrolling, but only for specific mice (e.g. Logitech MX mice but I don't have one of these to understand how it actually behaves).
  • SteerMouse
    • Seemed the most promising at first as it offered the ability to set fractional scroll units, but this broke many applications (or at least VS Code, stopped trying after that one).

At this point my assumption is that qmk may need a driver (or something similar, in the way that BetterMouse may work) in order to get this behavior.

All these applications just offer "smoothing/animation" over the "by-line" scroll wheel events, which is distinct from the hires scrolling Windows and Linux offers.

My work is making me switch away from Linux to macOS and I'm remembering all the reasons I ditched it 5 years ago.

@eynsai
Copy link
Contributor

eynsai commented Sep 3, 2024

@chrishoage By the way, what platform (chibiOS, LUFA, VUSB) did you test? Thanks!

@chrishoage
Copy link
Contributor

chibiOS on a Ploopy Adept

@eynsai
Copy link
Contributor

eynsai commented Sep 4, 2024

I took a look at the latest IOHIDFamily from apple. I was a bit confused - some parts of the code, like IOHIDPointing, seem to support a resolution for the wheel, while other parts, like IOHIDPointingDevice don't. Not sure what to make of it.

Anyways, my current PR implements SetRequest (where the host tells the keyboard what the resolution multiplier is) but not GetRequest (where the keyboard tells the host what the resolution multiplier is). Maybe if I can implement that, it would make things work on macOS? But I'm kind of intimidated by the prospect of modifying the code that handles this stuff - it seems kind of hard to refactor, especially since QMK, to the best of my knowledge, didn't send or receive feature reports at all prior to this PR - only input and output reports.

@justinjradi
Copy link

Anyways, my current PR implements SetRequest (where the host tells the keyboard what the resolution multiplier is) but not GetRequest (where the keyboard tells the host what the resolution multiplier is). Maybe if I can implement that, it would make things work on macOS? But I'm kind of intimidated by the prospect of modifying the code that handles this stuff - it seems kind of hard to refactor, especially since QMK, to the best of my knowledge, didn't send or receive feature reports at all prior to this PR - only input and output reports.

I think that george-norton started implementing getting/setting feature reports in https://github.com/george-norton/qmk_firmware/tree/multitouch_experiment (see #23243) if that's of any help. I should have clarified that the get_report stuff I was trying was just based soley off of my observations of the behavior of a Windows host. However I'm still confused and maybe just misinterpreted the packets since it looks like you've been able to get things working without it.

I wish I were able to see the report descriptor of a magic mouse and/or the traffic between a magic mouse and a Mac to see how viewport navigation is implemented. However, I don't own a Mac either.

@chrishoage
Copy link
Contributor

But I'm kind of intimidated by the prospect of modifying the code that handles this stuff - it seems kind of hard to refactor, especially since QMK, to the best of my knowledge, didn't send or receive feature reports at all prior to this PR - only input and output reports.

I don't think the lack of macOS support should hold up the open PR, it is great as is, and any improvements to macOS can be made later.

@eynsai
Copy link
Contributor

eynsai commented Sep 5, 2024

@chrishoage If you end up having some time to do some testing, would you be able to try the following?

  1. I added a bodge that should enable the keyboard to respond to HID_REQ_GetReport. You can find this on my develop-hires-scrolling-macos-fix branch. This might fix things for macOS...?
  2. If (1) doesn't work: On my develop-hires-scrolling branch, try setting POINTING_DEVICE_HIRES_SCROLL_EXPONENT and seeing if that does anything on macOS. The "generic mouse descriptor" in apple's IOHIDPointingDevice has an unit exponent, so maybe this does something?

@chrishoage
Copy link
Contributor

If (1) doesn't work: On my develop-hires-scrolling branch, try setting POINTING_DEVICE_HIRES_SCROLL_EXPONENT and seeing if that does anything on macOS. The "generic mouse descriptor" in apple's IOHIDPointingDevice has an unit exponent, so maybe this does something?

Actually I had to add POINTING_DEVICE_HIRES_SCROLL_EXPONENT before any of this as when I didn't I get a compile error.

When I compile with out it I get this error

Compiling: tmk_core/protocol/usb_descriptor.c                                                      In file included from tmk_core/protocol/chibios/lufa_utils/LUFA/Drivers/USB/USB.h:38,
                 from tmk_core/protocol/usb_descriptor.h:46,
                 from tmk_core/protocol/usb_descriptor.c:41:
tmk_core/protocol/usb_descriptor.c:167:44: error: 'POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER' undeclared here (not in a function); did you mean 'POINTING_DEVICE_HIRES_SCROLL_ENABLE'?
  167 |                 HID_RI_PHYSICAL_MAXIMUM(8, POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER),
      |                                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:67:76: note: in definition of macro '_HID_RI_ENCODE_8'
   67 |                         #define _HID_RI_ENCODE_8(Data)                  , (Data & 0xFF)
      |                                                                            ^~~~
tmk_core/protocol/chibios/lufa_utils/LUFA/Drivers/USB/USB.h:22:31: note: in expansion of macro 'CONCAT'
   22 | #define CONCAT_EXPANDED(x, y) CONCAT(x, y)
      |                               ^~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:70:73: note: in expansion of macro 'CONCAT_EXPANDED'
   70 |                         #define _HID_RI_ENCODE(DataBits, ...)           CONCAT_EXPANDED(_HID_RI_ENCODE_, DataBits(__VA_ARGS__))
      |                                                                         ^~~~~~~~~~~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:72:115: note: in expansion of macro '_HID_RI_ENCODE'
   72 |                         #define _HID_RI_ENTRY(Type, Tag, DataBits, ...) (Type | Tag | HID_RI_DATA_BITS(DataBits)) _HID_RI_ENCODE(DataBits, (__VA_ARGS__))
      |                                                                                                                   ^~~~~~~~~~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:110:73: note: in expansion of macro '_HID_RI_ENTRY'
  110 |                         #define HID_RI_PHYSICAL_MAXIMUM(DataBits, ...)  _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x40, DataBits, __VA_ARGS__)
      |                                                                         ^~~~~~~~~~~~~
tmk_core/protocol/usb_descriptor.c:167:17: note: in expansion of macro 'HID_RI_PHYSICAL_MAXIMUM'
  167 |                 HID_RI_PHYSICAL_MAXIMUM(8, POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER),
      |                 ^~~~~~~~~~~~~~~~~~~~~~~
tmk_core/protocol/usb_descriptor.c:168:41: error: 'POINTING_DEVICE_HIRES_SCROLL_EXPONENT' undeclared here (not in a function); did you mean 'POINTING_DEVICE_HIRES_SCROLL_ENABLE'?
  168 |                 HID_RI_UNIT_EXPONENT(8, POINTING_DEVICE_HIRES_SCROLL_EXPONENT),
      |                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:67:76: note: in definition of macro '_HID_RI_ENCODE_8'
   67 |                         #define _HID_RI_ENCODE_8(Data)                  , (Data & 0xFF)
      |                                                                            ^~~~
tmk_core/protocol/chibios/lufa_utils/LUFA/Drivers/USB/USB.h:22:31: note: in expansion of macro 'CONCAT'
   22 | #define CONCAT_EXPANDED(x, y) CONCAT(x, y)
      |                               ^~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:70:73: note: in expansion of macro 'CONCAT_EXPANDED'
   70 |                         #define _HID_RI_ENCODE(DataBits, ...)           CONCAT_EXPANDED(_HID_RI_ENCODE_, DataBits(__VA_ARGS__))
      |                                                                         ^~~~~~~~~~~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:72:115: note: in expansion of macro '_HID_RI_ENCODE'
   72 |                         #define _HID_RI_ENTRY(Type, Tag, DataBits, ...) (Type | Tag | HID_RI_DATA_BITS(DataBits)) _HID_RI_ENCODE(DataBits, (__VA_ARGS__))
      |                                                                                                                   ^~~~~~~~~~~~~~
./lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h:111:73: note: in expansion of macro '_HID_RI_ENTRY'
  111 |                         #define HID_RI_UNIT_EXPONENT(DataBits, ...)     _HID_RI_ENTRY(HID_RI_TYPE_GLOBAL, 0x50, DataBits, __VA_ARGS__)
      |                                                                         ^~~~~~~~~~~~~
tmk_core/protocol/usb_descriptor.c:168:17: note: in expansion of macro 'HID_RI_UNIT_EXPONENT'
  168 |                 HID_RI_UNIT_EXPONENT(8, POINTING_DEVICE_HIRES_SCROLL_EXPONENT),
      |                 ^~~~~~~~~~~~~~~~~~~~
 [ERRORS]
 |
 |
 |
make: *** [builddefs/common_rules.mk:373: .build/obj_ploopyco_madromys_rev1_001_chrishoage/usb_descriptor.o] Error 1

The only way for me to get it to compile has been

#define POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER 120
#define POINTING_DEVICE_HIRES_SCROLL_EXPONENT 1 

Omitting both lead to the error above.

I added a bodge that should enable the keyboard to respond to HID_REQ_GetReport. You can find this on my develop-hires-scrolling-macos-fix branch. This might fix things for macOS...?

I'll cherry pick this to my scratch branch I've been hacking on things and try it out!

@eynsai
Copy link
Contributor

eynsai commented Sep 5, 2024

Regarding the undefined macro errors - I realized that I put the preprocessor directives for the default values of those macros in the wrong .h file. The fix for this is located in commit 225fc629926a164a617ebd098ab3d612f16c2cf2, which has been applied to the most up-to-date versions of both my develop-hires-scrolling and develop-hires-scrolling-macos-fix branches.

@chrishoage
Copy link
Contributor

The best I can tell develop-hires-scrolling-macos-fix regressed all hires scrolling.

Please forgive my testing methodology, I'm hesitant to install qmk on my work computer in order to use qmk console

In ploopyco.c I've taken your hires dragscroll example and done this (with hires_scroll_task_kb being your dragscroll example with small modifications and drag_scroll_task_kb being the original ploopy dragscroll)

report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
    if (is_drag_scroll) {
        if (is_hires_scroll_on()) {
            return hires_scroll_task_kb(mouse_report);
        } else {
            // return drag_scroll_task_kb(mouse_report);
        }
    }

    return pointing_device_task_user(mouse_report);
}

with develop-hires-scrolling-macos-fix and the fallback dragscroll I get no dragscroll on Linux or macOS (don't have the chance to test windows today)

with a fresh pull of develop-hires-scrolling and the above code I get dragscroll on Linux (indicating is_hires_scroll_on) and no dragscroll on macos (indicating is_hires_scroll_on is returning false)

I'm happy to test anything further you wish!

@eynsai
Copy link
Contributor

eynsai commented Sep 5, 2024

I was able to replicate the issue on Windows. I'm not sure how that slipped past me - I think I failed to flash the keyboard I was testing with, but thought I flashed it...

Anyways, I have rewritten history on the develop-hires-scrolling-macos-fix branch on my fork. The new bodge accomplishes the same thing as the earlier attempt (implement code to respond to HID_REQ_GetRequest for the wheel resolution feature report, so we can see if that's what macOS wants from us). But this time, I've properly confirmed that it works, at least on Windows.

However, it also only works with ChibiOS devices where MOUSE_SHARED_EP is set.

If that's the case for your device, I'd really appreciate if you could give it a try when you get a chance.

@chrishoage
Copy link
Contributor

I have done a fresh pull of develop-hires-scrolling-macos-fix and set MOUSE_SHARED_EP = yes in my rules.mk file and unfortunately is_hires_scroll_on still reports false (using the testing methodology I outlined in my previous comment) in macOS. It continues to work normally on Linux however.

I also confirmed I was using the correct code by setting MOUSE_SHARED_EP = no and the mouse no longer functioned.

Perhaps it's really as simple as apple just don't fully implement HID standards?

@eynsai
Copy link
Contributor

eynsai commented Sep 5, 2024

Thanks a lot for helping me test this.

This test illustrates a few interesting things about USB HID (I'd imagine that this is common knowledge to those who professionally implement this stuff, but it's interesting to me at least.) If I got anything wrong, please correct me!

Preliminary: feature reports are bidirectional and can be sent both ways between the device and computer. In the case of hires scrolling, feature reports are used to communicate regarding whether hires scrolling is used or not.

When a HID descriptor uses a resolution multiplier, but doesn't assign that resolution multiplier its own report ID, then the computer seems to assume that it is free to select whatever value it wants. In the case of hires scroll on Windows and Linux, it selects 1 (on). In the case of hires scroll on macOS, it selects 0 (off). The computer does not request a feature report from the device. But it still sends feature reports to the device to let it know what it has selected.

This behavior makes sense. The conputer specifies what report it is requesting from the device via the report ID, so if the resolution multiplier feature report doesn't have its own report ID, then the device has no way to disambiguate between the computer requesting a mouse input report or a resolution multiplier feature report. So it makes sense that the computer just never requests a resolution multiplier feature report, since it has no way to.

When the resolution multiplier is given its own report ID (independent of the mouse/shared report ID), the computer behaves differently, and more bizzarely. The computer, upon connecting to the device, requests a resolution multiplier feature report from the device. The computer behaves differently depending on whether or not the request is handled properly. If the request is not handled properly and the computer doesn't receive a resolution multiplier feature report back, after a certain time (timeout?number of attempts?) the computer stops trying and defaults to a value of 0. This is what you experienced with my bad code yesterday - I gave the resolution multiplier feature report its own report ID, but I wasn't handling the computer's HID_REQ_GetRequest properly. You may have experienced a bit of irresponsiveness in the mouse when initially connecting to the computer - this is the computer requesting a resolution multiplier feature report, and not getting one back. Then, after the computer gives up, the mouse starts working again, albiet without hires scrolling. This behavior also makes sense.

But when the request is handled properly by the keyboard... The computer ignores the actual contents of the resolution multiplier feature report the keyboard sends, and still chooses whatever it wants? I don't understand why I'm seeing this behavior.

Anyways, all of that info is kind of irrelevant and only provided in case someone else decides to try improving things... responding to HID_REQ_GetRequest was the last thing I could think of to make things work on macOS, so unfortunately I'm stumped.

As a side note, what kind of Linux are you testing with? I have not been able to get smooth scrolling working on my Ubuntu computer, but maybe I'm using an outdated version?

@chrishoage
Copy link
Contributor

chrishoage commented Sep 6, 2024

responding to HID_REQ_GetRequest was the last thing I could think of to make things work on macOS, so unfortunately I'm stumped.

100% okay thank you for putting in a solid attempt. macOS is stupid and I think this work is great on Linux and Windows - still worth it with those alone!

As a side note, what kind of Linux are you testing with? I have not been able to get smooth scrolling working on my Ubuntu computer, but maybe I'm using an outdated version?

I'm using arch, I also applied the patch from this comment #17585 (comment)

With out it I was seeing the initial "jump" in values when I began scrolling, but after that scrolling was hires

@rightaditya
Copy link

Hey, just wanted to pipe in with some experience getting high-resolution scrolling working for a non-QMK (but also open-source) keyboard. We've also had mixed experience with Linux, with at least one person finding no change. I don't (yet) have any idea what might be behind this difference, but I figured it'd be useful to know that it's also being encountered elsewhere with a completely different code base. And it seems this is true for macOS as well... @eynsai's comment above might have helped narrow down the issue for macOS, though it doesn't explain why one person has reported it working while another reported otherwise in the case of my patched firmware.

Regarding the hypothesized behaviour regarding report IDs, I don't remember seeing anything like this when I was looking through the kernel's source code. From memory, it just instructs the HID device to enable the scroll multiplier if it sees the feature in the device report. I actually think there's also a minor bug in how it handles this case, compared both against what makes sense from reading through the relevant portions of the HID specs and what Windows does, but this is my first foray into USB anything so someone who does this more regularly will have a more reliable assessment than mine.

In case it's useful to anyone on Arch or an Arch-derived distro, I recently set up an AUR package for a patched libinput. It has the same effect as @IsaacElenbaas's patch (for libinput only).

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

No branches or pull requests