极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 27728|回复: 10

Arduino 控制USB设备(5)解析USB键盘的例子-

[复制链接]
发表于 2015-8-6 12:15:32 | 显示全部楼层 |阅读模式
本帖最后由 zoologist 于 2015-8-6 13:37 编辑

下面是一个获得 USB 键盘数据的例子【参考1】。原理上说,是将键盘切换为 Boot Protocol 这样就避免了需要具体解析HID的麻烦。

  1. /* MAX3421E USB Host controller LCD/keyboard demonstration */
  2. //#include <Spi.h>
  3. #include "Max3421e.h"
  4. #include "Usb.h"

  5. /* keyboard data taken from configuration descriptor */
  6. #define KBD_ADDR        1
  7. #define KBD_EP          1
  8. #define KBD_IF          0
  9. #define EP_MAXPKTSIZE   8
  10. #define EP_POLL         0x0a
  11. /**/
  12. //******************************************************************************
  13. //  macros to identify special charaters(other than Digits and Alphabets)
  14. //******************************************************************************
  15. #define BANG        (0x1E)
  16. #define AT          (0x1F)
  17. #define POUND       (0x20)
  18. #define DOLLAR      (0x21)
  19. #define PERCENT     (0x22)
  20. #define CAP         (0x23)
  21. #define AND         (0x24)
  22. #define STAR        (0x25)
  23. #define OPENBKT     (0x26)
  24. #define CLOSEBKT    (0x27)

  25. #define RETURN      (0x28)
  26. #define ESCAPE      (0x29)
  27. #define BACKSPACE   (0x2A)
  28. #define TAB         (0x2B)
  29. #define SPACE       (0x2C)
  30. #define HYPHEN      (0x2D)
  31. #define EQUAL       (0x2E)
  32. #define SQBKTOPEN   (0x2F)
  33. #define SQBKTCLOSE  (0x30)
  34. #define BACKSLASH   (0x31)
  35. #define SEMICOLON   (0x33)
  36. #define INVCOMMA    (0x34)
  37. #define TILDE       (0x35)
  38. #define COMMA       (0x36)
  39. #define PERIOD      (0x37)
  40. #define FRONTSLASH  (0x38)
  41. #define DELETE      (0x4c)
  42. /**/
  43. /* Modifier masks. One for both modifiers */
  44. #define SHIFT       0x22
  45. #define CTRL        0x11
  46. #define ALT         0x44
  47. #define GUI         0x88
  48. /**/
  49. /* "Sticky keys */
  50. #define CAPSLOCK    (0x39)
  51. #define NUMLOCK     (0x53)
  52. #define SCROLLLOCK  (0x47)
  53. /* Sticky keys output report bitmasks */
  54. #define bmNUMLOCK       0x01
  55. #define bmCAPSLOCK      0x02
  56. #define bmSCROLLLOCK    0x04
  57. /**/
  58. EP_RECORD ep_record[ 2 ];  //endpoint record structure for the keyboard

  59. char buf[ 8 ] = { 0 };      //keyboard buffer
  60. char old_buf[ 8 ] = { 0 };  //last poll
  61. /* Sticky key state */
  62. bool numLock = false;
  63. bool capsLock = false;
  64. bool scrollLock = false;
  65. bool line = false;

  66. void setup();
  67. void loop();

  68. MAX3421E Max;
  69. USB Usb;

  70. void setup() {
  71.   Serial.begin( 9600 );
  72.   Serial.println("Start");
  73.   Max.powerOn();
  74.   delay( 200 );
  75. }

  76. void loop() {
  77.     Max.Task();
  78.     Usb.Task();
  79.     if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) {
  80. //wait for addressing state
  81.         kbd_init();
  82.         Usb.setUsbTaskState( USB_STATE_RUNNING );
  83.     }
  84.     if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) {  
  85. //poll the keyboard  
  86.         kbd_poll();
  87.     }
  88. }
  89. /* Initialize keyboard */
  90. void kbd_init( void )
  91. {
  92. byte rcode = 0;  //return code
  93. /**/
  94.     /* Initialize data structures */
  95.     ep_record[ 0 ] = *( Usb.getDevTableEntry( 0,0 ));  
  96.                            //copy endpoint 0 parameters
  97.     ep_record[ 1 ].MaxPktSize = EP_MAXPKTSIZE;
  98.     ep_record[ 1 ].Interval  = EP_POLL;
  99.     ep_record[ 1 ].sndToggle = bmSNDTOG0;
  100.     ep_record[ 1 ].rcvToggle = bmRCVTOG0;
  101.     Usb.setDevTableEntry( 1, ep_record );              
  102.                            //plug kbd.endpoint parameters to devtable
  103.     /* Configure device */
  104.     rcode = Usb.setConf( KBD_ADDR, 0, 1 );                    
  105.     if( rcode ) {
  106.         Serial.print("Error attempting to configure keyboard. Return code :");
  107.         Serial.println( rcode, HEX );
  108.         while(1);  //stop
  109.     }
  110.     /* Set boot protocol */
  111.     rcode = Usb.setProto( KBD_ADDR, 0, 0, 0 );
  112.     if( rcode ) {
  113.         Serial.print("Error attempting to configure boot protocol. Return code :");
  114.         Serial.println( rcode, HEX );
  115.         while( 1 );  //stop
  116.     }
  117.     delay(2000);
  118.     Serial.println("Keyboard initialized");
  119. }

  120. /* Poll keyboard and print result */
  121. /* buffer starts at position 2, 0 is modifier key state and 1 is irrelevant */
  122. void kbd_poll( void )
  123. {
  124. char i;
  125. static char leds = 0;
  126. byte rcode = 0;     //return code
  127.     /* poll keyboard */
  128.     rcode = Usb.inTransfer( KBD_ADDR, KBD_EP, 8, buf );
  129.     if( rcode != 0 ) {
  130.         return;
  131.     }//if ( rcode..
  132.     for( i = 2; i < 8; i++ ) {
  133.      if( buf[ i ] == 0 ) {  //end of non-empty space
  134.         break;
  135.      }
  136.       if( buf_compare( buf[ i ] ) == false ) {   //if new key
  137.         switch( buf[ i ] ) {
  138.           case CAPSLOCK:
  139.             capsLock =! capsLock;
  140.             leds = ( capsLock ) ? leds |= bmCAPSLOCK : leds &= ~bmCAPSLOCK;   
  141.                       // set or clear bit 1 of LED report byte
  142.             break;
  143.           case NUMLOCK:
  144.             numLock =! numLock;
  145.             leds = ( numLock ) ? leds |= bmNUMLOCK : leds &= ~bmNUMLOCK;      
  146.                                   // set or clear bit 0 of LED report byte
  147.             break;
  148.           case SCROLLLOCK:
  149.             scrollLock =! scrollLock;
  150.             leds = ( scrollLock ) ? leds |= bmSCROLLLOCK : leds &= ~bmSCROLLLOCK;
  151.                                   // set or clear bit 2 of LED report byte
  152.             break;
  153.           case DELETE:
  154.             line = false;
  155.             break;
  156.           case RETURN:
  157.             line =! line;
  158.             break;  
  159.           default:
  160.             //Serial.print(HIDtoA( buf[ i ], buf[ 0 ] ));
  161.             break;
  162.         }//switch( buf[ i ...
  163.         Serial.print(buf[ i ],HEX);
  164.         Serial.print(' ');        
  165.         Serial.println(buf[ 0 ],HEX);        
  166.         rcode = Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, &leds );
  167.         if( rcode ) {
  168.           Serial.print("Set report error: ");
  169.           Serial.println( rcode, HEX );
  170.         }//if( rcode ...
  171.      }//if( buf_compare( buf[ i ] ) == false ...
  172.     }//for( i = 2...
  173.     for( i = 2; i < 8; i++ ) {                    //copy new buffer to old
  174.       old_buf[ i ] = buf[ i ];
  175.     }
  176. }
  177. /* compare byte against bytes in old buffer */
  178. bool buf_compare( byte data )
  179. {
  180. char i;
  181. for( i = 2; i < 8; i++ ) {
  182.    if( old_buf[ i ] == data ) {
  183.      return( true );
  184.    }
  185. }
  186. return( false );
  187. }

  188. /* HID to ASCII converter. Takes HID keyboard scancode, returns ASCII code */
  189. byte HIDtoA( byte HIDbyte, byte mod )
  190. {
  191.   /* upper row of the keyboard, numbers and special symbols */
  192.   if( HIDbyte >= 0x1e && HIDbyte <= 0x27 ) {
  193.     if(( mod & SHIFT ) || numLock ) {    //shift key pressed
  194.       switch( HIDbyte ) {
  195.         case BANG:  return( 0x21 );
  196.         case AT:    return( 0x40 );
  197.         case POUND: return( 0x23 );
  198.         case DOLLAR: return( 0x24 );
  199.         case PERCENT: return( 0x25 );
  200.         case CAP: return( 0x5e );
  201.         case AND: return( 0x26 );
  202.         case STAR: return( 0x2a );
  203.         case OPENBKT: return( 0x28 );
  204.         case CLOSEBKT: return( 0x29 );
  205.       }//switch( HIDbyte...
  206.     }
  207.     else {                  //numbers
  208.       if( HIDbyte == 0x27 ) {  //zero
  209.         return( 0x30 );
  210.       }
  211.       else {
  212.         return( HIDbyte + 0x13 );
  213.       }
  214.     }//numbers
  215.   }//if( HIDbyte >= 0x1e && HIDbyte <= 0x27
  216.   /**/
  217.   /* number pad. Arrows are not supported */
  218.   if(( HIDbyte >= 0x59 && HIDbyte <= 0x61 ) &&
  219.                    ( numLock == true )) {  // numbers 1-9
  220.     return( HIDbyte - 0x28 );
  221.   }
  222.   if(( HIDbyte == 0x62 ) && ( numLock == true )) {  //zero
  223.     return( 0x30 );
  224.   }
  225.   /* Letters a-z */
  226.   if( HIDbyte >= 0x04 && HIDbyte <= 0x1d ) {
  227.     if((( capsLock == true ) && ( mod & SHIFT ) == 0 )
  228.           || (( capsLock == false ) && ( mod & SHIFT ))) {  
  229.                      //upper case
  230.       return( HIDbyte + 0x3d );
  231.     }
  232.     else {  //lower case
  233.       return( HIDbyte + 0x5d );
  234.     }
  235.   }//if( HIDbyte >= 0x04 && HIDbyte <= 0x1d...
  236.   /* Other special symbols */
  237.   if( HIDbyte >= 0x2c && HIDbyte <= 0x38 ) {
  238.     switch( HIDbyte ) {
  239.       case SPACE: return( 0x20 );
  240.       case HYPHEN:
  241.         if(( mod & SHIFT ) == false ) {
  242.          return( 0x2d );
  243.         }
  244.         else {
  245.           return( 0x5f );
  246.         }
  247.       case EQUAL:
  248.        if(( mod & SHIFT ) == false ) {
  249.         return( 0x3d );
  250.        }
  251.        else {
  252.         return( 0x2b );
  253.        }
  254.        case SQBKTOPEN:
  255.          if(( mod & SHIFT ) == false ) {
  256.           return( 0x5b );
  257.          }
  258.          else {
  259.           return( 0x7b );
  260.          }
  261.        case SQBKTCLOSE:
  262.          if(( mod & SHIFT ) == false ) {
  263.           return( 0x5d );
  264.          }
  265.          else {
  266.           return( 0x7d );
  267.          }
  268.        case BACKSLASH:
  269.          if(( mod & SHIFT ) == false ) {
  270.            return( 0x5c );
  271.          }
  272.          else {
  273.            return( 0x7c );
  274.          }
  275.        case SEMICOLON:
  276.          if(( mod & SHIFT ) == false ) {
  277.            return( 0x3b );
  278.          }
  279.          else {
  280.            return( 0x3a );
  281.          }
  282.       case INVCOMMA:
  283.         if(( mod & SHIFT ) == false ) {
  284.           return( 0x27 );
  285.         }
  286.         else {
  287.           return( 0x22 );
  288.         }
  289.       case TILDE:  
  290.         if(( mod & SHIFT ) == false ) {
  291.           return( 0x60 );
  292.         }
  293.         else {
  294.           return( 0x7e );
  295.         }
  296.       case COMMA:   
  297.         if(( mod & SHIFT ) == false ) {
  298.           return( 0x2c );
  299.         }
  300.         else {
  301.           return( 0x3c );
  302.         }
  303.       case PERIOD:
  304.         if(( mod & SHIFT ) == false ) {
  305.           return( 0x2e );
  306.         }
  307.         else {
  308.           return( 0x3e );
  309.         }
  310.       case FRONTSLASH:
  311.         if(( mod & SHIFT ) == false ) {
  312.           return( 0x2f );
  313.         }
  314.         else {
  315.           return( 0x3f );
  316.         }
  317.       default:
  318.         break;
  319.     }//switch( HIDbyte..
  320.   }//if( HIDbye >= 0x2d && HIDbyte <= 0x38..
  321.   return( 0 );
  322. }
