DIY蓝牙键盘(1) - 理解 键盘报文

DIY蓝牙键盘(1) - 理解键盘报文

1. 键盘报文体验

一个键盘对于用户的体验是,用户按按键A他能看到字母A会在主机上显示出来。那这是如何实现的?

其实很简单,只要键盘发送下面的两个报文给主机,字母A就能在主机上显示出来。

(1)表1:字母A按下的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x040x000x000x00

(2)表2:字母A松开的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

报文的原则很简单,就是它把字母A所以对应的usage发给主机,主机就能显示出字母A. 以上表1按下报文Byte 1的值就是字母A的usage, 这个在USB官网的HID usage table(https://usb.org/sites/default/files/hut1_22.pdf)里面有定义。因为这个是USB标准所定义的,现在所有的操作系统都会认识这个usage, 于是主机会把0x04翻译成字母A.

有人要问了,那看起来只要发一个报文就可以输出A了,为什么还要再发一个松开的报文?

大家在用键盘的时候应该有这个体验,我们要输入一个字母A, 会按下A键然后松开。如果你一直按着字母A, 那么在主机上会看到一直会有字母A输出,下到你松开按键A.

当键盘只给主机发送一个A键盘按下的报文(表1),那么主机会一直输出字母A,这自然不是我们想到的。因此我们在发送完按下的报文后,还要发送松开的报文告诉主机说按键已经松开了。表2中把Byte 1的值改为0x00就是告诉主机按键已松开。

2. 按键实验

我们有了之上的知识后,那么比如我现在想要输入其他的字母要怎么做?

第一步我们要找到HID usage table(https://usb.org/sites/default/files/hut1_22.pdf),然后找到其他字母对应的usage并发出去。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UoLjMqi3-1631431089485)(C:\Users\86180\AppData\Roaming\Typora\typora-user-images\image-20210912112932516.png)]

上面我截取了一段键盘按键的usage, N的usage为0x11, i的usage为0x0C, c的usage为0x06, e的usage为0x08. 所以如果我要让主机输出单词Nice, 键盘必须要发出下面4组报文(report).

(1)发送N的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x110x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

(2)发送i的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x0C0x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

(3)发送c的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x060x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

(4)发送e的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x080x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

以此类推,我们查找到26个字母对应的usage, 并让键盘发出去,就可以让主机输出26个字母出来。

3. 报文格式解析

细心的同学可能会有个疑问:我用一个字节就可以完成26个字母的发送,还要其他4个字节来做什么?

第一个字节Byte 0下面会讲到,这里先跳过。 第2到第5个字母的地位是等同的。也就是说发送按键A,下面的4种方式的效果是一样的。

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x040x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x040x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x040x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x04

可能大家还是蒙的,你说这么多还是没有解释原因呀。现在解释正式开始。

上面说的所有情况都是用户一个按键一个按键按住松开的情况,那如果我4个按键一起按住一起松开,那键盘该怎么发送报文?

还是以Nice这个单词为例,假如我同时按住Nice然后松开,键盘应该发送如下的报文。

(1) 4个按键按住的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x110x0C0x060x08

(2) 4个按键松开的报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

可能有人要说了,如果我有同时按键10个按键的情况,那这4个字节不够用看呀,怎么办呢?其实也很简单,你只要把报文扩展为11个字节就可以了,下面两个报文就是同时输出: ABCDEFGHIJ的例子.

Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7Byte 8Byte 9Byte 10
0x000x040x050x060x070x080x090x0A0x0B0x0C0x0D
Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7Byte 8Byte 9Byte 10
0x000x000x000x000x000x000x000x000x000x000x00

4. Qwerty Key vs Modifier Key

在继续往讲之前,先来认识一下qwerty key和modifier key这两个概念。

上面介绍的26个字母的按键,都属于qwerty key. 这个qwerty这个词,你看一下手头键盘的第一行字母的排列,是不是觉得创造这个词的人很偷懒。

那什么是modifier key呢?“Ctrl”、“Alt”、“Shift”、"Win"这些按键统称为modifier key. 除了这些按键,键盘上的其他按键都称为qwerty key.

5. Modifier报文格式

上面留了个悬念,就是没有解释byte 0的作用。其实byte 0就是用来表示modifier按键的。 我们希望的Modifier报文的格式如下:

bit 7bit 6bit 5bit 4bit 3bit 2bit 1bit 0
R WinR ShiftR AltR CtrlL WinL ShiftL AltL Ctrl

对于一个全键盘会有左右边的modifier,因此我们定义byte 0的高4bit表示右边的modifier, 低4bit表示左边的modifier.

有了报文格式之后,我们就可以尝试来发一下modifier的报文。比如我们要发送左边的Ctrl,那应该发:

Byte 0Byte 1Byte 2Byte 3Byte 4
0x010x000x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

几个modifier的组合应该怎么发呢?比如: L Ctrl + L Alt + R Win

Byte 0Byte 1Byte 2Byte 3Byte 4
0x830x000x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

6. 组合按键报文

我们现在来看看,qwerty key和modifier key的组合。比如程序员经常使用的组合键:Ctrl + C, Ctrl + V.

(1) Ctrl + C 报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x010x060x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

(2) Ctrl + V 报文

Byte 0Byte 1Byte 2Byte 3Byte 4
0x010x190x000x000x00
Byte 0Byte 1Byte 2Byte 3Byte 4
0x000x000x000x000x00

7. 总结

这篇主要讲了键盘报文的分类与格式,以及如何根据要求发送相应的报文,让主机输出相应的qwerty key和modifier key.

大家应该会接着问,那主机为什么知道我这些报文的格式?那肯定是主机要提前知道我们发的报文的格式,那么问题就变成了:在发送报文前我们要怎么通知主机,让它知道我们报文的格式。

| 0x00 | 0x00 | 0x00 |

7. 总结

这篇主要讲了键盘报文的分类与格式,以及如何根据要求发送相应的报文,让主机输出相应的qwerty key和modifier key.

大家应该会接着问,那主机为什么知道我这些报文的格式?那肯定是主机要提前知道我们发的报文的格式,那么问题就变成了:在发送报文前我们要怎么通知主机,让它知道我们报文的格式。

我们下次再继。。。。。。

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ASN.1(Abstract Syntax Notation One)是一种用于表示抽象语法的标准化语言,它可以用于描述各种数据结构和通信协议的抽象语法。在通信协议中,ASN.1通常用于定义消息的结构和内容。 ASN.1使用一种类似于树形结构的方式来描述数据结构。数据结构由一个或多个成员组成,每个成员都有一个类型和一个唯一的标识符。这些成员按照特定的顺序排列,以形成一个数据结构。 在ASN.1中,报文结构可以通过定义数据类型和成员来体现。每个数据类型都有一个唯一的标识符和一个结构定义,该结构定义描述了该数据类型的成员和成员的类型。通过定义这些数据类型和成员,可以构建出整个报文的结构。 例如,一个简单的ASN.1报文结构可以如下所示: ``` MyMessage ::= SEQUENCE { header Header, body Body, signature OCTET STRING } Header ::= SEQUENCE { version INTEGER, timestamp GeneralizedTime } Body ::= CHOICE { message TextMessage, file FileMessage } TextMessage ::= SEQUENCE { from IA5String, to IA5String, text UTF8String } FileMessage ::= SEQUENCE { from IA5String, to IA5String, filename UTF8String, filedata OCTET STRING } ``` 在这个例子中,我们定义了一个名为MyMessage的数据类型,它由一个Header成员、一个Body成员和一个signature成员组成。Header和Body都是由SEQUENCE类型定义的数据类型,它们分别包含了各自的成员。Body成员是一个CHOICE类型的数据类型,表示它可以是TextMessage或FileMessage类型中的任意一种。每个具体的数据类型都有自己的成员和成员的类型,以此来描述整个报文的结构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值