Arduino 控制USB设备(5)解析USB键盘的例子-
本帖最后由 zoologist 于 2015-8-6 13:37 编辑下面是一个获得 USB 键盘数据的例子【参考1】。原理上说,是将键盘切换为 Boot Protocol 这样就避免了需要具体解析HID的麻烦。
/* MAX3421E USB Host controller LCD/keyboard demonstration */
//#include <Spi.h>
#include "Max3421e.h"
#include "Usb.h"
/* keyboard data taken from configuration descriptor */
#define KBD_ADDR 1
#define KBD_EP 1
#define KBD_IF 0
#define EP_MAXPKTSIZE 8
#define EP_POLL 0x0a
/**/
//******************************************************************************
//macros to identify special charaters(other than Digits and Alphabets)
//******************************************************************************
#define BANG (0x1E)
#define AT (0x1F)
#define POUND (0x20)
#define DOLLAR (0x21)
#define PERCENT (0x22)
#define CAP (0x23)
#define AND (0x24)
#define STAR (0x25)
#define OPENBKT (0x26)
#define CLOSEBKT (0x27)
#define RETURN (0x28)
#define ESCAPE (0x29)
#define BACKSPACE (0x2A)
#define TAB (0x2B)
#define SPACE (0x2C)
#define HYPHEN (0x2D)
#define EQUAL (0x2E)
#define SQBKTOPEN (0x2F)
#define SQBKTCLOSE(0x30)
#define BACKSLASH (0x31)
#define SEMICOLON (0x33)
#define INVCOMMA (0x34)
#define TILDE (0x35)
#define COMMA (0x36)
#define PERIOD (0x37)
#define FRONTSLASH(0x38)
#define DELETE (0x4c)
/**/
/* Modifier masks. One for both modifiers */
#define SHIFT 0x22
#define CTRL 0x11
#define ALT 0x44
#define GUI 0x88
/**/
/* "Sticky keys */
#define CAPSLOCK (0x39)
#define NUMLOCK (0x53)
#define SCROLLLOCK(0x47)
/* Sticky keys output report bitmasks */
#define bmNUMLOCK 0x01
#define bmCAPSLOCK 0x02
#define bmSCROLLLOCK 0x04
/**/
EP_RECORD ep_record[ 2 ];//endpoint record structure for the keyboard
char buf[ 8 ] = { 0 }; //keyboard buffer
char old_buf[ 8 ] = { 0 };//last poll
/* Sticky key state */
bool numLock = false;
bool capsLock = false;
bool scrollLock = false;
bool line = false;
void setup();
void loop();
MAX3421E Max;
USB Usb;
void setup() {
Serial.begin( 9600 );
Serial.println("Start");
Max.powerOn();
delay( 200 );
}
void loop() {
Max.Task();
Usb.Task();
if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) {
//wait for addressing state
kbd_init();
Usb.setUsbTaskState( USB_STATE_RUNNING );
}
if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) {
//poll the keyboard
kbd_poll();
}
}
/* Initialize keyboard */
void kbd_init( void )
{
byte rcode = 0;//return code
/**/
/* Initialize data structures */
ep_record[ 0 ] = *( Usb.getDevTableEntry( 0,0 ));
//copy endpoint 0 parameters
ep_record[ 1 ].MaxPktSize = EP_MAXPKTSIZE;
ep_record[ 1 ].Interval= EP_POLL;
ep_record[ 1 ].sndToggle = bmSNDTOG0;
ep_record[ 1 ].rcvToggle = bmRCVTOG0;
Usb.setDevTableEntry( 1, ep_record );
//plug kbd.endpoint parameters to devtable
/* Configure device */
rcode = Usb.setConf( KBD_ADDR, 0, 1 );
if( rcode ) {
Serial.print("Error attempting to configure keyboard. Return code :");
Serial.println( rcode, HEX );
while(1);//stop
}
/* Set boot protocol */
rcode = Usb.setProto( KBD_ADDR, 0, 0, 0 );
if( rcode ) {
Serial.print("Error attempting to configure boot protocol. Return code :");
Serial.println( rcode, HEX );
while( 1 );//stop
}
delay(2000);
Serial.println("Keyboard initialized");
}
/* Poll keyboard and print result */
/* buffer starts at position 2, 0 is modifier key state and 1 is irrelevant */
void kbd_poll( void )
{
char i;
static char leds = 0;
byte rcode = 0; //return code
/* poll keyboard */
rcode = Usb.inTransfer( KBD_ADDR, KBD_EP, 8, buf );
if( rcode != 0 ) {
return;
}//if ( rcode..
for( i = 2; i < 8; i++ ) {
if( buf[ i ] == 0 ) {//end of non-empty space
break;
}
if( buf_compare( buf[ i ] ) == false ) { //if new key
switch( buf[ i ] ) {
case CAPSLOCK:
capsLock =! capsLock;
leds = ( capsLock ) ? leds |= bmCAPSLOCK : leds &= ~bmCAPSLOCK;
// set or clear bit 1 of LED report byte
break;
case NUMLOCK:
numLock =! numLock;
leds = ( numLock ) ? leds |= bmNUMLOCK : leds &= ~bmNUMLOCK;
// set or clear bit 0 of LED report byte
break;
case SCROLLLOCK:
scrollLock =! scrollLock;
leds = ( scrollLock ) ? leds |= bmSCROLLLOCK : leds &= ~bmSCROLLLOCK;
// set or clear bit 2 of LED report byte
break;
case DELETE:
line = false;
break;
case RETURN:
line =! line;
break;
default:
//Serial.print(HIDtoA( buf[ i ], buf[ 0 ] ));
break;
}//switch( buf[ i ...
Serial.print(buf[ i ],HEX);
Serial.print(' ');
Serial.println(buf[ 0 ],HEX);
rcode = Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, &leds );
if( rcode ) {
Serial.print("Set report error: ");
Serial.println( rcode, HEX );
}//if( rcode ...
}//if( buf_compare( buf[ i ] ) == false ...
}//for( i = 2...
for( i = 2; i < 8; i++ ) { //copy new buffer to old
old_buf[ i ] = buf[ i ];
}
}
/* compare byte against bytes in old buffer */
bool buf_compare( byte data )
{
char i;
for( i = 2; i < 8; i++ ) {
if( old_buf[ i ] == data ) {
return( true );
}
}
return( false );
}
/* HID to ASCII converter. Takes HID keyboard scancode, returns ASCII code */
byte HIDtoA( byte HIDbyte, byte mod )
{
/* upper row of the keyboard, numbers and special symbols */
if( HIDbyte >= 0x1e && HIDbyte <= 0x27 ) {
if(( mod & SHIFT ) || numLock ) { //shift key pressed
switch( HIDbyte ) {
case BANG:return( 0x21 );
case AT: return( 0x40 );
case POUND: return( 0x23 );
case DOLLAR: return( 0x24 );
case PERCENT: return( 0x25 );
case CAP: return( 0x5e );
case AND: return( 0x26 );
case STAR: return( 0x2a );
case OPENBKT: return( 0x28 );
case CLOSEBKT: return( 0x29 );
}//switch( HIDbyte...
}
else { //numbers
if( HIDbyte == 0x27 ) {//zero
return( 0x30 );
}
else {
return( HIDbyte + 0x13 );
}
}//numbers
}//if( HIDbyte >= 0x1e && HIDbyte <= 0x27
/**/
/* number pad. Arrows are not supported */
if(( HIDbyte >= 0x59 && HIDbyte <= 0x61 ) &&
( numLock == true )) {// numbers 1-9
return( HIDbyte - 0x28 );
}
if(( HIDbyte == 0x62 ) && ( numLock == true )) {//zero
return( 0x30 );
}
/* Letters a-z */
if( HIDbyte >= 0x04 && HIDbyte <= 0x1d ) {
if((( capsLock == true ) && ( mod & SHIFT ) == 0 )
|| (( capsLock == false ) && ( mod & SHIFT ))) {
//upper case
return( HIDbyte + 0x3d );
}
else {//lower case
return( HIDbyte + 0x5d );
}
}//if( HIDbyte >= 0x04 && HIDbyte <= 0x1d...
/* Other special symbols */
if( HIDbyte >= 0x2c && HIDbyte <= 0x38 ) {
switch( HIDbyte ) {
case SPACE: return( 0x20 );
case HYPHEN:
if(( mod & SHIFT ) == false ) {
return( 0x2d );
}
else {
return( 0x5f );
}
case EQUAL:
if(( mod & SHIFT ) == false ) {
return( 0x3d );
}
else {
return( 0x2b );
}
case SQBKTOPEN:
if(( mod & SHIFT ) == false ) {
return( 0x5b );
}
else {
return( 0x7b );
}
case SQBKTCLOSE:
if(( mod & SHIFT ) == false ) {
return( 0x5d );
}
else {
return( 0x7d );
}
case BACKSLASH:
if(( mod & SHIFT ) == false ) {
return( 0x5c );
}
else {
return( 0x7c );
}
case SEMICOLON:
if(( mod & SHIFT ) == false ) {
return( 0x3b );
}
else {
return( 0x3a );
}
case INVCOMMA:
if(( mod & SHIFT ) == false ) {
return( 0x27 );
}
else {
return( 0x22 );
}
case TILDE:
if(( mod & SHIFT ) == false ) {
return( 0x60 );
}
else {
return( 0x7e );
}
case COMMA:
if(( mod & SHIFT ) == false ) {
return( 0x2c );
}
else {
return( 0x3c );
}
case PERIOD:
if(( mod & SHIFT ) == false ) {
return( 0x2e );
}
else {
return( 0x3e );
}
case FRONTSLASH:
if(( mod & SHIFT ) == false ) {
return( 0x2f );
}
else {
return( 0x3f );
}
default:
break;
}//switch( HIDbyte..
}//if( HIDbye >= 0x2d && HIDbyte <= 0x38..
return( 0 );
}
实验依然使用上一次的USB小键盘。上面的按键分布如下:
关于键值的介绍可以在【参考2】找到
NumLock OFF的情况下,各输出键值:
*输出三次62,相当于输出3个0
NumLock ON的情况下,各输出键值:
*输出三次62外加一个53
运行结果
本文完整代码下载 LCDkbd
参考:
1. https://github.com/felis/USB_Host_Shield/tree/master/examples/descriptor_parser USB_Host_Shield/examples/LCDkbd/
2. http://www.quadibloc.com/comp/scan.htm
本文首发 http://www.lab-z.com/usbkb/ 我看过有用32u4做键盘记录器,可以记录输入,并转发给电脑,很强的黑客工具 nick_zm 发表于 2015-8-7 00:52 static/image/common/back.gif
我看过有用32u4做键盘记录器,可以记录输入,并转发给电脑,很强的黑客工具
记录只是记录 ps2 的数据吧?
http://www.lab-z.com/ps2a/
不搭配硬件,直接解析不可能,性能不够 请问:
1、这个只能针对usb键盘吗?其他的,比方usb鼠标?usb手柄(游戏手柄之类)?
2、键盘切换为 Boot Protocol,关于这点,能否详细一点?我百度了,出来的好像都和你说的没多大关系。
谢谢 maxims 发表于 2015-8-8 08:41 static/image/common/back.gif
请问:
1、这个只能针对usb键盘吗?其他的,比方usb鼠标?usb手柄(游戏手柄之类)?
2、键盘切换为 Boot ...
1.其他的HID设备也可以,但是需要额外的程序解析
2.国内基本上没有介绍Boot Protocol 的资料,这种情况很常见......这个 Protocol 最初的设计目的是给BIOS之类使用的。基本上所有的键盘鼠标都会支持。 zoologist 发表于 2015-8-8 09:12 static/image/common/back.gif
1.其他的HID设备也可以,但是需要额外的程序解析
2.国内基本上没有介绍Boot Protocol 的资料,这种情况很 ...
好的,我再继续找找资料看看 zoologist 发表于 2015-8-7 09:38 static/image/common/back.gif
记录只是记录 ps2 的数据吧?
http://www.lab-z.com/ps2a/
https://github.com/tmk/tmk_keyboard/tree/master/converter/usb_usb 不好意思,我是新手,想请教
如果我需要直接读取hid讯号
(我有个rfid读卡器,目前是直接透过hid-usb接到电脑上读取卡号)
想改成用arduino,请问有没有建议做法,或参考资料,
非常感谢。 happy1991 发表于 2016-6-19 08:41 static/image/common/back.gif
不好意思,我是新手,想请教
如果我需要直接读取hid讯号
(我有个rfid读卡器,目前是直接透过hid-usb接到电 ...
不知道你的读卡器是不是 hid 键盘设备,如果是的话,直接按照键盘解析,如果不是的话,
那恐怕必须慢慢研究如何解析了。
ps:hid协议的话,windows可以直接解析,但是 arduino 还做不到 nick_zm 发表于 2015-8-7 00:52
我看过有用32u4做键盘记录器,可以记录输入,并转发给电脑,很强的黑客工具
可以请教下吗 大侠
请教一下如何把键值输出一样(输入A,输出也是A)
页:
[1]