10 #include <linux/uhid.h>
12 #define SLEEP_TIME_SEC 10
14 /* mouse report descriptor
15 * you can use a tool like https://eleccelerator.com/usbdescreqparser/
16 * or rip a report descriptor with usbhid-dump
17 * don't try to make any sense of the numbers, it is mostly legacy
20 static unsigned char rdesc[] = {
21 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
22 0x09, 0x02, // Usage (Mouse)
23 0xA1, 0x01, // Collection (Application)
24 0x09, 0x01, // Usage (Pointer)
25 0xA1, 0x00, // Collection (Physical)
26 0x05, 0x09, // Usage Page (Button)
27 0x19, 0x01, // Usage Minimum (0x01)
28 0x29, 0x03, // Usage Maximum (0x03)
29 0x15, 0x00, // Logical Minimum (0)
30 0x25, 0x01, // Logical Maximum (1)
31 0x75, 0x01, // Report Size (1)
32 0x95, 0x03, // Report Count (3)
33 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
34 0x75, 0x05, // Report Size (5)
35 0x95, 0x01, // Report Count (1)
36 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
37 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
38 0x09, 0x30, // Usage (X)
39 0x09, 0x31, // Usage (Y)
40 0x09, 0x38, // Usage (Wheel)
41 0x15, 0x81, // Logical Minimum (-127)
42 0x25, 0x7F, // Logical Maximum (127)
43 0x75, 0x08, // Report Size (8)
44 0x95, 0x03, // Report Count (3)
45 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
46 0xC0, // End Collection
47 0xC0, // End Collection
52 /* input report: report id is 0 (not specified in report
53 * descriptor so assumed */
54 typedef struct _report {
55 unsigned char buttons;
61 static report_t in_report;
63 static int uhid_write(int fd, const struct uhid_event *ev)
67 ret = write(fd, ev, sizeof(*ev));
69 fprintf(stderr, "cannot write to uhid: %m\n");
71 } else if (ret != sizeof(*ev)) {
72 fprintf(stderr, "wrong size written to uhid: %ld != %lu\n",
80 static int create(int fd)
84 memset(&ev, 0, sizeof(ev));
85 ev.type = UHID_CREATE;
86 strcpy((char*)ev.u.create.name, "mr_woggle's HID device");
87 ev.u.create.rd_data = rdesc;
88 ev.u.create.rd_size = sizeof(rdesc);
89 ev.u.create.bus = BUS_BLUETOOTH;
90 ev.u.create.vendor = 0x1234;
91 ev.u.create.product = 0xabcd;
92 ev.u.create.version = 1;
93 ev.u.create.country = 0;
95 return uhid_write(fd, &ev);
98 static int send_event(int fd)
100 struct uhid_event ev;
102 memset(&ev, 0, sizeof(ev));
103 ev.type = UHID_INPUT;
105 /* move mouse two pixels to the right */
108 ev.u.input.size = 5; /* includes report ID */
109 memcpy(ev.u.input.data, (uint8_t *) &in_report, sizeof(in_report));
111 return uhid_write(fd, &ev);
115 int main(int argc, char **argv)
118 const char *path = "/dev/uhid";
122 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
123 fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
130 fd = open(path, O_RDWR | O_CLOEXEC);
132 fprintf(stderr, "cannot open uhid-cdev (try as root?) %s: %m\n", path);
139 fprintf(stderr, "xannot create uhid device");
143 fprintf(stderr, "created virtual HID device\n");
144 fprintf(stderr, "ctrl-c to quit\n");
148 sleep(SLEEP_TIME_SEC);