getevent.c revision dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0
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> // this does not compile 12#include <errno.h> 13 14static struct pollfd *ufds; 15static char **device_names; 16static int nfds; 17 18enum { 19 PRINT_DEVICE_ERRORS = 1U << 0, 20 PRINT_DEVICE = 1U << 1, 21 PRINT_DEVICE_NAME = 1U << 2, 22 PRINT_DEVICE_INFO = 1U << 3, 23 PRINT_VERSION = 1U << 4, 24 PRINT_POSSIBLE_EVENTS = 1U << 5, 25}; 26 27static int print_possible_events(int fd) 28{ 29 uint8_t *bits = NULL; 30 ssize_t bits_size = 0; 31 int i, j, k; 32 int res, res2; 33 34 printf(" events:\n"); 35 for(i = 0; i <= EV_MAX; i++) { 36 int count = 0; 37 while(1) { 38 res = ioctl(fd, EVIOCGBIT(i, bits_size), bits); 39 if(res < bits_size) 40 break; 41 bits_size = res + 16; 42 bits = realloc(bits, bits_size * 2); 43 if(bits == NULL) { 44 fprintf(stderr, "failed to allocate buffer of size %d\n", bits_size); 45 return 1; 46 } 47 } 48 switch(i) { 49 case EV_KEY: 50 res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size); 51 break; 52 case EV_LED: 53 res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size); 54 break; 55 case EV_SND: 56 res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size); 57 break; 58 case EV_SW: 59 res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size); 60 break; 61 default: 62 res2 = 0; 63 } 64 for(j = 0; j < res; j++) { 65 for(k = 0; k < 8; k++) 66 if(bits[j] & 1 << k) { 67 char down; 68 if(j < res2 && (bits[j + bits_size] & 1 << k)) 69 down = '*'; 70 else 71 down = ' '; 72 if(count == 0) 73 printf(" type %04x:", i); 74 else if((count & 0x7) == 0 || i == EV_ABS) 75 printf("\n "); 76 printf(" %04x%c", j * 8 + k, down); 77 if(i == EV_ABS) { 78 struct input_absinfo abs; 79 if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) { 80 printf(" value %d, min %d, max %d, fuzz %d flat %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat); 81 } 82 } 83 count++; 84 } 85 } 86 if(count) 87 printf("\n"); 88 } 89 free(bits); 90 return 0; 91} 92 93static int open_device(const char *device, int print_flags) 94{ 95 int version; 96 int fd; 97 struct pollfd *new_ufds; 98 char **new_device_names; 99 char name[80]; 100 char location[80]; 101 char idstr[80]; 102 struct input_id id; 103 104 fd = open(device, O_RDWR); 105 if(fd < 0) { 106 if(print_flags & PRINT_DEVICE_ERRORS) 107 fprintf(stderr, "could not open %s, %s\n", device, strerror(errno)); 108 return -1; 109 } 110 111 if(ioctl(fd, EVIOCGVERSION, &version)) { 112 if(print_flags & PRINT_DEVICE_ERRORS) 113 fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno)); 114 return -1; 115 } 116 if(ioctl(fd, EVIOCGID, &id)) { 117 if(print_flags & PRINT_DEVICE_ERRORS) 118 fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno)); 119 return -1; 120 } 121 name[sizeof(name) - 1] = '\0'; 122 location[sizeof(location) - 1] = '\0'; 123 idstr[sizeof(idstr) - 1] = '\0'; 124 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { 125 //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno)); 126 name[0] = '\0'; 127 } 128 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { 129 //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno)); 130 location[0] = '\0'; 131 } 132 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { 133 //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno)); 134 idstr[0] = '\0'; 135 } 136 137 new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); 138 if(new_ufds == NULL) { 139 fprintf(stderr, "out of memory\n"); 140 return -1; 141 } 142 ufds = new_ufds; 143 new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); 144 if(new_device_names == NULL) { 145 fprintf(stderr, "out of memory\n"); 146 return -1; 147 } 148 device_names = new_device_names; 149 150 if(print_flags & PRINT_DEVICE) 151 printf("add device %d: %s\n", nfds, device); 152 if(print_flags & PRINT_DEVICE_INFO) 153 printf(" bus: %04x\n" 154 " vendor %04x\n" 155 " product %04x\n" 156 " version %04x\n", 157 id.bustype, id.vendor, id.product, id.version); 158 if(print_flags & PRINT_DEVICE_NAME) 159 printf(" name: \"%s\"\n", name); 160 if(print_flags & PRINT_DEVICE_INFO) 161 printf(" location: \"%s\"\n" 162 " id: \"%s\"\n", location, idstr); 163 if(print_flags & PRINT_VERSION) 164 printf(" version: %d.%d.%d\n", 165 version >> 16, (version >> 8) & 0xff, version & 0xff); 166 167 if(print_flags & PRINT_POSSIBLE_EVENTS) { 168 print_possible_events(fd); 169 } 170 171 ufds[nfds].fd = fd; 172 ufds[nfds].events = POLLIN; 173 device_names[nfds] = strdup(device); 174 nfds++; 175 176 return 0; 177} 178 179int close_device(const char *device, int print_flags) 180{ 181 int i; 182 for(i = 1; i < nfds; i++) { 183 if(strcmp(device_names[i], device) == 0) { 184 int count = nfds - i - 1; 185 if(print_flags & PRINT_DEVICE) 186 printf("remove device %d: %s\n", i, device); 187 free(device_names[i]); 188 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count); 189 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count); 190 nfds--; 191 return 0; 192 } 193 } 194 if(print_flags & PRINT_DEVICE_ERRORS) 195 fprintf(stderr, "remote device: %s not found\n", device); 196 return -1; 197} 198 199static int read_notify(const char *dirname, int nfd, int print_flags) 200{ 201 int res; 202 char devname[PATH_MAX]; 203 char *filename; 204 char event_buf[512]; 205 int event_size; 206 int event_pos = 0; 207 struct inotify_event *event; 208 209 res = read(nfd, event_buf, sizeof(event_buf)); 210 if(res < (int)sizeof(*event)) { 211 if(errno == EINTR) 212 return 0; 213 fprintf(stderr, "could not get event, %s\n", strerror(errno)); 214 return 1; 215 } 216 //printf("got %d bytes of event information\n", res); 217 218 strcpy(devname, dirname); 219 filename = devname + strlen(devname); 220 *filename++ = '/'; 221 222 while(res >= (int)sizeof(*event)) { 223 event = (struct inotify_event *)(event_buf + event_pos); 224 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); 225 if(event->len) { 226 strcpy(filename, event->name); 227 if(event->mask & IN_CREATE) { 228 open_device(devname, print_flags); 229 } 230 else { 231 close_device(devname, print_flags); 232 } 233 } 234 event_size = sizeof(*event) + event->len; 235 res -= event_size; 236 event_pos += event_size; 237 } 238 return 0; 239} 240 241static int scan_dir(const char *dirname, int print_flags) 242{ 243 char devname[PATH_MAX]; 244 char *filename; 245 DIR *dir; 246 struct dirent *de; 247 dir = opendir(dirname); 248 if(dir == NULL) 249 return -1; 250 strcpy(devname, dirname); 251 filename = devname + strlen(devname); 252 *filename++ = '/'; 253 while((de = readdir(dir))) { 254 if(de->d_name[0] == '.' && 255 (de->d_name[1] == '\0' || 256 (de->d_name[1] == '.' && de->d_name[2] == '\0'))) 257 continue; 258 strcpy(filename, de->d_name); 259 open_device(devname, print_flags); 260 } 261 closedir(dir); 262 return 0; 263} 264 265static void usage(int argc, char *argv[]) 266{ 267 fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-q] [-c count] [-r] [device]\n", argv[0]); 268} 269 270int getevent_main(int argc, char *argv[]) 271{ 272 int c; 273 int i; 274 int res; 275 int pollres; 276 int get_time = 0; 277 int print_device = 0; 278 char *newline = "\n"; 279 uint16_t get_switch = 0; 280 struct input_event event; 281 int version; 282 int print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME; 283 int print_flags_set = 0; 284 int dont_block = -1; 285 int event_count = 0; 286 int sync_rate = 0; 287 int64_t last_sync_time = 0; 288 const char *device = NULL; 289 const char *device_path = "/dev/input"; 290 291 opterr = 0; 292 do { 293 c = getopt(argc, argv, "tns:Sv::qc:rh"); 294 if (c == EOF) 295 break; 296 switch (c) { 297 case 't': 298 get_time = 1; 299 break; 300 case 'n': 301 newline = ""; 302 break; 303 case 's': 304 get_switch = strtoul(optarg, NULL, 0); 305 if(dont_block == -1) 306 dont_block = 1; 307 break; 308 case 'S': 309 get_switch = ~0; 310 if(dont_block == -1) 311 dont_block = 1; 312 break; 313 case 'v': 314 if(optarg) 315 print_flags = strtoul(optarg, NULL, 0); 316 else 317 print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION; 318 print_flags_set = 1; 319 break; 320 case 'q': 321 print_flags = 0; 322 print_flags_set = 1; 323 break; 324 case 'c': 325 event_count = atoi(optarg); 326 dont_block = 0; 327 break; 328 case 'r': 329 sync_rate = 1; 330 break; 331 case '?': 332 fprintf(stderr, "%s: invalid option -%c\n", 333 argv[0], optopt); 334 case 'h': 335 usage(argc, argv); 336 exit(1); 337 } 338 } while (1); 339 if(dont_block == -1) 340 dont_block = 0; 341 342 if (optind + 1 == argc) { 343 device = argv[optind]; 344 optind++; 345 } 346 if (optind != argc) { 347 usage(argc, argv); 348 exit(1); 349 } 350 nfds = 1; 351 ufds = calloc(1, sizeof(ufds[0])); 352 ufds[0].fd = inotify_init(); 353 ufds[0].events = POLLIN; 354 if(device) { 355 if(!print_flags_set) 356 print_flags = PRINT_DEVICE_ERRORS; 357 res = open_device(device, print_flags); 358 if(res < 0) { 359 return 1; 360 } 361 } 362 else { 363 print_device = 1; 364 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE); 365 if(res < 0) { 366 fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno)); 367 return 1; 368 } 369 res = scan_dir(device_path, print_flags); 370 if(res < 0) { 371 fprintf(stderr, "scan dir failed for %s\n", device_path); 372 return 1; 373 } 374 } 375 376 if(get_switch) { 377 for(i = 1; i < nfds; i++) { 378 uint16_t sw; 379 res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw); 380 if(res < 0) { 381 fprintf(stderr, "could not get switch state, %s\n", strerror(errno)); 382 return 1; 383 } 384 sw &= get_switch; 385 printf("%04x%s", sw, newline); 386 } 387 } 388 389 if(dont_block) 390 return 0; 391 392 while(1) { 393 pollres = poll(ufds, nfds, -1); 394 //printf("poll %d, returned %d\n", nfds, pollres); 395 if(ufds[0].revents & POLLIN) { 396 read_notify(device_path, ufds[0].fd, print_flags); 397 } 398 for(i = 1; i < nfds; i++) { 399 if(ufds[i].revents) { 400 if(ufds[i].revents & POLLIN) { 401 res = read(ufds[i].fd, &event, sizeof(event)); 402 if(res < (int)sizeof(event)) { 403 fprintf(stderr, "could not get event\n"); 404 return 1; 405 } 406 if(get_time) { 407 printf("%ld-%ld: ", event.time.tv_sec, event.time.tv_usec); 408 } 409 if(print_device) 410 printf("%s: ", device_names[i]); 411 printf("%04x %04x %08x", event.type, event.code, event.value); 412 if(sync_rate && event.type == 0 && event.code == 0) { 413 int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec; 414 if(last_sync_time) 415 printf(" rate %lld", 1000000LL / (now - last_sync_time)); 416 last_sync_time = now; 417 } 418 printf("%s", newline); 419 if(event_count && --event_count == 0) 420 return 0; 421 } 422 } 423 } 424 } 425 426 return 0; 427} 428