123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdint.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/inotify.h>
- #include <sys/limits.h>
- #include <sys/poll.h>
- #include <linux/input.h>
- #include <err.h>
- #include <errno.h>
- #include <unistd.h>
- struct label {
- const char *name;
- int value;
- };
- #define LABEL(constant) { #constant, constant }
- #define LABEL_END { NULL, -1 }
- static struct label key_value_labels[] = {
- { "UP", 0 },
- { "DOWN", 1 },
- { "REPEAT", 2 },
- LABEL_END,
- };
- #include "input.h-labels.h"
- #undef LABEL
- #undef LABEL_END
- static struct pollfd *ufds;
- static char **device_names;
- static int nfds;
- enum {
- PRINT_DEVICE_ERRORS = 1U << 0,
- PRINT_DEVICE = 1U << 1,
- PRINT_DEVICE_NAME = 1U << 2,
- PRINT_DEVICE_INFO = 1U << 3,
- PRINT_VERSION = 1U << 4,
- PRINT_POSSIBLE_EVENTS = 1U << 5,
- PRINT_INPUT_PROPS = 1U << 6,
- PRINT_HID_DESCRIPTOR = 1U << 7,
- PRINT_ALL_INFO = (1U << 8) - 1,
- PRINT_LABELS = 1U << 16,
- };
- static const char *get_label(const struct label *labels, int value)
- {
- while(labels->name && value != labels->value) {
- labels++;
- }
- return labels->name;
- }
- static int print_input_props(int fd)
- {
- uint8_t bits[INPUT_PROP_CNT / 8];
- int i, j;
- int res;
- int count;
- const char *bit_label;
- printf(" input props:\n");
- res = ioctl(fd, EVIOCGPROP(sizeof(bits)), bits);
- if(res < 0) {
- printf(" <not available\n");
- return 1;
- }
- count = 0;
- for(i = 0; i < res; i++) {
- for(j = 0; j < 8; j++) {
- if (bits[i] & 1 << j) {
- bit_label = get_label(input_prop_labels, i * 8 + j);
- if(bit_label)
- printf(" %s\n", bit_label);
- else
- printf(" %04x\n", i * 8 + j);
- count++;
- }
- }
- }
- if (!count)
- printf(" <none>\n");
- return 0;
- }
- static int print_possible_events(int fd, int print_flags)
- {
- uint8_t *bits = NULL;
- ssize_t bits_size = 0;
- const char* label;
- int i, j, k;
- int res, res2;
- struct label* bit_labels;
- const char *bit_label;
- printf(" events:\n");
- for(i = EV_KEY; i <= EV_MAX; i++) { // skip EV_SYN since we cannot query its available codes
- int count = 0;
- while(1) {
- res = ioctl(fd, EVIOCGBIT(i, bits_size), bits);
- if(res < bits_size)
- break;
- bits_size = res + 16;
- bits = realloc(bits, bits_size * 2);
- if(bits == NULL)
- err(1, "failed to allocate buffer of size %d\n", (int)bits_size);
- }
- res2 = 0;
- switch(i) {
- case EV_KEY:
- res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
- label = "KEY";
- bit_labels = key_labels;
- break;
- case EV_REL:
- label = "REL";
- bit_labels = rel_labels;
- break;
- case EV_ABS:
- label = "ABS";
- bit_labels = abs_labels;
- break;
- case EV_MSC:
- label = "MSC";
- bit_labels = msc_labels;
- break;
- case EV_LED:
- res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
- label = "LED";
- bit_labels = led_labels;
- break;
- case EV_SND:
- res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
- label = "SND";
- bit_labels = snd_labels;
- break;
- case EV_SW:
- res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
- label = "SW ";
- bit_labels = sw_labels;
- break;
- case EV_REP:
- label = "REP";
- bit_labels = rep_labels;
- break;
- case EV_FF:
- label = "FF ";
- bit_labels = ff_labels;
- break;
- case EV_PWR:
- label = "PWR";
- bit_labels = NULL;
- break;
- case EV_FF_STATUS:
- label = "FFS";
- bit_labels = ff_status_labels;
- break;
- default:
- res2 = 0;
- label = "???";
- bit_labels = NULL;
- }
- for(j = 0; j < res; j++) {
- for(k = 0; k < 8; k++)
- if(bits[j] & 1 << k) {
- char down;
- if(j < res2 && (bits[j + bits_size] & 1 << k))
- down = '*';
- else
- down = ' ';
- if(count == 0)
- printf(" %s (%04x):", label, i);
- else if((count & (print_flags & PRINT_LABELS ? 0x3 : 0x7)) == 0 || i == EV_ABS)
- printf("\n ");
- if(bit_labels && (print_flags & PRINT_LABELS)) {
- bit_label = get_label(bit_labels, j * 8 + k);
- if(bit_label)
- printf(" %.20s%c%*s", bit_label, down, (int) (20 - strlen(bit_label)), "");
- else
- printf(" %04x%c ", j * 8 + k, down);
- } else {
- printf(" %04x%c", j * 8 + k, down);
- }
- if(i == EV_ABS) {
- struct input_absinfo abs;
- if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
- printf(" : value %d, min %d, max %d, fuzz %d, flat %d, resolution %d",
- abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat,
- abs.resolution);
- }
- }
- count++;
- }
- }
- if(count)
- printf("\n");
- }
- free(bits);
- return 0;
- }
- static void print_event(int type, int code, int value, int print_flags)
- {
- const char *type_label, *code_label, *value_label;
- if (print_flags & PRINT_LABELS) {
- type_label = get_label(ev_labels, type);
- code_label = NULL;
- value_label = NULL;
- switch(type) {
- case EV_SYN:
- code_label = get_label(syn_labels, code);
- break;
- case EV_KEY:
- code_label = get_label(key_labels, code);
- value_label = get_label(key_value_labels, value);
- break;
- case EV_REL:
- code_label = get_label(rel_labels, code);
- break;
- case EV_ABS:
- code_label = get_label(abs_labels, code);
- switch(code) {
- case ABS_MT_TOOL_TYPE:
- value_label = get_label(mt_tool_labels, value);
- }
- break;
- case EV_MSC:
- code_label = get_label(msc_labels, code);
- break;
- case EV_LED:
- code_label = get_label(led_labels, code);
- break;
- case EV_SND:
- code_label = get_label(snd_labels, code);
- break;
- case EV_SW:
- code_label = get_label(sw_labels, code);
- break;
- case EV_REP:
- code_label = get_label(rep_labels, code);
- break;
- case EV_FF:
- code_label = get_label(ff_labels, code);
- break;
- case EV_FF_STATUS:
- code_label = get_label(ff_status_labels, code);
- break;
- }
- if (type_label)
- printf("%-12.12s", type_label);
- else
- printf("%04x ", type);
- if (code_label)
- printf(" %-20.20s", code_label);
- else
- printf(" %04x ", code);
- if (value_label)
- printf(" %-20.20s", value_label);
- else
- printf(" %08x ", value);
- } else {
- printf("%04x %04x %08x", type, code, value);
- }
- }
- static void print_hid_descriptor(int bus, int vendor, int product)
- {
- const char *dirname = "/sys/kernel/debug/hid";
- char prefix[16];
- DIR *dir;
- struct dirent *de;
- char filename[PATH_MAX];
- FILE *file;
- char line[2048];
- snprintf(prefix, sizeof(prefix), "%04X:%04X:%04X.", bus, vendor, product);
- dir = opendir(dirname);
- if(dir == NULL)
- return;
- while((de = readdir(dir))) {
- if (strstr(de->d_name, prefix) == de->d_name) {
- snprintf(filename, sizeof(filename), "%s/%s/rdesc", dirname, de->d_name);
- file = fopen(filename, "r");
- if (file) {
- printf(" HID descriptor: %s\n\n", de->d_name);
- while (fgets(line, sizeof(line), file)) {
- fputs(" ", stdout);
- fputs(line, stdout);
- }
- fclose(file);
- puts("");
- }
- }
- }
- closedir(dir);
- }
- static int open_device(const char *device, int print_flags)
- {
- int version;
- int fd;
- int clkid = CLOCK_MONOTONIC;
- struct pollfd *new_ufds;
- char **new_device_names;
- char name[80];
- char location[80];
- char idstr[80];
- struct input_id id;
- fd = open(device, O_RDONLY | O_CLOEXEC);
- if(fd < 0) {
- if(print_flags & PRINT_DEVICE_ERRORS)
- fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
- return -1;
- }
-
- if(ioctl(fd, EVIOCGVERSION, &version)) {
- if(print_flags & PRINT_DEVICE_ERRORS)
- fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
- return -1;
- }
- if(ioctl(fd, EVIOCGID, &id)) {
- if(print_flags & PRINT_DEVICE_ERRORS)
- fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
- return -1;
- }
- name[sizeof(name) - 1] = '\0';
- location[sizeof(location) - 1] = '\0';
- idstr[sizeof(idstr) - 1] = '\0';
- if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
- //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
- name[0] = '\0';
- }
- if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
- //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
- location[0] = '\0';
- }
- if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
- //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
- idstr[0] = '\0';
- }
- if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
- fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno));
- // a non-fatal error
- }
- new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
- if(new_ufds == NULL) {
- fprintf(stderr, "out of memory\n");
- return -1;
- }
- ufds = new_ufds;
- new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
- if(new_device_names == NULL) {
- fprintf(stderr, "out of memory\n");
- return -1;
- }
- device_names = new_device_names;
- if(print_flags & PRINT_DEVICE)
- printf("add device %d: %s\n", nfds, device);
- if(print_flags & PRINT_DEVICE_INFO)
- printf(" bus: %04x\n"
- " vendor %04x\n"
- " product %04x\n"
- " version %04x\n",
- id.bustype, id.vendor, id.product, id.version);
- if(print_flags & PRINT_DEVICE_NAME)
- printf(" name: \"%s\"\n", name);
- if(print_flags & PRINT_DEVICE_INFO)
- printf(" location: \"%s\"\n"
- " id: \"%s\"\n", location, idstr);
- if(print_flags & PRINT_VERSION)
- printf(" version: %d.%d.%d\n",
- version >> 16, (version >> 8) & 0xff, version & 0xff);
- if(print_flags & PRINT_POSSIBLE_EVENTS) {
- print_possible_events(fd, print_flags);
- }
- if(print_flags & PRINT_INPUT_PROPS) {
- print_input_props(fd);
- }
- if(print_flags & PRINT_HID_DESCRIPTOR) {
- print_hid_descriptor(id.bustype, id.vendor, id.product);
- }
- ufds[nfds].fd = fd;
- ufds[nfds].events = POLLIN;
- device_names[nfds] = strdup(device);
- nfds++;
- return 0;
- }
- int close_device(const char *device, int print_flags)
- {
- int i;
- for(i = 1; i < nfds; i++) {
- if(strcmp(device_names[i], device) == 0) {
- int count = nfds - i - 1;
- if(print_flags & PRINT_DEVICE)
- printf("remove device %d: %s\n", i, device);
- free(device_names[i]);
- memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
- memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
- nfds--;
- return 0;
- }
- }
- if(print_flags & PRINT_DEVICE_ERRORS)
- fprintf(stderr, "remote device: %s not found\n", device);
- return -1;
- }
- static int read_notify(const char *dirname, int nfd, int print_flags)
- {
- int res;
- char devname[PATH_MAX];
- char *filename;
- char event_buf[512];
- int event_size;
- int event_pos = 0;
- struct inotify_event *event;
- res = read(nfd, event_buf, sizeof(event_buf));
- if(res < (int)sizeof(*event)) {
- if(errno == EINTR)
- return 0;
- fprintf(stderr, "could not get event, %s\n", strerror(errno));
- return 1;
- }
- //printf("got %d bytes of event information\n", res);
- strcpy(devname, dirname);
- filename = devname + strlen(devname);
- *filename++ = '/';
- while(res >= (int)sizeof(*event)) {
- event = (struct inotify_event *)(event_buf + event_pos);
- //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
- if(event->len) {
- strcpy(filename, event->name);
- if(event->mask & IN_CREATE) {
- open_device(devname, print_flags);
- }
- else {
- close_device(devname, print_flags);
- }
- }
- event_size = sizeof(*event) + event->len;
- res -= event_size;
- event_pos += event_size;
- }
- return 0;
- }
- static int scan_dir(const char *dirname, int print_flags)
- {
- char devname[PATH_MAX];
- char *filename;
- DIR *dir;
- struct dirent *de;
- dir = opendir(dirname);
- if(dir == NULL)
- return -1;
- strcpy(devname, dirname);
- filename = devname + strlen(devname);
- *filename++ = '/';
- while((de = readdir(dir))) {
- if(de->d_name[0] == '.' &&
- (de->d_name[1] == '\0' ||
- (de->d_name[1] == '.' && de->d_name[2] == '\0')))
- continue;
- strcpy(filename, de->d_name);
- open_device(devname, print_flags);
- }
- closedir(dir);
- return 0;
- }
- static void usage(char *name)
- {
- fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
- fprintf(stderr, " -t: show time stamps\n");
- fprintf(stderr, " -n: don't print newlines\n");
- fprintf(stderr, " -s: print switch states for given bits\n");
- fprintf(stderr, " -S: print all switch states\n");
- fprintf(stderr, " -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)\n");
- fprintf(stderr, " -d: show HID descriptor, if available\n");
- fprintf(stderr, " -p: show possible events (errs, dev, name, pos. events)\n");
- fprintf(stderr, " -i: show all device info and possible events\n");
- fprintf(stderr, " -l: label event types and names in plain text\n");
- fprintf(stderr, " -q: quiet (clear verbosity mask)\n");
- fprintf(stderr, " -c: print given number of events then exit\n");
- fprintf(stderr, " -r: print rate events are received\n");
- }
- int getevent_main(int argc, char *argv[])
- {
- int c;
- int i;
- int res;
- int get_time = 0;
- int print_device = 0;
- char *newline = "\n";
- uint16_t get_switch = 0;
- struct input_event event;
- int print_flags = 0;
- int print_flags_set = 0;
- int dont_block = -1;
- int event_count = 0;
- int sync_rate = 0;
- int64_t last_sync_time = 0;
- const char *device = NULL;
- const char *device_path = "/dev/input";
- /* disable buffering on stdout */
- setbuf(stdout, NULL);
- opterr = 0;
- do {
- c = getopt(argc, argv, "tns:Sv::dpilqc:rh");
- if (c == EOF)
- break;
- switch (c) {
- case 't':
- get_time = 1;
- break;
- case 'n':
- newline = "";
- break;
- case 's':
- get_switch = strtoul(optarg, NULL, 0);
- if(dont_block == -1)
- dont_block = 1;
- break;
- case 'S':
- get_switch = ~0;
- if(dont_block == -1)
- dont_block = 1;
- break;
- case 'v':
- if(optarg)
- print_flags |= strtoul(optarg, NULL, 0);
- else
- print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
- print_flags_set = 1;
- break;
- case 'd':
- print_flags |= PRINT_HID_DESCRIPTOR;
- break;
- case 'p':
- print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE
- | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS | PRINT_INPUT_PROPS;
- print_flags_set = 1;
- if(dont_block == -1)
- dont_block = 1;
- break;
- case 'i':
- print_flags |= PRINT_ALL_INFO;
- print_flags_set = 1;
- if(dont_block == -1)
- dont_block = 1;
- break;
- case 'l':
- print_flags |= PRINT_LABELS;
- break;
- case 'q':
- print_flags_set = 1;
- break;
- case 'c':
- event_count = atoi(optarg);
- dont_block = 0;
- break;
- case 'r':
- sync_rate = 1;
- break;
- case '?':
- fprintf(stderr, "%s: invalid option -%c\n",
- argv[0], optopt);
- case 'h':
- usage(argv[0]);
- exit(1);
- }
- } while (1);
- if(dont_block == -1)
- dont_block = 0;
- if (optind + 1 == argc) {
- device = argv[optind];
- optind++;
- }
- if (optind != argc) {
- usage(argv[0]);
- exit(1);
- }
- nfds = 1;
- ufds = calloc(1, sizeof(ufds[0]));
- ufds[0].fd = inotify_init();
- ufds[0].events = POLLIN;
- if(device) {
- if(!print_flags_set)
- print_flags |= PRINT_DEVICE_ERRORS;
- res = open_device(device, print_flags);
- if(res < 0) {
- return 1;
- }
- } else {
- if(!print_flags_set)
- print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
- print_device = 1;
- res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
- if(res < 0) {
- fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
- return 1;
- }
- res = scan_dir(device_path, print_flags);
- if(res < 0) {
- fprintf(stderr, "scan dir failed for %s\n", device_path);
- return 1;
- }
- }
- if(get_switch) {
- for(i = 1; i < nfds; i++) {
- uint16_t sw;
- res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
- if(res < 0) {
- fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
- return 1;
- }
- sw &= get_switch;
- printf("%04x%s", sw, newline);
- }
- }
- if(dont_block)
- return 0;
- while(1) {
- //int pollres =
- poll(ufds, nfds, -1);
- //printf("poll %d, returned %d\n", nfds, pollres);
- if(ufds[0].revents & POLLIN) {
- read_notify(device_path, ufds[0].fd, print_flags);
- }
- for(i = 1; i < nfds; i++) {
- if(ufds[i].revents) {
- if(ufds[i].revents & POLLIN) {
- res = read(ufds[i].fd, &event, sizeof(event));
- if(res < (int)sizeof(event)) {
- fprintf(stderr, "could not get event\n");
- return 1;
- }
- if(get_time) {
- printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);
- }
- if(print_device)
- printf("%s: ", device_names[i]);
- print_event(event.type, event.code, event.value, print_flags);
- if(sync_rate && event.type == 0 && event.code == 0) {
- int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
- if(last_sync_time)
- printf(" rate %lld", 1000000LL / (now - last_sync_time));
- last_sync_time = now;
- }
- printf("%s", newline);
- if(event_count && --event_count == 0)
- return 0;
- }
- }
- }
- }
- return 0;
- }
|