我们都听过USB下键盘只能做6键无冲的说法,但是这种说法其实是错误的,最近在做一个键盘正好看了下这方面的东西,网上相关资料好像不多,我整理下放在这里。
USB下全键无冲
其实HID有两种协议,一种是boot protocol,一种是report protocol。系统在bios时只支持boot protocol,这种协议是固定的8byte构成,分别是ID、Modifiers和6个keycode,Modifiers就是功能按左右ctrl、shift之类的,剩下的keycode只能显示最多6个按键,多了就不行了,以前很多的键盘只支持最多按下6个按键是因为使用了这种协议。但是一旦进入到系统,就可以使用report protocol来发送案件信息,report protocol可以用descriptor来描述自己发送按键信息的规则。
手上几个键盘的解决方案
第一个
INFI75
infi75当按键少于6个(最多5个)的时候是用的boot protocol发送的,当大于等于6个的时候,会使用report protocol。
TMK/QMK
QMK使能NKRO后可以用shift+n来切换发送的协议
杜伽
杜伽的方案是虚拟出来好几个键盘来发送。。。这种操作也在知乎上看到过。不过很奇怪的是他每个键盘的report其实也不是boot protocol的格式。。。不知道为什么要这么搞
FL980V2
这个我也是没太看懂,我按下很多个按键但是好像发送的位数不太对。
descriptor
这里主要是三个部分
Device Descriptor
0x12 //bLenght
0x01 //bDescriptorType
0x00,0x02 //bcdUSB
0xef //bDeviceClass
0x02 //bDeviceSubClass
0x01 //bDeviceProtocol
0x40 //bMaxPacketSize0
0x3a,0x30 //idVendor
0x01,0x10 //idProduct
0x01,0x01 //bcdDevice
0x01 //iManufacturer
0x02 //iProduct
0x03 //iSerialNumber
0x01 //bNumConfigurations
- 0x12:长度(bLength)。描述符的长度
- 0x01:描述符类型(bDescriptorType)。代表这段数据属于设备描述符
- 0x00, 0x02:USB 版本号(bcdUSB)。代表USB2.0协议
- 0xef:设备类(bDeviceClass)。这是一个特定的类别代码。
- 0x02:设备子类(bDeviceSubClass)。这个字段的值也需要根据实际的设备类型来定。
- 0x01:设备协议(bDeviceProtocol)。同样,这个字段的值也需要根据实际的设备类型来定。
- 0x40:最大数据包大小(bMaxPacketSize0)。表示端点0的最大数据包大小,
- 0x3a, 0x30:供应商ID(idVendor)。由 USB Implementers Forum 分配的制造商标识符。
- 0x01, 0x10:产品ID(idProduct)。制造商分配的产品标识符。
- 0x01, 0x01:设备版本号(bcdDevice)。设备的发布版本号。
- 0x01:制造商描述符索引(iManufacturer)。如果制造商字符串描述符存在,则这个字段应该指向它。
- 0x02:产品描述符索引(iProduct)。如果产品字符串描述符存在,则这个字段应该指向它。
- 0x03:序列号描述符索引(iSerialNumber)。如果序列号字符串描述符存在,则这个字段应该指向它。
- 0x01:配置数量(bNumConfigurations)。表示设备的配置数量。
Configuration Descriptor
//配置描述符
0x09, //bLenght
0x02, //bDescriptorType
0x22,0x00, //wTotalLength
0x01, //bNumInterfaces
0x01, //bConfigurationValue
0x00, //iConfiguration
0xa0, //bmAttributes
0x32, //MaxPower
//接口描述符,键盘功能
0x09, //bLenght
0x04, //bDescriptorType
0x00, //bInterfaceNumber
0x00, //bAlternateSetting
0x01, //bNumbEndpoints
0x03, //bInterfaceClass
0x01, //bInterfaceSubClass
0x01, //bInterfaceProtocol
0x00, //iInterface
//HID类描述符
0x09, //bLenght
0x21, //bDescriptorType
0x11,0x01, //bcdHID
0x00, //bCountryCode
0x01, //bNumDescriptors
0x22, //bDescriptorType
0x43,0x00, //wDescriptorLength
//端点描述符
0x07, //bLenght
0x05, //bDescriptorType
0x81, //bEndpointAddres
0x03, //bmAttributes
0x40,0x00, //wMaxPacketSize
0x01 //bInterval
-
配置描述符(Configuration Descriptor):
- 长度(bLenght): 0x09 (9字节)
- 描述符类型(bDescriptorType): 0x02 (配置描述符)
- 总长度(wTotalLength): 0x0022 (整个descriptor有 34字节,小端)
- 接口数(bNumInterfaces): 0x01 (1接口)
- 配置值(bConfigurationValue): 0x01
- 配置描述符(iConfiguration): 0x00 (没有关联的描述符字符串)
- 配置特性(bmAttributes): 0xa0 (总线供电,支持远程唤醒)
- 最大功率(MaxPower): 0x32 (100mA,1代表2ma)
-
接口描述符(Interface Descriptor):
- 长度(bLenght): 0x09 (9字节)
- 描述符类型(bDescriptorType): 0x04 (接口描述符)
- 接口号(bInterfaceNumber): 0x00 (接口0)
- 替代设置(bAlternateSetting): 0x00
- 端点数(bNumbEndpoints): 0x01 (端点0以外的端点数1)
- 接口类(bInterfaceClass): 0x03 (HID)
- 接口子类(bInterfaceSubClass): 0x01 (1是 0否 支持BIOS)
- 接口协议(bInterfaceProtocol): 0x01 (00其他,01键盘,02鼠标)
- 接口(iInterface): 0x00 (没有关联的描述符字符串)
-
HID描述符(HID Descriptor):
- 长度(bLenght): 0x09 (9字节)
- 描述符类型(bDescriptorType): 0x21 (HID描述符)
- HID版本(bcdHID): 0x0111 (HID 1.11 小端)
- 国家代码(bCountryCode): 0x00 (没有特定的国家代码)
- HID描述符数(bNumDescriptors): 0x01
- 描述符类型(bDescriptorType): 0x22 (报告描述符)
- 描述符长度(wDescriptorLength): 0x0043 (67字节)
-
端点描述符(Endpoint Descriptor):
- 长度(bLenght): 0x07 (7字节)
- 描述符类型(bDescriptorType): 0x05 (端点描述符)
- 端点地址(bEndpointAddres): 0x81 (Bits 3…0是端点号,低速设备(Low-speed devices)最多拥有3个端点号(0–2),其他设备则最多拥有16个端点号(0–15)。,Bit 7是方向,OUT = 0 ,IN = 1,控制端点(control endpoints)忽略这个位。)
- 属性(bmAttributes): 0x03 (Bits 1…0表示传输类型,00b表示控制(control),01b表示等时(isochronous), 10b表示批量(bulk),11b表示中断(interrupt)。)
- 最大包长度(wMaxPacketSize):0x0040(64字节)
- 传输间隔(bInterval): 0x01(每帧传输)
HID报表描述符
最关键的是这里
05 01 // Usage Page (Generic Desktop),
09 06 // Usage (Keyboard),
a1 01 // Collection (Application),
85 01 // Report ID(01),
// bitmap of modifiers(功能按键)
05 07 // Usage Page (Keyboard),
19 e0 // Usage Minimum (Keyboard LeftControl),
29 e7 // Usage Maximum (Keyboard Right GUI),
15 00 // Logical Minimum (0),
25 01 // Logical Maximum (1),
95 08 // Report Count (8),
75 01 // Report Size (1),
81 02 // Input (Data, Variable, Absolute),
// LED output report
05 08 // Usage Page (LEDs)
19 01 // Usage Minimum (Num Lock 1)
29 05 // Usage Maximum (Kana 3)
95 05 // Report Count (5)
75 01 // Report Size (1)
91 02 // Output (Data,Var,Abs)
//凑齐LED 5bit后面的3个bit 为1byte
95 01 // Report Count (1)
75 03 // Report Size (3)
91 01 // Output (Cnst,Var,Abs)
// bitmap of keys(普通按键)
05 07 // Usage Page (Keyboard),
19 00 // Usage Minimum (0),
29 77 // Usage Maximum (119),
15 00 // Logical Minimum (0),
25 01 // Logical Maximum (1),
75 01 // Report Size (1),
95 78 // Report Count (120),
81 02 // Input (Data, Variable, Absolute),
c0 // End Collection
主要说明后面的report,会先发送1byte 的report ID,然后1byte的功能按键,然后1byte的LED,15byte的普通按键。然后每次发送report时按照这个规则给电脑发送就行了。