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