复制代码


实验依然使用上一次的USB小键盘。上面的按键分布如下:



关于键值的介绍可以在【参考2】找到

NumLock OFF的情况下,各输出键值:


*输出三次62,相当于输出3个0

NumLock ON的情况下,各输出键值:


*输出三次62外加一个53

运行结果



本文完整代码下载 LCDkbd


参考:
1. https://github.com/felis/USB_Hos ... s/descriptor_parser USB_Host_Shield/examples/LCDkbd/
2. http://www.quadibloc.com/comp/scan.htm

本文首发 http://www.lab-z.com/usbkb/

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2015-8-7 00:52:01 | 显示全部楼层
我看过有用32u4做键盘记录器,可以记录输入,并转发给电脑,很强的黑客工具
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-8-7 09:38:56 | 显示全部楼层
nick_zm 发表于 2015-8-7 00:52
我看过有用32u4做键盘记录器,可以记录输入,并转发给电脑,很强的黑客工具

记录只是记录 ps2 的数据吧?

http://www.lab-z.com/ps2a/

不搭配硬件,直接解析不可能,性能不够
回复 支持 反对

使用道具 举报

发表于 2015-8-8 08:41:50 | 显示全部楼层
请问:
1、这个只能针对usb键盘吗?其他的,比方usb鼠标?usb手柄(游戏手柄之类)?
2、键盘切换为 Boot Protocol,关于这点,能否详细一点?我百度了,出来的好像都和你说的没多大关系。

