espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.31k stars 7.35k forks source link

16-bit relative USB mouse support #9232

Open wareya opened 7 months ago

wareya commented 7 months ago

Related area

Gaming Mouse

Hardware specification

ESP32-S2

Is your feature request related to a problem?

I'm making a gaming mouse using an ESP32-S2-DevKitM-1U. Modern gaming mice all report at 1000hz with 16 bits of motion per frame.

The HID USB mouse implementation only support 8 bits of motion data per frame: https://github.com/espressif/arduino-esp32/blob/master/libraries/USB/src/USBHIDMouse.cpp

At 125hz and 800dpi, this limits the max tracking speed to 0.5 meters per second. At 1000hz, it's 4 meters per second, which sounds like a lot, but isn't enough for game genres that involve very fast flicking. At higher DPIs, the max tracking speed is reduced; 800dpi isn't really enough to run a HiDPI monitor any more, so "silly" DPIs like 1600, 3200, etc. are increasingly common.

TinyUSB doesn't seem to have a report type for 16-bit mice out of the box, but someone seems to have gotten it working anyway: https://github.com/hathach/tinyusb/issues/366

Describe the solution you'd like

Add a second class that uses 16-bit motion deltas and a proper report descriptor.

Describe alternatives you've considered

Overclocking above 1000hz (e.g. to 8000hz) only works on "High-Speed" USB devices, not "Full-Speed" as is usually used for keyboards and mice.

Additional context

No response

I have checked existing list of Feature requests and the Contribution Guide

wareya commented 7 months ago

This header file works with the 3.0.0-a version of the ardunio esp32 support library:

#include <USB.h>
#include <USBHID.h>
#include <USBHIDMouse.h>

#define TUD_HID_REPORT_DESC_MOUSE16(...) \
  HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP      )                   ,\
  HID_USAGE      ( HID_USAGE_DESKTOP_MOUSE     )                   ,\
  HID_COLLECTION ( HID_COLLECTION_APPLICATION  )                   ,\
    /* Report ID if any */\
    __VA_ARGS__ \
    HID_USAGE      ( HID_USAGE_DESKTOP_POINTER )                   ,\
    HID_COLLECTION ( HID_COLLECTION_PHYSICAL   )                   ,\
      HID_USAGE_PAGE  ( HID_USAGE_PAGE_BUTTON  )                   ,\
        HID_USAGE_MIN   ( 1                                      ) ,\
        HID_USAGE_MAX   ( 5                                      ) ,\
        HID_LOGICAL_MIN ( 0                                      ) ,\
        HID_LOGICAL_MAX ( 1                                      ) ,\
        /* Left, Right, Middle, Backward, Forward buttons */ \
        HID_REPORT_COUNT( 5                                      ) ,\
        HID_REPORT_SIZE ( 1                                      ) ,\
        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
        /* 3 bit padding */ \
        HID_REPORT_COUNT( 1                                      ) ,\
        HID_REPORT_SIZE ( 3                                      ) ,\
        HID_INPUT       ( HID_CONSTANT                           ) ,\
      HID_USAGE_PAGE  ( HID_USAGE_PAGE_DESKTOP )                   ,\
        /* X, Y position [-32767, 32767] */ \
        HID_USAGE       ( HID_USAGE_DESKTOP_X                    ) ,\
        HID_USAGE       ( HID_USAGE_DESKTOP_Y                    ) ,\
        HID_LOGICAL_MIN_N ( 0x8001, 2                            ) ,\
        HID_LOGICAL_MAX_N ( 0x7fff, 2                            ) ,\
        HID_REPORT_COUNT( 2                                      ) ,\
        HID_REPORT_SIZE ( 16                                     ) ,\
        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
        /* Verital wheel scroll [-127, 127] */ \
        HID_USAGE       ( HID_USAGE_DESKTOP_WHEEL                )  ,\
        HID_LOGICAL_MIN ( 0x81                                   )  ,\
        HID_LOGICAL_MAX ( 0x7f                                   )  ,\
        HID_REPORT_COUNT( 1                                      )  ,\
        HID_REPORT_SIZE ( 8                                      )  ,\
        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_RELATIVE )  ,\
      HID_USAGE_PAGE  ( HID_USAGE_PAGE_CONSUMER ), \
       /* Horizontal wheel scroll [-127, 127] */ \
        HID_USAGE_N     ( HID_USAGE_CONSUMER_AC_PAN, 2           ), \
        HID_LOGICAL_MIN ( 0x81                                   ), \
        HID_LOGICAL_MAX ( 0x7f                                   ), \
        HID_REPORT_COUNT( 1                                      ), \
        HID_REPORT_SIZE ( 8                                      ), \
        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
    HID_COLLECTION_END                                            , \
  HID_COLLECTION_END

static const uint8_t rel16_mouse_report_descriptor[] = {
    TUD_HID_REPORT_DESC_MOUSE16(HID_REPORT_ID(HID_REPORT_ID_MOUSE))
};

typedef struct TU_ATTR_PACKED
{
    uint8_t buttons;
    int16_t  x;
    int16_t  y;
    int8_t  wheel;
    int8_t  pan;
} hid_mouse_report_16_t;

HIDMouseType_t HIDMouseRel16 = { HID_MOUSE_RELATIVE, rel16_mouse_report_descriptor, sizeof(rel16_mouse_report_descriptor), sizeof(hid_mouse_report_16_t) };

class USBHIDRelativeMouse16: public USBHIDMouseBase {
public:
    USBHIDRelativeMouse16(void): USBHIDMouseBase(&HIDMouseRel16) { }
    void move(int16_t x, int16_t y, int8_t wheel = 0, int8_t pan = 0) {
        hid_mouse_report_16_t report = {
            .buttons = _buttons,
            .x       = x,
            .y       = y,
            .wheel   = wheel,
            .pan     = pan
        };
        sendReport(report);
    }
    void click(uint8_t b = MOUSE_LEFT) override {
        _buttons = b;
        move(0,0);
        _buttons = 0;
        move(0,0);
    }
    void buttons(uint8_t b) override {
        if (b != _buttons) {
            _buttons = b;
            move(0,0);
        }
    }
};

Based on USBHIDMouse.cpp.

SuGlider commented 7 months ago

@wareya - It is already within Arduino Core 3.0.0-Alpha3. You can test it.

Looking in master branch I can see that https://github.com/espressif/arduino-esp32/commits/master/libraries/USB/src/tusb_hid_mouse.h has already 2 bytes for X,Y absolute mouse feature.

Check the PR from https://github.com/espressif/arduino-esp32/pull/8831

wareya commented 7 months ago

Absolute mouse and relative mouse support is different. This is for 16-bit relative mouse support.

SuGlider commented 7 months ago

Thanks for noting that. You are right. Absolute has a different report descriptor. HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) --- HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE )

I'll work a way to add this feature.