From: Robin Krens Date: Sat, 28 May 2022 21:40:53 +0000 (+0200) Subject: simple mouse virtual device X-Git-Url: https://robinkrens.nl/gitweb/?a=commitdiff_plain;h=HEAD;p=uhid-examples simple mouse virtual device --- dc7ec815b2597a4a201dc8361c9bdd1e9b6ebdc6 diff --git a/vmouse.c b/vmouse.c new file mode 100644 index 0000000..73dc3d3 --- /dev/null +++ b/vmouse.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SLEEP_TIME_SEC 10 + +/* mouse report descriptor + * you can use a tool like https://eleccelerator.com/usbdescreqparser/ + * or rip a report descriptor with usbhid-dump + * don't try to make any sense of the numbers, it is mostly legacy + * convention */ + +static unsigned char rdesc[] = { +0x05, 0x01, // Usage Page (Generic Desktop Ctrls) +0x09, 0x02, // Usage (Mouse) +0xA1, 0x01, // Collection (Application) +0x09, 0x01, // Usage (Pointer) +0xA1, 0x00, // Collection (Physical) +0x05, 0x09, // Usage Page (Button) +0x19, 0x01, // Usage Minimum (0x01) +0x29, 0x03, // Usage Maximum (0x03) +0x15, 0x00, // Logical Minimum (0) +0x25, 0x01, // Logical Maximum (1) +0x75, 0x01, // Report Size (1) +0x95, 0x03, // Report Count (3) +0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) +0x75, 0x05, // Report Size (5) +0x95, 0x01, // Report Count (1) +0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) +0x05, 0x01, // Usage Page (Generic Desktop Ctrls) +0x09, 0x30, // Usage (X) +0x09, 0x31, // Usage (Y) +0x09, 0x38, // Usage (Wheel) +0x15, 0x81, // Logical Minimum (-127) +0x25, 0x7F, // Logical Maximum (127) +0x75, 0x08, // Report Size (8) +0x95, 0x03, // Report Count (3) +0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) +0xC0, // End Collection +0xC0, // End Collection + +// 52 bytes +}; + +/* input report: report id is 0 (not specified in report + * descriptor so assumed */ +typedef struct _report { + unsigned char buttons; + unsigned char x_pos; + unsigned char y_pos; + unsigned char wheel; +} report_t; + +static report_t in_report; + +static int uhid_write(int fd, const struct uhid_event *ev) +{ + ssize_t ret; + + ret = write(fd, ev, sizeof(*ev)); + if (ret < 0) { + fprintf(stderr, "cannot write to uhid: %m\n"); + return -errno; + } else if (ret != sizeof(*ev)) { + fprintf(stderr, "wrong size written to uhid: %ld != %lu\n", + ret, sizeof(ev)); + return -EFAULT; + } else { + return 0; + } +} + +static int create(int fd) +{ + struct uhid_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_CREATE; + strcpy((char*)ev.u.create.name, "mr_woggle's HID device"); + ev.u.create.rd_data = rdesc; + ev.u.create.rd_size = sizeof(rdesc); + ev.u.create.bus = BUS_BLUETOOTH; + ev.u.create.vendor = 0x1234; + ev.u.create.product = 0xabcd; + ev.u.create.version = 1; + ev.u.create.country = 0; + + return uhid_write(fd, &ev); +} + +static int send_event(int fd) +{ + struct uhid_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_INPUT; + + /* move mouse two pixels to the right */ + in_report.x_pos = 2; + + ev.u.input.size = 5; /* includes report ID */ + memcpy(ev.u.input.data, (uint8_t *) &in_report, sizeof(in_report)); + + return uhid_write(fd, &ev); +} + + +int main(int argc, char **argv) +{ + int fd; + const char *path = "/dev/uhid"; + int ret; + + if (argc >= 2) { + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { + fprintf(stderr, "Usage: %s [%s]\n", argv[0], path); + return EXIT_SUCCESS; + } else { + path = argv[1]; + } + } + + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) { + fprintf(stderr, "cannot open uhid-cdev (try as root?) %s: %m\n", path); + return EXIT_FAILURE; + } + + ret = create(fd); + if (ret) { + close(fd); + fprintf(stderr, "xannot create uhid device"); + return EXIT_FAILURE; + } + + fprintf(stderr, "created virtual HID device\n"); + fprintf(stderr, "ctrl-c to quit\n"); + + while (1) { + send_event(fd); + sleep(SLEEP_TIME_SEC); + } + + /* ugly exit */ +}