谢谢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-8-8 09:12:10 | 显示全部楼层
maxims 发表于 2015-8-8 08:41
请问:
1、这个只能针对usb键盘吗?其他的,比方usb鼠标?usb手柄(游戏手柄之类)?
2、键盘切换为 Boot ...

1.其他的HID设备也可以,但是需要额外的程序解析
2.国内基本上没有介绍Boot Protocol 的资料,这种情况很常见......这个 Protocol 最初的设计目的是给BIOS之类使用的。基本上所有的键盘鼠标都会支持。
回复 支持 反对

使用道具 举报

发表于 2015-8-8 22:09:45 | 显示全部楼层
zoologist 发表于 2015-8-8 09:12
1.其他的HID设备也可以,但是需要额外的程序解析
2.国内基本上没有介绍Boot Protocol 的资料,这种情况很 ...

好的,我再继续找找资料看看
回复 支持 反对

使用道具 举报

发表于 2015-8-9 02:08:21 | 显示全部楼层
zoologist 发表于 2015-8-7 09:38
记录只是记录 ps2 的数据吧?

http://www.lab-z.com/ps2a/

https://github.com/tmk/tmk_keyboard/tree/master/converter/usb_usb
回复 支持 反对

使用道具 举报

发表于 2016-6-19 08:41:12 | 显示全部楼层
不好意思,我是新手,想请教
如果我需要直接读取hid讯号
(我有个rfid读卡器,目前是直接透过hid-usb接到电脑上读取卡号)
想改成用arduino,请问有没有建议做法,或参考资料,
非常感谢。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-6-19 22:22:04 | 显示全部楼层
happy1991 发表于 2016-6-19 08:41
不好意思,我是新手,想请教
如果我需要直接读取hid讯号
(我有个rfid读卡器,目前是直接透过hid-usb接到电 ...

不知道你的读卡器是不是 hid 键盘设备,如果是的话,直接按照键盘解析,如果不是的话,

那恐怕必须慢慢研究如何解析了。

ps:hid协议的话,windows可以直接解析,但是 arduino 还做不到
回复 支持 反对

使用道具 举报

发表于 2018-8-23 14:08:11 | 显示全部楼层
nick_zm 发表于 2015-8-7 00:52
我看过有用32u4做键盘记录器,可以记录输入,并转发给电脑,很强的黑客工具

可以请教下吗 大侠

回复 支持 反对

使用道具 举报

发表于 2018-9-11 21:14:05 | 显示全部楼层
请教一下如何把键值输出一样(输入A,输出也是A)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-25 06:40 , Processed in 0.050288 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表