模拟游戏设备 - 树莓派 Zero

5

你好,我想将我的树莓派零号作为HID设备(游戏手柄)使用。

当我将我的树莓派零号的USB端口连接到我的电脑时,我希望它能够显示为一个游戏手柄,并添加X和Y轴。目前,我已经成功将树莓派零号显示为键盘并向其发送按键信息。参考这个页面,有人知道我的想法是否可行吗?

1个回答

4

我希望能够实现这个功能(但我没有树莓派硬件来测试)。

你提供的链接中的报告描述符指定了一个仅键盘的HID报告描述符,尽管标题是“键盘/鼠标/游戏杆(HID)”:

echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00
\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03
\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01
\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07
\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc

…解码后为:

//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------

/*
05 01        (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page 
09 06        (LOCAL)  USAGE              0x00010006 Keyboard (CA=Application Collection) 
A1 01        (MAIN)   COLLECTION         0x00000001 Application (Usage=0x00010006: Page=Generic Desktop Page, Usage=Keyboard, Type=CA)
05 07          (GLOBAL) USAGE_PAGE         0x0007 Keyboard/Keypad Page 
19 E0          (LOCAL)  USAGE_MINIMUM      0x000700E0 Keyboard Left Control (DV=Dynamic Value) 
29 E7          (LOCAL)  USAGE_MAXIMUM      0x000700E7 Keyboard Right GUI (DV=Dynamic Value) 
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0)  <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)  
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field  
95 08          (GLOBAL) REPORT_COUNT       0x08 (8) Number of fields  
81 02          (MAIN)   INPUT              0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields  
75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field  
81 03          (MAIN)   INPUT              0x00000003 (1 field x 8 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
95 05          (GLOBAL) REPORT_COUNT       0x05 (5) Number of fields  
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field  
05 08          (GLOBAL) USAGE_PAGE         0x0008 LED Indicator Page 
19 01          (LOCAL)  USAGE_MINIMUM      0x00080001 Num Lock (OOC=On/Off Control) 
29 05          (LOCAL)  USAGE_MAXIMUM      0x00080005 Kana (OOC=On/Off Control) 
91 02          (MAIN)   OUTPUT             0x00000002 (5 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields  
75 03          (GLOBAL) REPORT_SIZE        0x03 (3) Number of bits per field  
91 03          (MAIN)   OUTPUT             0x00000003 (1 field x 3 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
95 06          (GLOBAL) REPORT_COUNT       0x06 (6) Number of fields  
75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field  
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 65          (GLOBAL) LOGICAL_MAXIMUM    0x65 (101)  
05 07          (GLOBAL) USAGE_PAGE         0x0007 Keyboard/Keypad Page 
19 00          (LOCAL)  USAGE_MINIMUM      0x00070000 Keyboard No event indicated (Sel=Selector) 
29 65          (LOCAL)  USAGE_MAXIMUM      0x00070065 Keyboard Application (Sel=Selector) 
81 00          (MAIN)   INPUT              0x00000000 (6 fields x 8 bits) 0=Data 0=Array 0=Absolute 
C0           (MAIN)   END_COLLECTION     Application 
*/

//--------------------------------------------------------------------------------
// Keyboard/Keypad Page inputReport (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
                                                     // No REPORT ID byte
                                                     // Collection: Keyboard
  uint8_t  KB_KeyboardKeyboardLeftControl : 1;       // Usage 0x000700E0: Keyboard Left Control, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftShift : 1;         // Usage 0x000700E1: Keyboard Left Shift, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftAlt : 1;           // Usage 0x000700E2: Keyboard Left Alt, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftGui : 1;           // Usage 0x000700E3: Keyboard Left GUI, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightControl : 1;      // Usage 0x000700E4: Keyboard Right Control, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightShift : 1;        // Usage 0x000700E5: Keyboard Right Shift, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightAlt : 1;          // Usage 0x000700E6: Keyboard Right Alt, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightGui : 1;          // Usage 0x000700E7: Keyboard Right GUI, Value = 0 to 1
  uint8_t  pad_2;                                    // Pad
  uint8_t  KB_Keyboard[6];                           // Value = 0 to 101
} inputReport_t;


//--------------------------------------------------------------------------------
// LED Indicator Page outputReport (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
                                                     // No REPORT ID byte
                                                     // Collection: Keyboard
  uint8_t  LED_KeyboardNumLock : 1;                  // Usage 0x00080001: Num Lock, Value = 0 to 1
  uint8_t  LED_KeyboardCapsLock : 1;                 // Usage 0x00080002: Caps Lock, Value = 0 to 1
  uint8_t  LED_KeyboardScrollLock : 1;               // Usage 0x00080003: Scroll Lock, Value = 0 to 1
  uint8_t  LED_KeyboardCompose : 1;                  // Usage 0x00080004: Compose, Value = 0 to 1
  uint8_t  LED_KeyboardKana : 1;                     // Usage 0x00080005: Kana, Value = 0 to 1
  uint8_t  : 3;                                      // Pad
} outputReport_t;

