4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * The code may be used by anyone for any purpose,
7 * and can serve as a starting point for developing
8 * applications using uhid.
12 * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
13 * program as root and then use the following keys to control the mouse:
14 * q: Quit the application
15 * 1: Toggle left button (down, up, ...)
16 * 2: Toggle right button
17 * 3: Toggle middle button
25 * If uhid is not available as /dev/uhid, then you can pass a different path as
27 * If <linux/uhid.h> is not installed in /usr, then compile this with:
28 * gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c
29 * And ignore the warning about kernel headers. However, it is recommended to
30 * use the installed uhid.h if available.
42 #include <linux/uhid.h>
44 /* HID Report Desciptor
45 * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
46 * as the kernel will parse it:
50 * Physical(GenericDesktop.Pointer)
51 * Application(GenericDesktop.Mouse)
61 * Flags( Variable Absolute )
63 * Physical(GenericDesktop.Pointer)
64 * Application(GenericDesktop.Mouse)
68 * GenericDesktop.Wheel
69 * Logical Minimum(-128)
70 * Logical Maximum(127)
74 * Flags( Variable Relative )
76 * This is the mapping that we expect:
77 * Button.0001 ---> Key.LeftBtn
78 * Button.0002 ---> Key.RightBtn
79 * Button.0003 ---> Key.MiddleBtn
80 * GenericDesktop.X ---> Relative.X
81 * GenericDesktop.Y ---> Relative.Y
82 * GenericDesktop.Wheel ---> Relative.Wheel
84 * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
85 * This file should print the same information as showed above.
88 static unsigned char rdesc[] = {
89 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
90 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
91 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
92 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
93 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
94 0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
95 0x81, 0x06, 0xc0, 0xc0,
98 static int uhid_write(int fd, const struct uhid_event *ev)
102 ret = write(fd, ev, sizeof(*ev));
104 fprintf(stderr, "Cannot write to uhid: %m\n");
106 } else if (ret != sizeof(*ev)) {
107 fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n",
115 static int create(int fd)
117 struct uhid_event ev;
119 memset(&ev, 0, sizeof(ev));
120 ev.type = UHID_CREATE;
121 strcpy((char*)ev.u.create.name, "test-uhid-device");
122 ev.u.create.rd_data = rdesc;
123 ev.u.create.rd_size = sizeof(rdesc);
124 ev.u.create.bus = BUS_USB;
125 ev.u.create.vendor = 0x15d9;
126 ev.u.create.product = 0x0a37;
127 ev.u.create.version = 0;
128 ev.u.create.country = 0;
130 return uhid_write(fd, &ev);
133 static void destroy(int fd)
135 struct uhid_event ev;
137 memset(&ev, 0, sizeof(ev));
138 ev.type = UHID_DESTROY;
143 static int event(int fd)
145 struct uhid_event ev;
148 memset(&ev, 0, sizeof(ev));
149 ret = read(fd, &ev, sizeof(ev));
151 fprintf(stderr, "Read HUP on uhid-cdev\n");
153 } else if (ret < 0) {
154 fprintf(stderr, "Cannot read uhid-cdev: %m\n");
156 } else if (ret != sizeof(ev)) {
157 fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n",
164 fprintf(stderr, "UHID_START from uhid-dev\n");
167 fprintf(stderr, "UHID_STOP from uhid-dev\n");
170 fprintf(stderr, "UHID_OPEN from uhid-dev\n");
173 fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
176 fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
179 fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
182 fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
188 static bool btn1_down;
189 static bool btn2_down;
190 static bool btn3_down;
191 static signed char abs_hor;
192 static signed char abs_ver;
193 static signed char wheel;
195 static int send_event(int fd)
197 struct uhid_event ev;
199 memset(&ev, 0, sizeof(ev));
200 ev.type = UHID_INPUT;
204 ev.u.input.data[0] |= 0x1;
206 ev.u.input.data[0] |= 0x2;
208 ev.u.input.data[0] |= 0x4;
210 ev.u.input.data[1] = abs_hor;
211 ev.u.input.data[2] = abs_ver;
212 ev.u.input.data[3] = wheel;
214 return uhid_write(fd, &ev);
217 static int keyboard(int fd)
222 ret = read(STDIN_FILENO, buf, sizeof(buf));
224 fprintf(stderr, "Read HUP on stdin\n");
226 } else if (ret < 0) {
227 fprintf(stderr, "Cannot read stdin: %m\n");
231 for (i = 0; i < ret; ++i) {
234 btn1_down = !btn1_down;
235 ret = send_event(fd);
240 btn2_down = !btn2_down;
241 ret = send_event(fd);
246 btn3_down = !btn3_down;
247 ret = send_event(fd);
253 ret = send_event(fd);
260 ret = send_event(fd);
267 ret = send_event(fd);
274 ret = send_event(fd);
281 ret = send_event(fd);
288 ret = send_event(fd);
296 fprintf(stderr, "Invalid input: %c\n", buf[i]);
303 int main(int argc, char **argv)
306 const char *path = "/dev/uhid";
307 struct pollfd pfds[2];
309 struct termios state;
311 ret = tcgetattr(STDIN_FILENO, &state);
313 fprintf(stderr, "Cannot get tty state\n");
315 state.c_lflag &= ~ICANON;
316 state.c_cc[VMIN] = 1;
317 ret = tcsetattr(STDIN_FILENO, TCSANOW, &state);
319 fprintf(stderr, "Cannot set tty state\n");
323 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
324 fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
331 fprintf(stderr, "Open uhid-cdev %s\n", path);
332 fd = open(path, O_RDWR | O_CLOEXEC);
334 fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path);
338 fprintf(stderr, "Create uhid device\n");
345 pfds[0].fd = STDIN_FILENO;
346 pfds[0].events = POLLIN;
348 pfds[1].events = POLLIN;
350 fprintf(stderr, "Press 'q' to quit...\n");
352 ret = poll(pfds, 2, -1);
354 fprintf(stderr, "Cannot poll for fds: %m\n");
357 if (pfds[0].revents & POLLHUP) {
358 fprintf(stderr, "Received HUP on stdin\n");
361 if (pfds[1].revents & POLLHUP) {
362 fprintf(stderr, "Received HUP on uhid-cdev\n");
366 if (pfds[0].revents & POLLIN) {
371 if (pfds[1].revents & POLLIN) {
378 fprintf(stderr, "Destroy uhid device\n");