Skip to content

USB: NKRO

hasu@tmk edited this page Jun 27, 2021 · 9 revisions

Keyboard Test Tool

EK Switch Hitter

https://web.archive.org/web/20190428204254/https://www.elitekeyboards.com/switchhitter.php

AquaKeyTest

https://geekhack.org/index.php?topic=34670.0

usbhid-dump

https://github.com/DIGImend/usbhid-dump

You can see report data in stream mode of usbhiddump.

$ sudo usbhid-dump -d feed:caaa -es                                                                                   
Starting dumping interrupt transfer stream                                                                            
with 1 minute timeout.                                                                                                
                                                                                                                      
005:091:003:STREAM             1624765630.955897
 00 10 00 40 00 00 00 00 00 00 00 00 00 00 00 00           
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00           
                                                           
005:091:003:STREAM             1624765630.970874           
 00 90 00 40 00 00 00 00 00 00 00 00 00 00 00 00           
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                             
005:091:003:STREAM             1624765631.054870           
 00 90 40 40 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

TMK USB NKRO

MEMO

https://github.com/tmk/tmk_keyboard/blob/1a02ebcc612e9a9c0d87e02295c7258de3a70ccc/tmk_core/doc/USB_NKRO.txt

Issue

NKRO doesn't work with BIOS/UEFI

https://github.com/tmk/tmk_keyboard/issues/475

Linux problem

This is really good writeup of this issue and the commit fixed it at Dec 29, 2014. Current Linux(4.0 and up ?) doesn't have this issue.

https://github.com/torvalds/linux/commit/6ce901eb61aa30ba8565c62049ee80c90728ef14 https://github.com/torvalds/linux/commit/8e7b341037db1835ee6eea64663013cbfcf33575#diff-f35f6b78ead6796aeaf38a7414178d43

HID usage Backslash(0x31) and Non-US Hash(0x32) are translated into one Linux internal keycode(43) in Linux kernel, also Delete(0x4C), Clear(0x9C) and Keypad Clear(0xD8) are translated into one keycode(111). Those keys can't be distinguished each other on Linux input system by design(not bug), this fact itself is not problem. The problem is Linux cannot handle event of those keys in NKRO report correctly.

https://github.com/tmk/tmk_keyboard/issues/117#issuecomment-51674009

Some keyboard firmwares like Soarer's, kiibohd and keyboardio use tricky keyboard report to work around this problem.

Soarer's Converter USB Descriptor

The trick removes the 'Non-US Hash' and 'Clear' from its report to prevent Linux bug, but this can cause new issue.

https://github.com/keyboardio/Kaleidoscope/issues/273

As for TMK just use 6KRO if you have this problem with NKRO.

Windows problem

Windows had weird problem with custom keyboard report other than boot keyboard(6KRO) report.

https://github.com/tmk/tmk_keyboard/blob/1a02ebcc612e9a9c0d87e02295c7258de3a70ccc/tmk_core/doc/USB_NKRO.txt#L132

It seems Microsoft fixed it and Windows has no problem with NKRO report as of today.(2017/12/31)

The good news is that we reported the bug, and it has been identified and corrected, and the fix should be available in a future Windows update. - Dec 5, 2010

http://forums.anandtech.com/showpost.php?p=30873364&postcount=17

USB NKRO Descriptor

TMK/LUFA

https://github.com/tmk/tmk_keyboard/blob/feebc2356304ef45ed12924673bd09ae20acb113/tmk_core/protocol/lufa/descriptor.c#L190-L223

