键盘设备和主机的hid规范
看一下hid规范的键盘码-refer to hid usage table section 10
①host side
drivers/hid/usbhid/usbkbd.c中定义了一张表
看看是怎么检测和上报按下释放事件的,在函数static void usb_kbd_irq(struct urb *urb)
②device side
单片机装备5个按键k1,k2,k3,k4,k5用来模拟键盘的1, 2, 3, 4, 5键
比如单片机检测到k1按下,会令keyboardvalue[5]=0x1e,代码如下
- /*键盘发送给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*/
- 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
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
- };
- /****************************************检测修饰键*********************************************************/
- /*每次中断传输都会执行以下检查*/
- 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规范<span></span>令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
- /*总之实现了,在按键释放时报告一次释放事件,释放之后不会再报告;在按键按下时会报告一次按下事件,按下之后不会再报告。还算巧妙*/
②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;
- }