simple mouse virtual device master
authorRobin Krens <robin@robinkrens.nl>
Sat, 28 May 2022 21:40:53 +0000 (23:40 +0200)
committerRobin Krens <robin@robinkrens.nl>
Sat, 28 May 2022 21:40:53 +0000 (23:40 +0200)
vmouse.c [new file with mode: 0644]

diff --git a/vmouse.c b/vmouse.c
new file mode 100644 (file)
index 0000000..73dc3d3
--- /dev/null
+++ b/vmouse.c
@@ -0,0 +1,152 @@
+#include <errno.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/uhid.h>
+
+#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 */
+}