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