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
117 changes: 89 additions & 28 deletions libraries/USB/src/USBHIDMouse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,69 +24,130 @@

#include "USBHIDMouse.h"

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

USBHIDMouse::USBHIDMouse(): hid(), _buttons(0){
static bool initialized = false;


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

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

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

void USBHIDMouse::end(){
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 USBHIDMouse::move(int8_t x, int8_t y, int8_t wheel, int8_t pan){

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
};
hid.SendReport(HID_REPORT_ID_MOUSE, &report, sizeof(report));
sendReport(report);
}

void USBHIDMouse::click(uint8_t b){

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

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

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

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

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


#endif /* CONFIG_TINYUSB_HID_ENABLED */
64 changes: 53 additions & 11 deletions libraries/USB/src/USBHIDMouse.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,67 @@
#define MOUSE_FORWARD 0x10
#define MOUSE_ALL 0x1F

class USBHIDMouse: public USBHIDDevice {
private:
USBHID hid;
uint8_t _buttons;
void buttons(uint8_t b);
bool write(int8_t x, int8_t y, int8_t vertical, int8_t horizontal);

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:
USBHIDMouse(void);
USBHIDMouseBase(HIDMouseType_t *type);
void begin(void);
void end(void);

void click(uint8_t b = MOUSE_LEFT);
void move(int8_t x, int8_t y, int8_t wheel = 0, int8_t pan = 0);
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
typedef USBHIDRelativeMouse USBHIDMouse;


#endif
Original file line number Diff line number Diff line change
Expand Up @@ -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

// with int16_t instead of int8_t for X and Y coordinates.
typedef struct TU_ATTR_PACKED
{
uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
int16_t x; /**< Current x position of the mouse. */
int16_t y; /**< Current y position of the mouse. */
int8_t wheel; /**< Current delta wheel movement on the mouse. */
int8_t pan; // using AC Pan
} abs_mouse_report_t;

/// Standard Mouse Buttons Bitmap
typedef enum
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,55 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_COLLECTION_END , \
HID_COLLECTION_END \

// 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 \

// Consumer Control Report Descriptor Template
#define TUD_HID_REPORT_DESC_CONSUMER(...) \
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\
Expand Down