我认为至少需要更改HID报告描述符字节以指定游戏手柄报告而非键盘报告。有许多替代方案,但以下内容定义了一个8位x轴和y轴以及8个按钮,可能是一个不错的起点:

//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------

/*
05 01        (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page 
09 04        (LOCAL)  USAGE              0x00010004 Joystick (CA=Application Collection) 
A1 01        (MAIN)   COLLECTION         0x00000001 Application (Usage=0x00010004: Page=Generic Desktop Page, Usage=Joystick, Type=CA)
15 81          (GLOBAL) LOGICAL_MINIMUM    0x81 (-127)  
25 7F          (GLOBAL) LOGICAL_MAXIMUM    0x7F (127)  
09 01          (LOCAL)  USAGE              0x00010001 Pointer (CP=Physical Collection) 
A1 00          (MAIN)   COLLECTION         0x00000000 Physical (Usage=0x00010001: Page=Generic Desktop Page, Usage=Pointer, Type=CP)
09 30            (LOCAL)  USAGE              0x00010030 X (DV=Dynamic Value) 
09 31            (LOCAL)  USAGE              0x00010031 Y (DV=Dynamic Value) 
75 08            (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field  
95 02            (GLOBAL) REPORT_COUNT       0x02 (2) Number of fields  
81 02            (MAIN)   INPUT              0x00000002 (2 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
C0             (MAIN)   END_COLLECTION     Physical 
05 09          (GLOBAL) USAGE_PAGE         0x0009 Button Page 
19 01          (LOCAL)  USAGE_MINIMUM      0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot) 
29 08          (LOCAL)  USAGE_MAXIMUM      0x00090008 Button 8 (MULTI=Selector, On/Off, Momentary, or One Shot) 
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0)  <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)  
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field  
95 08          (GLOBAL) REPORT_COUNT       0x08 (8) Number of fields  
81 02          (MAIN)   INPUT              0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
C0           (MAIN)   END_COLLECTION     Application 
*/

//--------------------------------------------------------------------------------
// Generic Desktop Page inputReport (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
                                                     // No REPORT ID byte
                                                     // Collection: Joystick Pointer
  int8_t   GD_JoystickPointerX;                      // Usage 0x00010030: X, Value = -127 to 127
  int8_t   GD_JoystickPointerY;                      // Usage 0x00010031: Y, Value = -127 to 127
                                                     // Collection: Joystick
  uint8_t  BTN_JoystickButton1 : 1;                  // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1
  uint8_t  BTN_JoystickButton2 : 1;                  // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1
  uint8_t  BTN_JoystickButton3 : 1;                  // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1
  uint8_t  BTN_JoystickButton4 : 1;                  // Usage 0x00090004: Button 4, Value = 0 to 1
  uint8_t  BTN_JoystickButton5 : 1;                  // Usage 0x00090005: Button 5, Value = 0 to 1
  uint8_t  BTN_JoystickButton6 : 1;                  // Usage 0x00090006: Button 6, Value = 0 to 1
  uint8_t  BTN_JoystickButton7 : 1;                  // Usage 0x00090007: Button 7, Value = 0 to 1
  uint8_t  BTN_JoystickButton8 : 1;                  // Usage 0x00090008: Button 8, Value = 0 to 1
} inputReport_t;

您可能还需要更改以下内容:

echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass

将定义一个BOOT键盘的功能更改为:

echo 0 > functions/hid.usb0/protocol
echo 0 > functions/hid.usb0/subclass

这段文字的意思是该设备没有特定的子类(例如BOOT设备)或协议(例如键盘或鼠标)。可能需要进行其他更改,但正如我所说,我没有硬件来进行实验。

希望这能有所帮助。


谢谢您的回复,看起来很有前途,我很快就要尝试一下!可能是初学者的问题,但我该如何将您解码的预览解析为十六进制值? - Erwin Vorenhout
哇,那完全奏效了!你知道有没有关于如何将数据写入按钮/轴的文档可用? - Erwin Vorenhout
你应该能够按照你链接的文章中描述的方式完成它。在你的情况下,你需要将三个字节(x、y和8个按钮位)回显到你新定义的小工具中。 - aja
谢谢,但我不明白如何将这些字节格式化为/dev/hidg0所需的格式,就像他们在这里做的那样echo -ne "\0\0\x4\0\0\0\0\0" > /dev/hidg0 #按下A按钮 - Erwin Vorenhout
游戏手柄发给主机的报告结构由您的HID报告描述符定义。在这种情况下,如果您想要发送x=10,y=-2以及按下按钮2和3,则应向/dev设备写入echo -ne“\x0A\xFE\x06” - aja
谢谢,现在我明白X、Y是8位二进制补码,按钮只是十六进制转换为二进制,你应该享受一杯美味的热咖啡,感谢你! - Erwin Vorenhout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接