Files
m5stack-automation-tool/firmware/MacroPad/abs_mouse.h
T
2026-07-17 15:29:53 -04:00

115 lines
4.8 KiB
C++

#pragma once
#include "USBHID.h"
#include <string.h>
// Absolute-position mouse HID device.
//
// The stock USBHIDMouse is RELATIVE (it reports dx/dy deltas), which
// accumulates error and drifts the remote cursor out of sync over a lossy
// BLE link. This device reports ABSOLUTE coordinates (0..32767 spanning the
// target's screen) so every report fully specifies where the cursor is — a
// dropped report just means the next one re-pins the position, never drift.
// That's exactly what the BT Keyboard virtual trackpad needs to stay synced
// across many devices.
//
// Report payload (the 1-byte report ID is prepended by USBHID::SendReport):
// byte 0 : buttons bitmask (bit0 left, bit1 right, bit2 middle)
// bytes 1-2 : X (uint16 little-endian, 0..32767)
// bytes 3-4 : Y (uint16 little-endian, 0..32767)
// byte 5 : wheel (int8, relative scroll tick)
#define ABS_MOUSE_REPORT_ID 0x0A
#define ABS_MOUSE_BTN_LEFT 0x01
#define ABS_MOUSE_BTN_RIGHT 0x02
#define ABS_MOUSE_BTN_MIDDLE 0x04
#define ABS_MOUSE_MAX 32767
class AbsoluteMouse : public USBHIDDevice {
public:
AbsoluteMouse() : _hid(), _buttons(0), _x(0), _y(0) {
static bool initialized = false;
if (!initialized) {
initialized = true;
uint16_t len = 0;
_descriptor(&len);
_hid.addDevice(this, len);
}
}
void begin() { _hid.begin(); }
// Called by the TinyUSB stack to fetch our report descriptor.
uint16_t _onGetDescriptor(uint8_t* buffer) override {
uint16_t len = 0;
const uint8_t* d = _descriptor(&len);
memcpy(buffer, d, len);
return len;
}
bool ready() { return _hid.ready(); }
// Emit one absolute report. ``x``/``y`` are 0..ABS_MOUSE_MAX; ``wheel``
// is a relative scroll tick. Returns the SendReport result.
bool report(uint8_t buttons, uint16_t x, uint16_t y, int8_t wheel) {
if (x > ABS_MOUSE_MAX) x = ABS_MOUSE_MAX;
if (y > ABS_MOUSE_MAX) y = ABS_MOUSE_MAX;
_buttons = buttons;
_x = x;
_y = y;
uint8_t r[6];
r[0] = buttons;
r[1] = (uint8_t)(x & 0xFF);
r[2] = (uint8_t)((x >> 8) & 0xFF);
r[3] = (uint8_t)(y & 0xFF);
r[4] = (uint8_t)((y >> 8) & 0xFF);
r[5] = (uint8_t)wheel;
return _hid.SendReport(ABS_MOUSE_REPORT_ID, r, sizeof(r));
}
private:
USBHID _hid;
uint8_t _buttons;
uint16_t _x, _y;
static const uint8_t* _descriptor(uint16_t* outLen) {
static const uint8_t d[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x85, ABS_MOUSE_REPORT_ID, // Report ID
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x03, // Usage Maximum (3)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs)
0x95, 0x01, // Report Count (1)
0x75, 0x05, // Report Size (5)
0x81, 0x03, // Input (Const) - padding
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x00, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Var,Rel)
0xC0, // End Collection
0xC0 // End Collection
};
*outLen = sizeof(d);
return d;
}
};