const USB_Descriptor_HIDReport_Datatype_t PROGMEM NKROReport[] =
{
    HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
    HID_RI_USAGE(8, 0x06), /* Keyboard */
    HID_RI_COLLECTION(8, 0x01), /* Application */
        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
        HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
        HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
        HID_RI_REPORT_COUNT(8, 0x08),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),

        HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
        HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
        HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
        HID_RI_REPORT_COUNT(8, 0x05),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
        HID_RI_REPORT_COUNT(8, 0x01),
        HID_RI_REPORT_SIZE(8, 0x03),
        HID_RI_OUTPUT(8, HID_IOF_CONSTANT),

        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
        HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
        HID_RI_USAGE_MAXIMUM(8, (NKRO_EPSIZE-1)*8-1), /* Keyboard Right GUI */
        HID_RI_LOGICAL_MINIMUM(8, 0x00),
        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
        HID_RI_REPORT_COUNT(8, (NKRO_EPSIZE-1)*8),
        HID_RI_REPORT_SIZE(8, 0x01),
        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
    HID_RI_END_COLLECTION(0),
}

Soarer's Converter

Soarer's Converter USB Descriptor

NKRO/6KRO trick

I watched HID reports from soarer's with usbhid-dump on Linux(or in report mode) the converter always sends two reports from interface 0(boot) and 2(NKRO) at same time. Interface0(boot keyboard) sends reports in boot protocol format(6KRO). Because report descriptor of interface0 declares Input data as "Constant", in the result OS ignores reports from this interface and uses only NKRO report.

$ sudo usbhid-dump  -d16c0:047d -i0 -es -t10000
$ sudo usbhid-dump  -d16c0:047d -i2 -es -t10000

Decent host can read the report descriptor correctly, ignores Boot report and uses only NKRO report, while crappy host(or BIOS) cannot read the report descriptor, ignores NKRO report and uses only Boot report.

I didn't confirm but I guess the converter stops interface2(NKRO) when BIOS/UEFI requests boot mode.

It doesn't seem to have switching method between NKRO and Boot keyboard.

Also refer this: http://deskthority.net/workshop-f7/soarer-desparately-needed-t9322-30.html#p210886

In theory, the keyboard should come up in NKRO with an NKRO descriptor and advertise boot mode capability on ONE endpoint, the BIOS should request boot mode, and then the keyboard should switch to boot mode. However, some BIOSes assume that a keyboard that advertises boot mode actually is running in boot mode, and fail to request it (which is a safe assumption on 99.9% of keyboards, but violates the spec). If a BIOS follows the spec and requests that the boot mode endpoint switch to boot mode, I believe Soarer is shutting down the NKRO endpoint.

Then, per the spec, once the OS comes up and resets all USB devices, it'll parse all the descriptors. His boot mode endpoint intentionally doesn't have a descriptor (has Constant descriptor), because there is no way to reliably sense that there's a real OS here, but his NKRO endpoint has one, so the OS ignores everything coming from the boot mode endpoint (but it still has to be sent in case a BIOS sees boot mode capability and assumes it's good to go).

Quote from v1.11 changes:

Prevented debug and rawhid output when keyboard_protocol is not set (i.e. in BIOS mode).

Realforce RGB

Realforce RGB Descriptor

http://www.realforce.co.jp/en/products/realforce_rgb/

Interface0
    Boot keyboard + 6KRO report descriptor
        Modifiers 1byte + constant 1byte + keys 6 bytes = 8
    Endpoint 1IN
    PacketSize 8
    Interval    1
    
Interface1
    Multimeida
        ReportID=1 + consumer 1byte =2
        ReportID=2 + constant 1byte + NKRO keyboard 232bits(0-231[Right GUI]) = 31
        ReportID=3 + consumer 1byte =2
    Endpoint 2IN
    PakcetSize  32
    Interval    1

Interface2
    Vendor specific
        64byte report
    Endopoint 3IN/4OUT
    PakcetSize  64
    Interval    1

Use Boot keyboard interface until its report is full and NKRO keyboard interface is used only when Boot report is not enough. Modifiers is always registered with Boot report. No switching function between Boot and NKRO keyboard.

Modifiers don't affect on keys of NKRO keyboard interface with some OS such as MacOS?

Resources

Myths about USB NKRO and how USB HID works

https://www.devever.net/~hl/usbnkro

Clone this wiki locally