summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile11
-rw-r--r--evcat.c163
-rw-r--r--maps.h27
4 files changed, 203 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5473711
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+evcat
+*.gen.h
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..330fe53
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+.POSIX:
+
+evcat: evcat.c keymap.h
+ cc -o evcat evcat.c
+
+keymap.h: /usr/include/linux/input-event-codes.h
+ grep -e "^#define KEY_.*" /usr/include/linux/input-event-codes.h | \
+ sed -e 's/^#define \(KEY_[^ \t]\+\)[ \t]\+\([^ \t\n]\+\).*$$/ { \1, "\1" },/g' > keymap.gen.h
+ grep -e "^#define BTN_.*" /usr/include/linux/input-event-codes.h | \
+ sed -e 's/^#define \(BTN_[^ \t]\+\)[ \t]\+\([^ \t\n]\+\).*$$/ { \1, "\1" },/g' >> keymap.gen.h
+
diff --git a/evcat.c b/evcat.c
new file mode 100644
index 0000000..0903913
--- /dev/null
+++ b/evcat.c
@@ -0,0 +1,163 @@
+#define _POSIX_C_SOURCE 200809L
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <linux/input.h>
+#include <linux/input-event-codes.h>
+#include <sys/signalfd.h>
+#include <sys/epoll.h>
+
+#include "maps.h"
+
+static int fd_ep = -1;
+static int fd_sig = -1;
+static int fd_in = STDIN_FILENO;
+
+struct input_event ev;
+
+const char *resolve_id_impl(const struct kv map[], size_t n, unsigned int key) {
+ static char buf[10];
+
+ for (size_t i = 0; i < n; i ++) {
+ const struct kv k = map[i];
+ if (k.key == key) {
+ return k.name;
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "UNK_0x%x", key);
+ return buf;
+}
+
+void parse_args(int argc, char **argv) {
+ char opt;
+ while ((opt = getopt(argc, argv, "vh")) != -1) {
+ switch (opt) {
+ case 'v':
+ printf("evact 1.0\n");
+ exit(0);
+ default:
+ printf("Usage: %s [-vh] <path>\n"
+ "\n"
+ "-v\tShow version\n"
+ "-v\tShow help\n"
+ "\n"
+ "path\tRead the specific input file, should be /dev/input/eventX.\n"
+ "\tDefaults to stdin.\n", argv[0]);
+ exit(64);
+ }
+ }
+
+ if (optind < argc) {
+ int fd_in = open(argv[optind], O_RDONLY);
+ if (fd_in == -1) {
+ err(errno, "open %s", argv[optind]);
+ }
+ }
+}
+
+static void print_key(void) {
+ printf("%s\t%s\n",
+ resolve_key(ev.code),
+ resolve_key_vals(ev.value));
+}
+
+static void print_unknown(void) {
+ printf("UNK\t0x%x\n",
+ ev.type);
+}
+
+static void handle_in(void) {
+ ssize_t n = read(fd_in, &ev, sizeof(ev));
+ if (n == -1) {
+ err(errno, "read");
+ }
+ if (n == 0) {
+ exit(0);
+ }
+ if (n < sizeof(ev)) {
+ errx(1, "Expected %d bytes, but got %d bytes.", sizeof(ev), n);
+ }
+ if (ev.type == EV_SYN || ev.type == EV_MSC) {
+ return;
+ }
+ switch (ev.type) {
+ case EV_KEY: print_key(); break;
+ default: print_unknown();
+ }
+}
+
+static void handle_sig(void) {
+ struct signalfd_siginfo siginfo;
+ ssize_t n = read(fd_sig, &siginfo, sizeof(struct signalfd_siginfo));
+ if (n == -1) {
+ err(errno, "read");
+ }
+ if (n == 0) {
+ exit(0);
+ }
+ if (n < sizeof(struct signalfd_siginfo)) {
+ errx(1, "Expected %d bytes, but got %d bytes.", sizeof(struct signalfd_siginfo), n);
+ }
+ exit(0);
+}
+
+static void cleanup(void) {
+ close(fd_sig);
+ close(fd_in);
+ close(fd_ep);
+}
+
+int main(int argc, char **argv) {
+ if ((fd_ep = epoll_create1(0)) == -1) {
+ err(errno, "epoll_create1");
+ }
+
+ atexit(cleanup);
+
+ parse_args(argc, argv);
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGINT);
+ if ((fd_sig = signalfd(-1, &mask, 0)) == -1) {
+ err(errno, "signalfd");
+ }
+ if ((errno = sigprocmask(SIG_SETMASK, &mask, NULL))) {
+ err(errno, "sigprocmask");
+ }
+
+ struct epoll_event evs[8];
+ if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_sig, &((struct epoll_event) { .events = EPOLLIN, .data.fd = fd_sig }))) {
+ err(errno, "epoll_ctl(fd_sig)");
+ }
+ if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_in, &((struct epoll_event) { .events = EPOLLIN, .data.fd = fd_in }))) {
+ err(errno, "epoll_ctl(fd_in)");
+ }
+
+ while (1) {
+ int c = epoll_wait(fd_ep, evs, sizeof(evs) / sizeof(struct epoll_event), -1);
+ if (c == -1) {
+ err(errno, "epoll_wait");
+ }
+ for (int i = 0; i < c; i ++) {
+ const struct epoll_event *e = &evs[i];
+ if (e->data.fd == fd_in) {
+ handle_in();
+ } else if (e->data.fd == fd_sig) {
+ handle_sig();
+ } else {
+ errx(1, "Unknown fd: %d\n", e->data.fd);
+ }
+ }
+ }
+}
+
diff --git a/maps.h b/maps.h
new file mode 100644
index 0000000..ca0afbb
--- /dev/null
+++ b/maps.h
@@ -0,0 +1,27 @@
+#ifndef _MAPS_H
+#define _MAPS_H
+
+struct kv {
+ const unsigned int key;
+ const char *name;
+};
+
+struct kv keys[] = {
+#include "keymap.gen.h"
+};
+
+struct kv key_vals[] = {
+ { 0, "Released" },
+ { 1, "Pressed" },
+ { 2, "Repeated" },
+};
+
+const char *resolve_id_impl(const struct kv map[], size_t n, unsigned int key);
+
+#define resolve_id(map, key) resolve_id_impl(map, sizeof(map) / sizeof(struct kv), key)
+
+#define resolve_key(key) resolve_id(keys, key)
+
+#define resolve_key_vals(key) resolve_id(key_vals, key)
+
+#endif // _MAPS_H