【问题标题】:Emulate a Gaming Device - Raspberry PI Zero模拟游戏设备 - Raspberry PI 零
【发布时间】:2018-03-06 20:07:13
【问题描述】:

您好,我想将 Raspberry PI Zero 用作 HID 设备(操纵杆)。

当我将 Raspberry PI Zero USB 端口连接到我的 PC 时,我希望它显示为操纵杆并向其添加 X 和 Y 轴,我目前设法将 raspberry pi zero 显示为键盘并向其发送击键.通过使用this 页面作为参考,任何人都知道我的想法是否真的可行?

【问题讨论】:

    标签: raspberry-pi hid


    【解决方案1】:

    应该可以(但我没有 PI 硬件来测试它)。

    您链接中的报告描述符指定了一个仅限键盘的 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 设备)或协议(例如键盘或鼠标)。

    可能还有其他必要的更改,但正如我所说,我没有硬件可以试验。

    我希望这会有所帮助。

    【讨论】:

    • 感谢您的回复,看起来很有希望,很快就会尝试! , 可能是一个初学者的问题,但我怎样才能将您的解码预览解析为十六进制值?
    • 哇,这完全有效!!,你知道是否有任何关于如何将数据写入按钮/轴的文档?
    • 您应该能够按照您链接的文章中描述的方式进行操作。在您的情况下,您将向新定义的小工具回显 3 个字节:x、y 和 8 个按钮位。
    • 谢谢,但我根本不明白如何将这些字节格式化为 /dev/hidg0 所需的格式,就像他们在这里所做的那样echo -ne "\0\0\x4\0\0\0\0\0" &gt; /dev/hidg0 #press the A-button
    • 发送到主机的操纵杆报告的结构由您的 HID 报告描述符定义。在这种情况下,如果您想发送 x=10, y=-2,同时按下按钮 2 和 3,那么您可以将 echo -ne "\x0A\xFE\x06" 发送到您的 /dev
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    • 2017-11-24
    • 2020-05-24
    • 2020-10-21
    • 2015-05-06
    • 2016-12-14
    • 1970-01-01
    相关资源
    最近更新 更多