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