diff options
author | yuuta <yuuta@yuuta.moe> | 2023-11-27 17:42:32 -0800 |
---|---|---|
committer | yuuta <yuuta@yuuta.moe> | 2023-11-27 17:42:32 -0800 |
commit | e79d53015364c1850810c7db7728f08d8208ac2a (patch) | |
tree | 506d0e679bc6a010d7473f1cf2dc20271b9e4c92 | |
download | evcat-master.tar evcat-master.tar.gz evcat-master.tar.bz2 evcat-master.zip |
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | evcat.c | 163 | ||||
-rw-r--r-- | maps.h | 27 |
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 + @@ -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); + } + } + } +} + @@ -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 |