USB下无冲键盘的实现

我们都听过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的格式。。。不知道为什么要这么搞


可以看到选中的两行是由不同device发送的

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
  1. 配置描述符(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)
  2. 接口描述符(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 (没有关联的描述符字符串)
  3. 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字节)
  4. 端点描述符(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时按照这个规则给电脑发送就行了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,724评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,104评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,142评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,086评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,076评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,914评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,220评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,871评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,318评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,834评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,951评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,574评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,162评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,162评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,383评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,349评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,652评论 2 343

推荐阅读更多精彩内容