1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <dirent.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8 #include <sys/inotify.h>
9 #include <sys/limits.h>
10 #include <sys/poll.h>
11 #include <linux/input.h>
12 #include <errno.h>
13
14 #include "getevent.h"
15
16 static struct pollfd *ufds;
17 static char **device_names;
18 static int nfds;
19
20 enum {
21 PRINT_DEVICE_ERRORS = 1U << 0,
22 PRINT_DEVICE = 1U << 1,
23 PRINT_DEVICE_NAME = 1U << 2,
24 PRINT_DEVICE_INFO = 1U << 3,
25 PRINT_VERSION = 1U << 4,
26 PRINT_POSSIBLE_EVENTS = 1U << 5,
27 PRINT_INPUT_PROPS = 1U << 6,
28 PRINT_HID_DESCRIPTOR = 1U << 7,
29
30 PRINT_ALL_INFO = (1U << 8) - 1,
31
32 PRINT_LABELS = 1U << 16,
33 };
34
get_label(const struct label * labels,int value)35 static const char *get_label(const struct label *labels, int value)
36 {
37 while(labels->name && value != labels->value) {
38 labels++;
39 }
40 return labels->name;
41 }
42
print_input_props(int fd)43 static int print_input_props(int fd)
44 {
45 uint8_t bits[INPUT_PROP_CNT / 8];
46 int i, j;
47 int res;
48 int count;
49 const char *bit_label;
50
51 printf(" input props:\n");
52 res = ioctl(fd, EVIOCGPROP(sizeof(bits)), bits);
53 if(res < 0) {
54 printf(" <not available\n");
55 return 1;
56 }
57 count = 0;
58 for(i = 0; i < res; i++) {
59 for(j = 0; j < 8; j++) {
60 if (bits[i] & 1 << j) {
61 bit_label = get_label(input_prop_labels, i * 8 + j);
62 if(bit_label)
63 printf(" %s\n", bit_label);
64 else
65 printf(" %04x\n", i * 8 + j);
66 count++;
67 }
68 }
69 }
70 if (!count)
71 printf(" <none>\n");
72 return 0;
73 }
74
print_possible_events(int fd,int print_flags)75 static int print_possible_events(int fd, int print_flags)
76 {
77 uint8_t *bits = NULL;
78 ssize_t bits_size = 0;
79 const char* label;
80 int i, j, k;
81 int res, res2;
82 struct label* bit_labels;
83 const char *bit_label;
84
85 printf(" events:\n");
86 for(i = EV_KEY; i <= EV_MAX; i++) { // skip EV_SYN since we cannot query its available codes
87 int count = 0;
88 while(1) {
89 res = ioctl(fd, EVIOCGBIT(i, bits_size), bits);
90 if(res < bits_size)
91 break;
92 bits_size = res + 16;
93 bits = realloc(bits, bits_size * 2);
94 if(bits == NULL) {
95 fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size);
96 return 1;
97 }
98 }
99 res2 = 0;
100 switch(i) {
101 case EV_KEY:
102 res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
103 label = "KEY";
104 bit_labels = key_labels;
105 break;
106 case EV_REL:
107 label = "REL";
108 bit_labels = rel_labels;
109 break;
110 case EV_ABS:
111 label = "ABS";
112 bit_labels = abs_labels;
113 break;
114 case EV_MSC:
115 label = "MSC";
116 bit_labels = msc_labels;
117 break;
118 case EV_LED:
119 res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
120 label = "LED";
121 bit_labels = led_labels;
122 break;
123 case EV_SND:
124 res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
125 label = "SND";
126 bit_labels = snd_labels;
127 break;
128 case EV_SW:
129 res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
130 label = "SW ";
131 bit_labels = sw_labels;
132 break;
133 case EV_REP:
134 label = "REP";
135 bit_labels = rep_labels;
136 break;
137 case EV_FF:
138 label = "FF ";
139 bit_labels = ff_labels;
140 break;
141 case EV_PWR:
142 label = "PWR";
143 bit_labels = NULL;
144 break;
145 case EV_FF_STATUS:
146 label = "FFS";
147 bit_labels = ff_status_labels;
148 break;
149 default:
150 res2 = 0;
151 label = "???";
152 bit_labels = NULL;
153 }
154 for(j = 0; j < res; j++) {
155 for(k = 0; k < 8; k++)
156 if(bits[j] & 1 << k) {
157 char down;
158 if(j < res2 && (bits[j + bits_size] & 1 << k))
159 down = '*';
160 else
161 down = ' ';
162 if(count == 0)
163 printf(" %s (%04x):", label, i);
164 else if((count & (print_flags & PRINT_LABELS ? 0x3 : 0x7)) == 0 || i == EV_ABS)
165 printf("\n ");
166 if(bit_labels && (print_flags & PRINT_LABELS)) {
167 bit_label = get_label(bit_labels, j * 8 + k);
168 if(bit_label)
169 printf(" %.20s%c%*s", bit_label, down, 20 - strlen(bit_label), "");
170 else
171 printf(" %04x%c ", j * 8 + k, down);
172 } else {
173 printf(" %04x%c", j * 8 + k, down);
174 }
175 if(i == EV_ABS) {
176 struct input_absinfo abs;
177 if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
178 printf(" : value %d, min %d, max %d, fuzz %d, flat %d, resolution %d",
179 abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat,
180 abs.resolution);
181 }
182 }
183 count++;
184 }
185 }
186 if(count)
187 printf("\n");
188 }
189 free(bits);
190 return 0;
191 }
192
print_event(int type,int code,int value,int print_flags)193 static void print_event(int type, int code, int value, int print_flags)
194 {
195 const char *type_label, *code_label, *value_label;
196
197 if (print_flags & PRINT_LABELS) {
198 type_label = get_label(ev_labels, type);
199 code_label = NULL;
200 value_label = NULL;
201
202 switch(type) {
203 case EV_SYN:
204 code_label = get_label(syn_labels, code);
205 break;
206 case EV_KEY:
207 code_label = get_label(key_labels, code);
208 value_label = get_label(key_value_labels, value);
209 break;
210 case EV_REL:
211 code_label = get_label(rel_labels, code);
212 break;
213 case EV_ABS:
214 code_label = get_label(abs_labels, code);
215 switch(code) {
216 case ABS_MT_TOOL_TYPE:
217 value_label = get_label(mt_tool_labels, value);
218 }
219 break;
220 case EV_MSC:
221 code_label = get_label(msc_labels, code);
222 break;
223 case EV_LED:
224 code_label = get_label(led_labels, code);
225 break;
226 case EV_SND:
227 code_label = get_label(snd_labels, code);
228 break;
229 case EV_SW:
230 code_label = get_label(sw_labels, code);
231 break;
232 case EV_REP:
233 code_label = get_label(rep_labels, code);
234 break;
235 case EV_FF:
236 code_label = get_label(ff_labels, code);
237 break;
238 case EV_FF_STATUS:
239 code_label = get_label(ff_status_labels, code);
240 break;
241 }
242
243 if (type_label)
244 printf("%-12.12s", type_label);
245 else
246 printf("%04x ", type);
247 if (code_label)
248 printf(" %-20.20s", code_label);
249 else
250 printf(" %04x ", code);
251 if (value_label)
252 printf(" %-20.20s", value_label);
253 else
254 printf(" %08x ", value);
255 } else {
256 printf("%04x %04x %08x", type, code, value);
257 }
258 }
259
print_hid_descriptor(int bus,int vendor,int product)260 static void print_hid_descriptor(int bus, int vendor, int product)
261 {
262 const char *dirname = "/sys/kernel/debug/hid";
263 char prefix[16];
264 DIR *dir;
265 struct dirent *de;
266 char filename[PATH_MAX];
267 FILE *file;
268 char line[2048];
269
270 snprintf(prefix, sizeof(prefix), "%04X:%04X:%04X.", bus, vendor, product);
271
272 dir = opendir(dirname);
273 if(dir == NULL)
274 return;
275 while((de = readdir(dir))) {
276 if (strstr(de->d_name, prefix) == de->d_name) {
277 snprintf(filename, sizeof(filename), "%s/%s/rdesc", dirname, de->d_name);
278
279 file = fopen(filename, "r");
280 if (file) {
281 printf(" HID descriptor: %s\n\n", de->d_name);
282 while (fgets(line, sizeof(line), file)) {
283 fputs(" ", stdout);
284 fputs(line, stdout);
285 }
286 fclose(file);
287 puts("");
288 }
289 }
290 }
291 closedir(dir);
292 }
293
open_device(const char * device,int print_flags)294 static int open_device(const char *device, int print_flags)
295 {
296 int version;
297 int fd;
298 struct pollfd *new_ufds;
299 char **new_device_names;
300 char name[80];
301 char location[80];
302 char idstr[80];
303 struct input_id id;
304
305 fd = open(device, O_RDWR);
306 if(fd < 0) {
307 if(print_flags & PRINT_DEVICE_ERRORS)
308 fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
309 return -1;
310 }
311
312 if(ioctl(fd, EVIOCGVERSION, &version)) {
313 if(print_flags & PRINT_DEVICE_ERRORS)
314 fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
315 return -1;
316 }
317 if(ioctl(fd, EVIOCGID, &id)) {
318 if(print_flags & PRINT_DEVICE_ERRORS)
319 fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
320 return -1;
321 }
322 name[sizeof(name) - 1] = '\0';
323 location[sizeof(location) - 1] = '\0';
324 idstr[sizeof(idstr) - 1] = '\0';
325 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
326 //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
327 name[0] = '\0';
328 }
329 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
330 //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
331 location[0] = '\0';
332 }
333 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
334 //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
335 idstr[0] = '\0';
336 }
337
338 new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
339 if(new_ufds == NULL) {
340 fprintf(stderr, "out of memory\n");
341 return -1;
342 }
343 ufds = new_ufds;
344 new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
345 if(new_device_names == NULL) {
346 fprintf(stderr, "out of memory\n");
347 return -1;
348 }
349 device_names = new_device_names;
350
351 if(print_flags & PRINT_DEVICE)
352 printf("add device %d: %s\n", nfds, device);
353 if(print_flags & PRINT_DEVICE_INFO)
354 printf(" bus: %04x\n"
355 " vendor %04x\n"
356 " product %04x\n"
357 " version %04x\n",
358 id.bustype, id.vendor, id.product, id.version);
359 if(print_flags & PRINT_DEVICE_NAME)
360 printf(" name: \"%s\"\n", name);
361 if(print_flags & PRINT_DEVICE_INFO)
362 printf(" location: \"%s\"\n"
363 " id: \"%s\"\n", location, idstr);
364 if(print_flags & PRINT_VERSION)
365 printf(" version: %d.%d.%d\n",
366 version >> 16, (version >> 8) & 0xff, version & 0xff);
367
368 if(print_flags & PRINT_POSSIBLE_EVENTS) {
369 print_possible_events(fd, print_flags);
370 }
371
372 if(print_flags & PRINT_INPUT_PROPS) {
373 print_input_props(fd);
374 }
375 if(print_flags & PRINT_HID_DESCRIPTOR) {
376 print_hid_descriptor(id.bustype, id.vendor, id.product);
377 }
378
379 ufds[nfds].fd = fd;
380 ufds[nfds].events = POLLIN;
381 device_names[nfds] = strdup(device);
382 nfds++;
383
384 return 0;
385 }
386
close_device(const char * device,int print_flags)387 int close_device(const char *device, int print_flags)
388 {
389 int i;
390 for(i = 1; i < nfds; i++) {
391 if(strcmp(device_names[i], device) == 0) {
392 int count = nfds - i - 1;
393 if(print_flags & PRINT_DEVICE)
394 printf("remove device %d: %s\n", i, device);
395 free(device_names[i]);
396 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
397 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
398 nfds--;
399 return 0;
400 }
401 }
402 if(print_flags & PRINT_DEVICE_ERRORS)
403 fprintf(stderr, "remote device: %s not found\n", device);
404 return -1;
405 }
406
read_notify(const char * dirname,int nfd,int print_flags)407 static int read_notify(const char *dirname, int nfd, int print_flags)
408 {
409 int res;
410 char devname[PATH_MAX];
411 char *filename;
412 char event_buf[512];
413 int event_size;
414 int event_pos = 0;
415 struct inotify_event *event;
416
417 res = read(nfd, event_buf, sizeof(event_buf));
418 if(res < (int)sizeof(*event)) {
419 if(errno == EINTR)
420 return 0;
421 fprintf(stderr, "could not get event, %s\n", strerror(errno));
422 return 1;
423 }
424 //printf("got %d bytes of event information\n", res);
425
426 strcpy(devname, dirname);
427 filename = devname + strlen(devname);
428 *filename++ = '/';
429
430 while(res >= (int)sizeof(*event)) {
431 event = (struct inotify_event *)(event_buf + event_pos);
432 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
433 if(event->len) {
434 strcpy(filename, event->name);
435 if(event->mask & IN_CREATE) {
436 open_device(devname, print_flags);
437 }
438 else {
439 close_device(devname, print_flags);
440 }
441 }
442 event_size = sizeof(*event) + event->len;
443 res -= event_size;
444 event_pos += event_size;
445 }
446 return 0;
447 }
448
scan_dir(const char * dirname,int print_flags)449 static int scan_dir(const char *dirname, int print_flags)
450 {
451 char devname[PATH_MAX];
452 char *filename;
453 DIR *dir;
454 struct dirent *de;
455 dir = opendir(dirname);
456 if(dir == NULL)
457 return -1;
458 strcpy(devname, dirname);
459 filename = devname + strlen(devname);
460 *filename++ = '/';
461 while((de = readdir(dir))) {
462 if(de->d_name[0] == '.' &&
463 (de->d_name[1] == '\0' ||
464 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
465 continue;
466 strcpy(filename, de->d_name);
467 open_device(devname, print_flags);
468 }
469 closedir(dir);
470 return 0;
471 }
472
usage(int argc,char * argv[])473 static void usage(int argc, char *argv[])
474 {
475 fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
476 fprintf(stderr, " -t: show time stamps\n");
477 fprintf(stderr, " -n: don't print newlines\n");
478 fprintf(stderr, " -s: print switch states for given bits\n");
479 fprintf(stderr, " -S: print all switch states\n");
480 fprintf(stderr, " -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)\n");
481 fprintf(stderr, " -d: show HID descriptor, if available\n");
482 fprintf(stderr, " -p: show possible events (errs, dev, name, pos. events)\n");
483 fprintf(stderr, " -i: show all device info and possible events\n");
484 fprintf(stderr, " -l: label event types and names in plain text\n");
485 fprintf(stderr, " -q: quiet (clear verbosity mask)\n");
486 fprintf(stderr, " -c: print given number of events then exit\n");
487 fprintf(stderr, " -r: print rate events are received\n");
488 }
489
getevent_main(int argc,char * argv[])490 int getevent_main(int argc, char *argv[])
491 {
492 int c;
493 int i;
494 int res;
495 int pollres;
496 int get_time = 0;
497 int print_device = 0;
498 char *newline = "\n";
499 uint16_t get_switch = 0;
500 struct input_event event;
501 int version;
502 int print_flags = 0;
503 int print_flags_set = 0;
504 int dont_block = -1;
505 int event_count = 0;
506 int sync_rate = 0;
507 int64_t last_sync_time = 0;
508 const char *device = NULL;
509 const char *device_path = "/dev/input";
510
511 opterr = 0;
512 do {
513 c = getopt(argc, argv, "tns:Sv::dpilqc:rh");
514 if (c == EOF)
515 break;
516 switch (c) {
517 case 't':
518 get_time = 1;
519 break;
520 case 'n':
521 newline = "";
522 break;
523 case 's':
524 get_switch = strtoul(optarg, NULL, 0);
525 if(dont_block == -1)
526 dont_block = 1;
527 break;
528 case 'S':
529 get_switch = ~0;
530 if(dont_block == -1)
531 dont_block = 1;
532 break;
533 case 'v':
534 if(optarg)
535 print_flags |= strtoul(optarg, NULL, 0);
536 else
537 print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
538 print_flags_set = 1;
539 break;
540 case 'd':
541 print_flags |= PRINT_HID_DESCRIPTOR;
542 break;
543 case 'p':
544 print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE
545 | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS | PRINT_INPUT_PROPS;
546 print_flags_set = 1;
547 if(dont_block == -1)
548 dont_block = 1;
549 break;
550 case 'i':
551 print_flags |= PRINT_ALL_INFO;
552 print_flags_set = 1;
553 if(dont_block == -1)
554 dont_block = 1;
555 break;
556 case 'l':
557 print_flags |= PRINT_LABELS;
558 break;
559 case 'q':
560 print_flags_set = 1;
561 break;
562 case 'c':
563 event_count = atoi(optarg);
564 dont_block = 0;
565 break;
566 case 'r':
567 sync_rate = 1;
568 break;
569 case '?':
570 fprintf(stderr, "%s: invalid option -%c\n",
571 argv[0], optopt);
572 case 'h':
573 usage(argc, argv);
574 exit(1);
575 }
576 } while (1);
577 if(dont_block == -1)
578 dont_block = 0;
579
580 if (optind + 1 == argc) {
581 device = argv[optind];
582 optind++;
583 }
584 if (optind != argc) {
585 usage(argc, argv);
586 exit(1);
587 }
588 nfds = 1;
589 ufds = calloc(1, sizeof(ufds[0]));
590 ufds[0].fd = inotify_init();
591 ufds[0].events = POLLIN;
592 if(device) {
593 if(!print_flags_set)
594 print_flags |= PRINT_DEVICE_ERRORS;
595 res = open_device(device, print_flags);
596 if(res < 0) {
597 return 1;
598 }
599 } else {
600 if(!print_flags_set)
601 print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
602 print_device = 1;
603 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
604 if(res < 0) {
605 fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
606 return 1;
607 }
608 res = scan_dir(device_path, print_flags);
609 if(res < 0) {
610 fprintf(stderr, "scan dir failed for %s\n", device_path);
611 return 1;
612 }
613 }
614
615 if(get_switch) {
616 for(i = 1; i < nfds; i++) {
617 uint16_t sw;
618 res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
619 if(res < 0) {
620 fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
621 return 1;
622 }
623 sw &= get_switch;
624 printf("%04x%s", sw, newline);
625 }
626 }
627
628 if(dont_block)
629 return 0;
630
631 while(1) {
632 pollres = poll(ufds, nfds, -1);
633 //printf("poll %d, returned %d\n", nfds, pollres);
634 if(ufds[0].revents & POLLIN) {
635 read_notify(device_path, ufds[0].fd, print_flags);
636 }
637 for(i = 1; i < nfds; i++) {
638 if(ufds[i].revents) {
639 if(ufds[i].revents & POLLIN) {
640 res = read(ufds[i].fd, &event, sizeof(event));
641 if(res < (int)sizeof(event)) {
642 fprintf(stderr, "could not get event\n");
643 return 1;
644 }
645 if(get_time) {
646 printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);
647 }
648 if(print_device)
649 printf("%s: ", device_names[i]);
650 print_event(event.type, event.code, event.value, print_flags);
651 if(sync_rate && event.type == 0 && event.code == 0) {
652 int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
653 if(last_sync_time)
654 printf(" rate %lld", 1000000LL / (now - last_sync_time));
655 last_sync_time = now;
656 }
657 printf("%s", newline);
658 if(event_count && --event_count == 0)
659 return 0;
660 }
661 }
662 }
663 }
664
665 return 0;
666 }
667