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