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