// inputtest -- read raw events from /dev/input/eventN. // // The point of the raw devices is everything the console cannot say: which // key was released, whether one is still held, and where the mouse went. None // of that shows up in a character stream, so none of it can be tested by // typing into a shell. // // inputtest read the keyboard until Esc is released // inputtest mouse read the mouse until interrupted // inputtest -n N stop after N events (used by the boot check) // // Prints one line per event: type, code and value, decoded where there is a // name for it. #include "core/types.h" #include "uapi/user.h" #include "uapi/fcntl.h" #include "dev/input.h" static void puts_(const char *s) { int n = 0; while (s[n]) n++; write(1, (void*)s, n); } static void putn_(int v) { char buf[12]; int i = 0, neg = 0; if (v < 0) { neg = 1; v = -v; } if (v == 0) buf[i++] = '0'; while (v) { buf[i++] = '0' + (v % 10); v /= 10; } if (neg) buf[i++] = '-'; while (i--) write(1, &buf[i], 1); } static const char * typename_(int t) { switch (t) { case EV_SYN: return "SYN"; case EV_KEY: return "KEY"; case EV_REL: return "REL"; default: return "?"; } } static int streq(const char *a, const char *b) { while (*a && *a == *b) { a++; b++; } return *a == *b; } int main(int argc, char **argv) { const char *path = "/dev/input/event0"; int limit = 0, count = 0, i; int fd; struct input_event ev; for (i = 1; i < argc; i++) { if (streq(argv[i], "mouse")) path = "/dev/input/event1"; else if (streq(argv[i], "-n") && i + 1 < argc) { const char *p = argv[++i]; limit = 0; while (*p >= '0' && *p <= '9') limit = limit * 10 + (*p++ - '0'); } } fd = open((char*)path, O_RDONLY); if (fd < 0) { puts_("inputtest: cannot open "); puts_(path); puts_("\n"); exit(); } puts_("inputtest: reading "); puts_(path); puts_("\n"); for (;;) { int n = read(fd, &ev, sizeof(ev)); // A short read would mean the device handed back part of a struct, // which would desynchronise every event after it. Saying so is more // use than silently carrying on with garbage. if (n == 0) { puts_("inputtest: end of stream\n"); break; } if (n < 0) { puts_("inputtest: read error\n"); break; } if (n != sizeof(ev)) { puts_("inputtest: SHORT READ -- events are not whole\n"); break; } puts_(" "); puts_(typename_(ev.type)); puts_(" code "); putn_(ev.code); puts_(" value "); putn_(ev.value); if (ev.type == EV_KEY) puts_(ev.value ? " (press)" : " (release)"); puts_("\n"); // Esc released ends the keyboard run, so a person can stop it without // a signal. The boot check uses -n instead. if (ev.type == EV_KEY && ev.code == KEY_ESC && ev.value == 0) break; if (limit && ++count >= limit) { puts_("inputtest: event limit reached\n"); break; } } close(fd); puts_("inputtest: done\n"); exit(); }