adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.06k stars 1.2k forks source link

Add support for multiple virtual keyboard devices for N-Key rollover #1439

Closed MostlyCoraGrace closed 3 years ago

MostlyCoraGrace commented 5 years ago

current support only allows for one keyboard device with 6 pressed keys. The gamer in me can and will press more than that on occasion. More keys = more better 😎

dhalbert commented 5 years ago

Do you have an example of a keyboard that transmits more than 6 pressed keys at once? All the USB HID keyboard descriptors I have seen do 6 keys max. I just checked a Logitech Gaming Keyboard, and it's also 6.

MostlyCoraGrace commented 5 years ago

Most of the info I have comes from open-source wikis, where they use many keyboard devices each sending 6 keys each: https://deskthority.net/wiki/Rollover,_blocking_and_ghosting#Interface-limited_NKRO

https://github.com/qmk/qmk_firmware/blob/995c3141a674a0311786cc713ea96d39330a9b48/docs/usb_nkro.txt My Corsair K95 RGB for instance creates many virtual devices for N-Key rollover. Here I have two screenshots, one with the K95 RGB unplugged, and one with it plugged in, and you can see more than one HID device show up: capture1

capture

dhalbert commented 3 years ago

This missive is interesting: https://www.devever.net/~hl/usbnkro.

The 6KRO limit is if the device is recognized as a boot keyboard only. So there are a couple of ways to achieve NKRO: one is to use a >6-key report descriptor, and another is to simulate multiple keyboards.

TinyUSB allocates the number of separate HID interfaces at compile time (also true for other devices, such as CDC). Currently we allocate only one. I will make this at least two to be able to support boot keyboards. But I don't think we need NKRO on boot keyboards..

Tagging @deshipu and @Red-M for interest.

Red-M commented 3 years ago

It would actually be very handy to have a way to assign a 6KRO for the first USB descriptor then another descriptor as an NKRO to allow for NKRO when inside an OS but to also allow for boot time control.

My current idea to cheat for NKRO was this: https://github.com/Red-M/RedPycoKeeb/blob/master/Firmware/lib/pycokeeb/basekeeb.py#L123-L149 (there is some implementation bugs with this and its missing a keycode to hid map to allow for release key reports being handled correctly)

Another thing to note is that the boot time 6KRO descriptor needs to be the first USB descriptor because otherwise the HID won't work at boot time.

Red-M commented 3 years ago

Actually that bit at the bottom of that post is exactly what we should try to get as it solves the issue of buggy BIOS implementations and silently allows for NKRO if the host supports it, which is perfect since nothing extra has to be handled by any HID use-case to "handle" HID interaction.

dhalbert commented 3 years ago

It would actually be very handy to have a way to assign a 6KRO for the first USB descriptor then another descriptor as an NKRO to allow for NKRO when inside an OS but to also allow for boot time control.

This will be possible. You will be able designate a keyboard (or mouse) descriptor as "boot", and it will mark it as a boot device. You could have a completely different keyboard report descriptor as the actual report descriptor (which would would be ignored in boot mode). So you could use the same interface for the boot-6KRO and the non-boot NKRO. I think that is one of the points in https://www.devever.net/~hl/usbnkro.

deshipu commented 3 years ago

I thought that the host is supposed to tell the device whether it expects a boot keyboard or not when the plug is connected?

dhalbert commented 3 years ago

I thought that the host is supposed to tell the device whether it expects a boot keyboard or not when the plug is connected?

The host sends a "Set_Protocol" command to switch to the boot protocol and the standard, implied descriptor. So I think you could still have an NKRO-style report descriptor, but also will need to support the standard descriptor if it's Set_Protocol to boot mode. I think this is implied by the spec and by the last few paragraphs in https://www.devever.net/~hl/usbnkro. If I am misinterpreting something let me know. I think we would need to have a CIrcuitPython keyboard driver that could query which protocol is in use and send reports appropriately if you wanted to support an NKRO report.

image

deshipu commented 3 years ago

That sounds right, thank you!

jepler commented 3 years ago

With dynamic USB descriptors (#4689) you can do things like this. In my experimentation, I successfully created a descriptor with NKRO which also worked in the BIOS boot menu of a Dell (https://emergent.unpythonic.net/01626210345 & https://emergent.unpythonic.net/01625944378). However, functioning as a boot keyboard (particcularly on macs) is still a problem (#1136).