From 704f23576a00e4bec41006ac97e955d7a82b8012 Mon Sep 17 00:00:00 2001 From: Caleb Connolly <caleb.connolly@linaro.org> Date: Fri, 12 Apr 2024 22:39:22 +0100 Subject: [PATCH] iskey: new utility iskey tells you if any of a given list of keys are pressed on any input device in the system. e.g. $ iskey KEY_VOLUMEDOWN Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org> --- README.md | 3 ++ iskey/README.md | 7 +++ iskey/iskey.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++ iskey/meson.build | 7 +++ 4 files changed, 145 insertions(+) create mode 100644 iskey/README.md create mode 100644 iskey/iskey.c create mode 100644 iskey/meson.build diff --git a/README.md b/README.md index ade831e..92cad17 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ BuffyBox is a suite of graphical applications for the terminal. **[squeek2lvgl]** – Converter for transforming [Squeekboard] layouts into [LVGL]-compatible C code +**[iskey]** - A utility for checking for key presses in bash scripts. + **[shared]** – Internal code that is shared by some or all applications in the suite but not meant to be used externally ## Contributing @@ -44,6 +46,7 @@ For the license of bundled images and fonts, see [shared/cursor] and [shared/fon [LVGL]: https://github.com/lvgl/lvgl [shared]: ./shared [squeek2lvgl]: ./squeek2lvgl +[iskey]: ./iskey [Squeekboard]: https://gitlab.gnome.org/World/Phosh/squeekboard [shared/cursor]: ./shared/cursor [shared/fonts]: ./shared/fonts diff --git a/iskey/README.md b/iskey/README.md new file mode 100644 index 0000000..ff7bf6f --- /dev/null +++ b/iskey/README.md @@ -0,0 +1,7 @@ +# iskey + +A tiny utility for determining if a key is pressed. + +iskey is intended to be used in the context of a constrained environment like +the initramfs, it allows for easily scripting things like "is the user holding +volume down" which are generally non-trivial to check for in a shell script. diff --git a/iskey/iskey.c b/iskey/iskey.c new file mode 100644 index 0000000..e92f52d --- /dev/null +++ b/iskey/iskey.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include <dirent.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <libevdev/libevdev.h> + +#define MAX_KEYS 32 + +static int codes[MAX_KEYS] = { 0 }; +static unsigned int types[MAX_KEYS] = { 0 }; +static int debug = 0; +static int print_key = 0; + +#define log(fmt, ...) \ + do { \ + if (debug) \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } while (0) + +#define INPUT_DIR "/dev/input/" + +int usage(const char *name) +{ + fprintf(stderr, "Usage: %s [-d] [-s] key1...\n", name); + fprintf(stderr, " -d: debug mode\n"); + fprintf(stderr, " -s: print the name of the key\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " Check if any input device has the specified keys pressed\n" + " and exit with code 0 if so, otherwise exit with code 1\n"); + return 1; +} + +/* Check if any of the input devices have a non-zero value for any of the keys. + * if so then return 0, otherwise return -1. + */ +int check_for_keys(struct libevdev *dev) +{ + int i; + + for (i = 0; i < MAX_KEYS; i++) { + if (codes[i] == 0) + break; + if (!libevdev_has_event_code(dev, types[i], codes[i])) + continue; + if (libevdev_get_event_value(dev, types[i], codes[i])) { + if (print_key) + printf("%s\n", libevdev_event_code_get_name(types[i], codes[i])); + return 0; + } + } + + return -1; +} + +int main(int argc, char *argv[]) +{ + struct libevdev *dev; + struct dirent *dir; + DIR *d; + int i = 0, opt, fd; + char path[64] = { 0 }; + + /* getopt */ + while ((opt = getopt(argc, argv, "d")) != -1) { + switch (opt) { + case 'd': + debug = 1; + break; + case 's': + print_key = 1; + break; + default: + return usage(argv[0]); + } + } + + for (; optind < argc && i < MAX_KEYS; optind++) { + codes[i] = libevdev_event_code_from_code_name(argv[optind]); + if (codes[i] == -1) { + fprintf(stderr, "Unknown key %s\n", argv[optind]); + return 1; + } + types[i++] = libevdev_event_type_from_code_name(argv[optind]); + log("Checking for %s %s (%d)\n", libevdev_event_type_get_name(types[i-1]), argv[optind], codes[i-1]); + } + + d = opendir(INPUT_DIR); + if (!d) { + perror("couldn't open /dev/input/"); + return 1; + } + + /* Walk through the entries in /dev/input */ + while ((dir = readdir(d)) != NULL) { + memset(path, 0, sizeof(path)); + i = snprintf(path, sizeof(path), "%s%s", INPUT_DIR, dir->d_name); + if (i < 0 || i >= sizeof(path)) { + printf("Path '%s' too long\n", dir->d_name); + return 1; + } + + if (dir->d_type != DT_CHR || strncmp("event", dir->d_name, 5) != 0) + continue; + + fd = open(path, O_RDONLY|O_NONBLOCK); + if (fd < 0) { + log("couldn't open device %s\n", dir->d_name); + continue; + } + fd = libevdev_new_from_fd(fd, &dev); + if (fd < 0) { + log("couldn't init libevdev for %s: %s\n", dir->d_name, strerror(-fd)); + continue; + } + log("Checking device %s\n", libevdev_get_name(dev)); + if (!check_for_keys(dev)) { + close(fd); + return 0; + } + close(fd); + } + closedir(d); + + return 1; +} diff --git a/iskey/meson.build b/iskey/meson.build new file mode 100644 index 0000000..aa317d4 --- /dev/null +++ b/iskey/meson.build @@ -0,0 +1,7 @@ +project('iskey', 'c') + +libevdev_dep = dependency('libevdev') + +iskey_exe = executable('iskey', + 'iskey.c', + dependencies: libevdev_dep) -- GitLab