115 lines
4.8 KiB
C++
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;
|
|
}
|
|
};
|