/*键盘发送给PC的数据每次8个字节
data0 data1 data2 data3 data4 data5 data6 data7
定义分别是:
**data0 --
|--bit0: Left Control是否按下,按下为1
|--bit1: Left Shift 是否按下,按下为1
|--bit2: Left Alt 是否按下,按下为1
|--bit3: Left GUI 是否按下,按下为1
|--bit4: Right Control是否按下,按下为1
|--bit5: Right Shift 是否按下,按下为1
|--bit6: Right Alt 是否按下,按下为1
|--bit7: Right GUI 是否按下,按下为1
data1 -- 保留
data2--data7 -- 普通按键**
refer to hid spec 8.3*/
看一下hid规范的键盘码-refer to hid usage table section 10
Table 12: Keyboard/Keypad Page
***Usage ID (Dec) Usage ID (Hex) Usage Name Ref: Typical AT-101 Position PC-AT Mac UNI X Boot
0 00 Reserved (no event indicated)9 N/A √ √ √ 4/101/104
1 01 Keyboard ErrorRollOver9 N/A √ √ √ 4/101/104
2 02 Keyboard POSTFail9 N/A √ √ √ 4/101/104
3 03 Keyboard ErrorUndefined9 N/A √ √ √ 4/101/104
4 04 Keyboard a and A4 31 √ √ √ 4/101/104
5 05 Keyboard b and B 50 √ √ √ 4/101/104
6 06 Keyboard c and C4 48 √ √ √ 4/101/104
7 07 Keyboard d and D 33 √ √ √ 4/101/104
8 08 Keyboard e and E 19 √ √ √ 4/101/104
9 09 Keyboard f and F 34 √ √ √ 4/101/104
10 0A Keyboard g and G 35 √ √ √ 4/101/104
11 0B Keyboard h and H 36 √ √ √ 4/101/104
12 0C Keyboard i and I 24 √ √ √ 4/101/104
13 0D Keyboard j and J 37 √ √ √ 4/101/104
14 0E Keyboard k and K 38 √ √ √ 4/101/104
15 0F Keyboard l and L 39 √ √ √ 4/101/104
16 10 Keyboard m and M4 52 √ √ √ 4/101/104
17 11 Keyboard n and N 51 √ √ √ 4/101/104
18 12 Keyboard o and O4 25 √ √ √ 4/101/104
19 13 Keyboard p and P4 26 √ √ √ 4/101/104
20 14 Keyboard q and Q4 17 √ √ √ 4/101/104
21 15 Keyboard r and R 20 √ √ √ 4/101/104
22 16 Keyboard s and S4 32 √ √ √ 4/101/104
23 17 Keyboard t and T 21 √ √ √ 4/101/104
24 18 Keyboard u and U 23 √ √ √ 4/101/104
25 19 Keyboard v and V 49 √ √ √ 4/101/104
26 1A Keyboard w and W4 18 √ √ √ 4/101/104
27 1B Keyboard x and X4 47 √ √ √ 4/101/104
28 1C Keyboard y and Y4 22 √ √ √ 4/101/104
29 1D Keyboard z and Z4 46 √ √ √ 4/101/104
30 1E Keyboard 1 and !4 2 √ √ √ 4/101/104
31 1F Keyboard 2 and @4 3 √ √ √ 4/101/104
32 20 Keyboard 3 and #4 4 √ √ √ 4/101/104
33 21 Keyboard 4 and $4 5 √ √ √ 4/101/104
34 22 Keyboard 5 and %4 6 √ √ √ 4/101/104
35 23 Keyboard 6 and ^4 7 √ √ √ 4/101/104
36 24 Keyboard 7 and &4 8 √ √ √ 4/101/104
37 25 Keyboard 8 and 4 9 √ √ √ 4/101/104
38 26 Keyboard 9 and (4 10 √ √ √ 4/101/104
39 27 Keyboard 0 and )4 11 √ √ √ 4/101/104
40 28 Keyboard Return (ENTER)5 43 √ √ √ 4/101/104
41 29 Keyboard ESCAPE 110 √ √ √ 4/101/104
42 2A Keyboard DELETE (Backspace)13 15 √ √ √ 4/101/104
43 2B Keyboard Tab 16 √ √ √ 4/101/104
44 2C Keyboard Spacebar 61 √ √ √ 4/101/104
45 2D Keyboard - and (underscore)4 12 √ √ √ 4/101/104
46 2E Keyboard = and +4 13 √ √ √ 4/101/104
47 2F Keyboard [ and {4 27 √ √ √ 4/101/104
48 30 Keyboard ] and }4 28 √ √ √ 4/101/104
49 31 Keyboard \ and | 29 √ √ √ 4/101/104
50 32 Keyboard Non-US # and ~2 42 √ √ √ 4/101/104
51 33 Keyboard ; and :4 40 √ √ √ 4/101/104
52 34 Keyboard ‘ and “4 41 √ √ √ 4/101/104
53 35 Keyboard Grave Accent and Tilde4 1 √ √ √ 4/101/104
54 36 Keyboard, and <4 53 √ √ √ 4/101/104
55 37 Keyboard . and >4 54 √ √ √ 4/101/104
56 38 Keyboard / and ?4 55 √ √ √ 4/101/104
57 39 Keyboard Caps Lock11 30 √ √ √ 4/101/104
58 3A Keyboard F1 112 √ √ √ 4/101/104
59 3B Keyboard F2 113 √ √ √ 4/101/104
60 3C Keyboard F3 114 √ √ √ 4/101/104
61 3D Keyboard F4 115 √ √ √ 4/101/104
62 3E Keyboard F5 116 √ √ √ 4/101/104
63 3F Keyboard F6 117 √ √ √ 4/101/104
64 40 Keyboard F7 118 √ √ √ 4/101/104
65 41 Keyboard F8 119 √ √ √ 4/101/104
66 42 Keyboard F9 120 √ √ √ 4/101/104
67 43 Keyboard F10 121 √ √ √ 4/101/104
68 44 Keyboard F11 122 √ √ √ 101/104
69 45 Keyboard F12 123 √ √ √ 101/104
70 46 Keyboard PrintScreen1 124 √ √ √ 101/104
71 47 Keyboard Scroll Lock11 125 √ √ √ 4/101/104
72 48 Keyboard Pause1 126 √ √ √ 101/104
73 49 Keyboard Insert1 75 √ √ √ 101/104
74 4A Keyboard Home1 80 √ √ √ 101/104
75 4B Keyboard PageUp1 85 √ √ √ 101/104
76 4C Keyboard Delete Forward1;14 76 √ √ √ 101/104
77 4D Keyboard End1 81 √ √ √ 101/104
78 4E Keyboard PageDown1 86 √ √ √ 101/104
79 4F Keyboard RightArrow1 89 √ √ √ 101/104
80 50 Keyboard LeftArrow1 79 √ √ √ 101/104
81 51 Keyboard DownArrow1 84 √ √ √ 101/104
82 52 Keyboard UpArrow1 83 √ √ √ 101/104
83 53 Keypad Num Lock and Clear11 90 √ √ √ 101/104
84 54 Keypad /1 95 √ √ √ 101/104
85 55 Keypad * 100 √ √ √ 4/101/104
86 56 Keypad - 105 √ √ √ 4/101/104
87 57 Keypad + 106 √ √ √ 4/101/104
88 58 Keypad ENTER5 108 √ √ √ 101/104
89 59 Keypad 1 and End 93 √ √ √ 4/101/104
90 5A Keypad 2 and Down Arrow 98 √ √ √ 4/101/104
91 5B Keypad 3 and PageDn 103 √ √ √ 4/101/104
92 5C Keypad 4 and Left Arrow 92 √ √ √ 4/101/104
93 5D Keypad 5 97 √ √ √ 4/101/104
94 5E Keypad 6 and Right Arrow 102 √ √ √ 4/101/104
95 5F Keypad 7 and Home 91 √ √ √ 4/101/104
96 60 Keypad 8 and Up Arrow 96 √ √ √ 4/101/104
97 61 Keypad 9 and PageUp 101 √ √ √ 4/101/104
98 62 Keypad 0 and Insert 99 √ √ √ 4/101/104
99 63 Keypad . and Delete 104 √ √ √ 4/101/104
100 64 Keyboard Non-US \ and |3;6 45 √ √ √ 4/101/104
101 65 Keyboard Application10 129 √ √ 104
102 66 Keyboard Power9 √ √
103 67 Keypad = √
104 68 Keyboard F13 √
105 69 Keyboard F14 √
106 6A Keyboard F15 √
107 6B Keyboard F16
108 6C Keyboard F17
109 6D Keyboard F18
110 6E Keyboard F19
111 6F Keyboard F20
112 70 Keyboard F21
113 71 Keyboard F22
114 72 Keyboard F23
115 73 Keyboard F24
116 74 Keyboard Execute √
117 75 Keyboard Help √
118 76 Keyboard Menu √
119 77 Keyboard Select √
120 78 Keyboard Stop √
121 79 Keyboard Again √
122 7A Keyboard Undo √
123 7B Keyboard Cut √
124 7C Keyboard Copy √
125 7D Keyboard Paste √
126 7E Keyboard Find √
127 7F Keyboard Mute √
128 80 Keyboard Volume Up √
129 81 Keyboard Volume Down √
130 82 Keyboard Locking Caps Lock12 √
131 83 Keyboard Locking Num Lock12 √
132 84 Keyboard Locking Scroll Lock12 √
133 85 Keypad Comma27 107
134 86 Keypad Equal Sign29
135 87 Keyboard International115,28 56
136 88 Keyboard International216
137 89 Keyboard International317
138 8A Keyboard International418
139 8B Keyboard International519
140 8C Keyboard International620
141 8D Keyboard International721
142 8E Keyboard International822
143 8F Keyboard International922
144 90 Keyboard LANG125
145 91 Keyboard LANG226
146 92 Keyboard LANG330
147 93 Keyboard LANG431
148 94 Keyboard LANG532
149 95 Keyboard LANG68
150 96 Keyboard LANG78
151 97 Keyboard LANG88
152 98 Keyboard LANG98
153 99 Keyboard Alternate Erase7
154 9A Keyboard SysReq/Attention1
155 9B Keyboard Cancel
156 9C Keyboard Clear
157 9D Keyboard Prior
158 9E Keyboard Return
159 9F Keyboard Separator
160 A0 Keyboard Out
161 A1 Keyboard Oper
162 A2 Keyboard Clear/Again
163 A3 Keyboard CrSel/Props
164 A4 Keyboard ExSel
165-175 A5-CF Reserved
176 B0 Keypad 00
177 B1 Keypad 000
178 B2 Thousands Separator 33
179 B3 Decimal Separator 33
180 B4 Currency Unit 34
181 B5 Currency Sub-unit 34
182 B6 Keypad (
183 B7 Keypad )
184 B8 Keypad {
185 B9 Keypad }
186 BA Keypad Tab
187 BB Keypad Backspace
188 BC Keypad A
189 BD Keypad B
190 BE Keypad C
191 BF Keypad D
192 C0 Keypad E
193 C1 Keypad F
194 C2 Keypad XOR
195 C3 Keypad ^
196 C4 Keypad %
197 C5 Keypad <
198 C6 Keypad >
199 C7 Keypad &
200 C8 Keypad &&
201 C9 Keypad |
202 CA Keypad ||
203 CB Keypad :
204 CC Keypad #
205 CD Keypad Space
206 CE Keypad @
207 CF Keypad !
208 D0 Keypad Memory Store
209 D1 Keypad Memory Recall
210 D2 Keypad Memory Clear
211 D3 Keypad Memory Add
212 D4 Keypad Memory Subtract
213 D5 Keypad Memory Multiply
214 D6 Keypad Memory Divide
215 D7 Keypad +/-
216 D8 Keypad Clear
217 D9 Keypad Clear Entry
218 DA Keypad Binary
219 DB Keypad Octal
220 DC Keypad Decimal
221 DD Keypad Hexadecimal
222-223 DE-DF Reserved
224 E0 Keyboard LeftControl 58 √ √ √ 4/101/104
225 E1 Keyboard LeftShift 44 √ √ √ 4/101/104
226 E2 Keyboard LeftAlt 60 √ √ √ 4/101/104
227 E3 Keyboard Left GUI10;23 127 √ √ √ 104
228 E4 Keyboard RightControl 64 √ √ √ 101/104
229 E5 Keyboard RightShift 57 √ √ √ 4/101/104
230 E6 Keyboard RightAlt 62 √ √ √ 101/104
231 E7 Keyboard Right GUI10;24 128 √ √ √ 104
232-65535 E8-FFFF Reserved
看看是怎么检测和上报按下释放事件的,在函数static void usb_kbd_irq(struct urb urb)
/检测修饰键/
/每次中断传输都会执行以下检查/
for (i = 0; i < 8; i++)
input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
/
new是kbd的成员,在usb_kbd_alloc_mem函数中分配8字节内存:kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma),
并且在中断urb初始化函数中usb_fill_int_urb(kbd->irq, dev, pipe, kbd->new, (maxp > 8 ? 8 : maxp), usb_kbd_irq, kbd, endpoint->bInterval);
指定new为urb的缓冲区,即从单片机端点里取得的数据会放在new指向的内存里面,最大为8字节
根据hid规范,从单片机获取的数据的首字节即new[0],其8位分别表示
new[0] –
|–bit0: Left Control是否按下,按下为1
|–bit1: Left Shift 是否按下,按下为1
|–bit2: Left Alt 是否按下,按下为1
|–bit3: Left GUI 是否按下,按下为1
|–bit4: Right Control是否按下,按下为1
|–bit5: Right Shift 是否按下,按下为1
|–bit6: Right Alt 是否按下,按下为1
|–bit7: Right GUI 是否按下,按下为1
(kbd->new[0] >> i) & 1 检测第i位是否为1,如果为1,则上报按键usb_kbd_keycode[i + 224]
例如,若Left Control键按下,则在首次循环中,(kbd->new[0] >> 0) & 1=1,所以上报usb_kbd_keycode[0 + 224],查上面usb_kbd_keycode数组可知,
usb_kbd_keycode[224]=29,即上报键值29
至于29到底是不是代表此键,可以查看输入子系统的键值定义,http://blog.csdn.net/songqqnew/article/details/6875502,发现有行
#define KEY_LEFTCTRL 29
其他类似…
可见通过input_report_key函数关联了3个按键表,总结一下
1.hid规范的键盘码:本页可查到。是设备和主机间的约定,比如上面的例子,板子上有Left Control键按下,单片机就要按hid规范令new[0].0=1,
主机获取到new[0].0=1则就会知道Left control键按下。又如对于鼠标按键,板子中键按下,单片机要按hid规范令data[0]=0x04,主机获取到data[0]=0x04,便知道鼠标的左键按下。当然,鼠标hid和键盘hid的数据格式和含义不一样。
2.input.h里的键盘码:http://blog.csdn.net/songqqnew/article/details/6875502。是input子系统里规定的某个按键按下要上报哪个数值。应该是input子系统和应用程序间的一个约定。
3.usb_kbd_keycode[256]:本页可查到。此数组为了操作方便,用数组下标和对应成员值将hid规范码和input规范码统一起来,对于某个按键
有usb_kbd_keycode[hid规范码]=input规范码
比如按键a:usb_kbd_keycode[4]=30,按键1:usb_kbd_keycode[0x1e]=2
*/
/每次中断传输都会执行以下检查/
for (i = 2; i < 8; i++) {
/根据hid规范普通按键值处于data[2]-data[7],所以检查new[2]-new[7]获取按键值。在单片机侧是直接在相应字节填入hid规范码,如填入new[5]=0x1e./
if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
/*这种情况发生在原来按下的键释放时。
至于>3,可以看hid规范码:有意义的hid规范码从4(字符a)开始。
数组old[]是new[]的一个拷贝,size 8,见最后一行。
*/
/*memscan源码如下
memscan – Find a character in an area of memory.
void *memscan(void *addr, int c, size_t size)
{
unsigned char *p = addr
while (size) {
if (*p == c)
return (void *)p;
p++;
size–;
}
return (void *)p;
} */
/*比如单片机发过来数据new[5]=0x1e(按键1),则在i=5时,
在new[2]至new[7]中寻找和old[5]相等的字符,如果相等返回new中相等字符的地址;否则返回new的最后一个元素的下一个地址,实际就是new+8。所以若没找到,
则memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8成立
*/
/总之,此if做了:检查old[i]值的hid规范合法性,并和新出现的按键值即new[2]–new[7]一一比较,如果新出现的按键值没有old[i],说明old[i]已经被释放了,所以执行以下操作
如果不是新的释放事件,而是原来的键一直处于释放状态,则不会执行下面的操作,说明只会在按键释放瞬间发生按键释放上报事件,而在未按期间不会上报释放事件。/
if (usb_kbd_keycode[kbd->old[i]])//old[i]对应的input码有意义,执行以下
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);//上报按键释放事件
else
dev_info(&urb->dev->dev,
“Unknown key (scancode %#x) released.\n”, kbd->old[i]);
}
if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
/*这种情况发生在原来释放的键按下时。
此if非彼if,它做了:检查new[i]值的hid规范合法性,并和old[2]–old[7]比较,如果没有一个值和new[i]相等,说明new[i]是新按下的按键,所以执行下面的操作
如果不是新键按下,而是原来的按键一直没有释放,则不会执行下面的操作,说明只会在按键按下时上报按键事件,而按着过程中,不会上报按键事件。
*/ if (usb_kbd_keycode[kbd->new[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);//上报新键按下事件
else
dev_info(&urb->dev->dev,
“Unknown key (scancode %#x) released.\n”, kbd->new[i]);
}
}
input_sync(kbd->dev);
memcpy(kbd->old, kbd->new, 8);//拷贝new到old
/总之实现了,在按键释放时报告一次释放事件,释放之后不会再报告;在按键按下时会报告一次按下事件,按下之后不会再报告。还算巧妙/
host side
drivers/hid/usbhid/usbkbd.c中定义了一张表
static const unsigned char usb_kbd_keycode[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,//0
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,//16
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,//32
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,//48
65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,//64
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,//80
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,//96
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,//112
115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,//128
122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,//144
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,//160
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,//176
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,//192
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,//208
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,//224
150,158,159,128,136,177,178,176,142,152,173,140//240-251
};**
device side
单片机装备5个按键k1,k2,k3,k4,k5用来模拟键盘的1, 2, 3, 4, 5键
比如单片机检测到k1按下,会令keyboardvalue[5]=0x1e,代码如下
static INT8U keyboardvalue[8] = {0,0,0,0,0,0,0,0};//和hid规范相应的8个字节,用于发送给主机
int main( void )
{
INT8U btmp;
Clock_Init( );
USB_Init( USB_ENABLE );
EA = 1;
while( 1 )
{
// keyboardvalue[5] = 0x3D;
// HID_SendData( keyboardvalue, 8 );
for( btmp = 0; btmp < 8; btmp ++ )
{
keyboardvalue[btmp] = 0;
}
btmp = 1;
switch( KeyScan( )
{
case K1_PRESS:
keyboardvalue[5] = 0x1e;//即数字1,参照hid规范码,当然也可使用其他字节,比如 keyboardvalue[2]=0x1e, keyboardvalue[7]=0x1e等
break;
case K2_PRESS:
keyboardvalue[5] = 0x1f;//数字2
break;
case K3_PRESS:
keyboardvalue[5] = 0x20;//数字3
break;
case K4_PRESS:
keyboardvalue[5] = 0x21;//数字4
break;
case K5_PRESS:
keyboardvalue[5] = 0x22;//数字5
break;
case K1_RELEASE:
case K2_RELEASE:
case K3_RELEASE:
case K4_RELEASE:
case K5_RELEASE:
break;
default:
btmp = 0;
break;
}
if( btmp )
{
HID_SendData( keyboardvalue, 8 ); //发送使能
}
IdleMode( );
}
return 0;
}