Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Absolute mouse support #6331

Closed
wants to merge 14 commits into from
Closed

Absolute mouse support #6331

wants to merge 14 commits into from

Conversation

tobozo
Copy link
Contributor

@tobozo tobozo commented Feb 22, 2022

This PR adds USBHIDAbsMouse class with absolute mouse positioning support.

TinyUSB does not appear to provide (yet) the report struct for absolute positioning, only relative positioning.

Limitations: only one of USBHIDMouse / USBHIDAbsMouse should be used.

I'm still open to discussion as how to properly contribute the abs_mouse_report_descriptor and struct abs_mouse_report_t to the TinyUSB project so it eventually lands back in the espressif codebase.

@tobozo
Copy link
Contributor Author

tobozo commented Feb 23, 2022

testing this one with all imported features from relative mouse, still not sure how to melt that properly with the existing USBHIDMouse, both absolute and relative mouse positioning can coexist so I'm not sure it should be exclusive.

typedef struct TU_ATTR_PACKED
{
  uint8_t buttons = 0;
  int16_t x = 0;
  int16_t y = 0;
  int8_t wheel = 0;
  int8_t pan = 0;
} abs_mouse_report_t;

// Absolute Mouse Report Descriptor Template
#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \
  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 absolute position [0, 32767] */ \
        HID_USAGE       ( HID_USAGE_DESKTOP_X                    ) ,\
        HID_USAGE       ( HID_USAGE_DESKTOP_Y                    ) ,\
        HID_LOGICAL_MIN  ( 0x00                                ) ,\
        HID_LOGICAL_MAX_N( 0x7FFF, 2                           ) ,\
        HID_REPORT_SIZE  ( 16                                  ) ,\
        HID_REPORT_COUNT ( 2                                   ) ,\
        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
        /* Vertical 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 \

@me-no-dev
Copy link
Member

this is a better looking descriptor. Give me a few days to wrap up other issues and will think of how to best put that in the USB.

@tobozo
Copy link
Contributor Author

tobozo commented Mar 2, 2022

been testing this and it seems to work

Also moved the new descriptor macro to hid_device.h and the abs_mouse_report_t struct declaration to hid.h.
I'll update my fork so those changes appear in this PR, but it's only for the sakes of the discussion.

[edit] looks like there are multiple copies of hid_device.h and hid.h 🙄

enum MousePositioning_t
{
  HID_MOUSE_RELATIVE,
  HID_MOUSE_ABSOLUTE
};

struct HIDMouseType_t
{
  MousePositioning_t positioning;
  const uint8_t* report_descriptor;
  size_t descriptor_size;
  size_t report_size;
};

extern HIDMouseType_t HIDMouseRel;
extern HIDMouseType_t HIDMouseAbs;


class USBHIDMouseBase: public USBHIDDevice {
public:
    USBHIDMouseBase(HIDMouseType_t *type);
    void begin(void);
    void end(void);
    void press(uint8_t b = MOUSE_LEFT);   // press LEFT by default
    void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
    bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default
    template <typename T> bool sendReport(T report) { return hid.SendReport( HID_REPORT_ID_MOUSE, &report, _type->report_size ); };
    // internal use
    uint16_t _onGetDescriptor(uint8_t* buffer);
    void buttons(uint8_t b);
protected:
    USBHID hid;
    uint8_t _buttons;
    HIDMouseType_t *_type;
};


class USBHIDRelativeMouse: public USBHIDMouseBase {
public:
    USBHIDRelativeMouse(void): USBHIDMouseBase(&HIDMouseRel) { }
    void move(int8_t x, int8_t y, int8_t wheel = 0, int8_t pan = 0);
    void click(uint8_t b = MOUSE_LEFT);
    void buttons(uint8_t b);
};


class USBHIDAbsoluteMouse: public USBHIDMouseBase {
public:
    USBHIDAbsoluteMouse(void): USBHIDMouseBase(&HIDMouseAbs) { }
    void move(int16_t x, int16_t y, int8_t wheel = 0, int8_t pan = 0);
    void click(uint8_t b = MOUSE_LEFT);
    void buttons(uint8_t b);
private:
    int16_t _lastx = 0;
    int16_t _lasty = 0;
};


// don't break examples and old sketches
#define USBHIDMouse USBHIDRelativeMouse;




USBHIDMouseBase::USBHIDMouseBase(HIDMouseType_t *type) : hid(), _buttons(0), _type(type)
{
  static bool initialized = false;
    if(!initialized){
        initialized = true;
        hid.addDevice(this, _type->descriptor_size);
    }
};

uint16_t USBHIDMouseBase::_onGetDescriptor(uint8_t* dst)
{
    memcpy(dst, _type->report_descriptor, _type->descriptor_size);
    return _type->descriptor_size;
}

void USBHIDMouseBase::begin()
{
    hid.begin();
}

void USBHIDMouseBase::end()
{
}


void USBHIDMouseBase::press(uint8_t b)
{
    buttons(_buttons | b);
}

void USBHIDMouseBase::release(uint8_t b)
{
    buttons(_buttons & ~b);
}

bool USBHIDMouseBase::isPressed(uint8_t b)
{
    if ((b & _buttons) > 0) {
        return true;
    }
    return false;
}



static const uint8_t abs_mouse_report_descriptor[] = {
    TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(HID_REPORT_ID_MOUSE))
};

HIDMouseType_t HIDMouseAbs = { HID_MOUSE_ABSOLUTE, abs_mouse_report_descriptor, sizeof(abs_mouse_report_descriptor), sizeof(abs_mouse_report_t) };


void USBHIDAbsoluteMouse::move(int16_t x, int16_t y, int8_t wheel, int8_t pan)
{
    abs_mouse_report_t report;
    report.buttons = _buttons;
    report.x       = _lastx = x;
    report.y       = _lasty = y;
    report.wheel   = wheel;
    report.pan     = pan;
    sendReport(report);
}


void USBHIDAbsoluteMouse::click(uint8_t b)
{
    _buttons = b;
    move(_lastx,_lasty);
    _buttons = 0;
    move(_lastx,_lasty);
}

void USBHIDAbsoluteMouse::buttons(uint8_t b)
{
    if (b != _buttons){
        _buttons = b;
        move(_lastx,_lasty);
    }
}



static const uint8_t rel_mouse_report_descriptor[] = {
    TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(HID_REPORT_ID_MOUSE))
};

HIDMouseType_t HIDMouseRel = { HID_MOUSE_RELATIVE, rel_mouse_report_descriptor, sizeof(rel_mouse_report_descriptor), sizeof(hid_mouse_report_t) };



void USBHIDRelativeMouse::move(int8_t x, int8_t y, int8_t wheel, int8_t pan)
{
    hid_mouse_report_t report = {
        .buttons = _buttons,
        .x       = x,
        .y       = y,
        .wheel   = wheel,
        .pan     = pan
    };
    sendReport(report);
}


void USBHIDRelativeMouse::click(uint8_t b)
{
    _buttons = b;
    move(0,0);
    _buttons = 0;
    move(0,0);
}

void USBHIDRelativeMouse::buttons(uint8_t b)
{
    if (b != _buttons){
        _buttons = b;
        move(0,0);
    }
}



@@ -300,6 +300,17 @@ typedef struct TU_ATTR_PACKED
int8_t pan; // using AC Pan
} hid_mouse_report_t;

// Absolute Mouse data struct is a copy of the Standard (relative) Mouse Report
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any change to headers in the sdk folder should be done in the appropriate remote place. in his case, it is https://github.com/hathach/tinyusb

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! PR submitted hathach/tinyusb#1363

I need to solve other C++ issues with the build breaking, I don't know how (and if) to template move(), click() and buttons() in the base class and have them superseded in the absolute/relative inherited classes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's get the descriptor merged into tinyusb and then we will discuss how to best plug it in. Probably separate class with own report ID

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are separate classes: USBHIDRelativeMouse (aliased as USBHIDMouse for legacy), and USBHIDAbsoluteMouse.

There's also a base class USBHIDMouseBase but only to provide inheritance, so it's not an issue to have separate instances and should also work with a different report ID.

I tried to solve the build errors by using virtual / override, will do more testing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build failed for ESP32 only, but looking at the error it's not coming from my pull request.

Will I have to do something to trigger the check_suite once this is fixed on arduino-esp32 repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last build error points to a missing implementation for esp32s3, I can't remember why this PR was only targeting esp32s2, but I wonder how this should be dealt with: should I also apply the hid patch to sdk/tools/esp32s3/includes/arduino_tinyusb folder?

also the mouse class needs rewriting

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

header patches should not be in the sdk folder at all. They should be in USBHIDMouse.h. In 3.0.0 SDK is no longer part of the repo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh nice, that makes more sense, also it simplifies the path

I guess this PR is no longer relevant since it's based on the 2.x.x core, should I keep it open until I can properly test it with core 3.0.0?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. It should work with 3.0.0 as well

@CLAassistant
Copy link

CLAassistant commented May 6, 2023

CLA assistant check
All committers have signed the CLA.

@tobozo tobozo closed this Nov 3, 2023
me-no-dev pushed a commit that referenced this pull request Nov 29, 2023
* Added absolute mouse support

* make click() virtual

---------

Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com>
Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants