From 15699204a55b00f190719629a9eb70f1858d12f3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 May 2007 17:11:46 +0000 Subject: * automatically discover the proper input device * support symbolic key names git-svn-id: file:///home/lennart/svn/public/keyfuzz/trunk@19 e03e4fad-c0d1-0310-aabf-8987f8117c4c --- src/Makefile.am | 19 +++++++- src/keyfuzz.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 149 insertions(+), 13 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index c0b154a..8e04f69 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ sbin_PROGRAMS = keyfuzz -keyfuzz_SOURCES = keyfuzz.c cmdline.c cmdline.h +keyfuzz_SOURCES = keyfuzz.c cmdline.c cmdline.h keys-from-name.h keys-to-name.h keyfuzz_CFLAGS = $(AM_CFLAGS) -DPKGSYSCONFDIR="\"${sysconfdir}/@PACKAGE@\"" EXTRA_DIST = keyfuzz.ggo @@ -29,9 +29,24 @@ CLEANFILES = if USE_GENGETOPT CLEANFILES += cmdline.c cmdline.h -BUILT_SOURCES += cmdline.c cmdline.h +BUILT_SOURCES += cmdline.c cmdline.h cmdline.c cmdline.h: keyfuzz.ggo Makefile gengetopt < $< endif + +keys.txt: input.h Makefile + awk '/^#define.*KEY_/ { if ($$2 != "KEY_MAX") { print $$2 } }' < $< > $@ + +keys-from-name.gperf: keys.txt Makefile + awk 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print $$1 ", " $$1 }' < $< > $@ + +keys-from-name.h: keys-from-name.gperf Makefile + gperf -t --ignore-case -N lookup_key -H hash_key_name -p -C < $< > $@ + +keys-to-name.h: keys.txt Makefile + awk 'BEGIN{ print "const char* const key_names[KEY_MAX] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@ + +CLEANFILES += keys-from-name.h keys-to-name.h +BUILT_SOURCES += keys-from-name.h keys-to-name.h diff --git a/src/keyfuzz.c b/src/keyfuzz.c index e2857ba..7ce36d5 100644 --- a/src/keyfuzz.c +++ b/src/keyfuzz.c @@ -5,14 +5,19 @@ #include #include #include -#include +#include +#include "input.h" #include "cmdline.h" +#include "keys-from-name.h" +#include "keys-to-name.h" + #define MAX_SCANCODES 1024 static struct gengetopt_args_info args; + int evdev_open(const char *dev) { int fd; char fn[PATH_MAX]; @@ -131,7 +136,10 @@ int dump_table(int fd) { break; } - printf("0x%03x\t0x%03x\n", scancode, keycode); + if (keycode < KEY_MAX && key_names[keycode]) + printf("0x%03x\t%s\n", scancode, key_names[keycode]); + else + printf("0x%03x\t0x%03x\n", scancode, keycode); } if (!r) @@ -142,7 +150,7 @@ fail: } int merge_table(int fd) { - int r = -1; + int r = 0; int line = 0; while (!feof(stdin)) { @@ -160,27 +168,131 @@ int merge_table(int fd) { continue; if (sscanf(p, "%i %i", &scancode, &new_keycode) != 2) { - fprintf(stderr, "Parse failure at line %i\n", line); - goto fail; + char t[20]; + const struct key *k; + + if (sscanf(p, "%i %20s", &scancode, t) != 2) { + fprintf(stderr, "WARNING: Parse failure at line %i, ignoring.\n", line); + r = -1; + continue; + } + + if (!(k = lookup_key(t, strlen(t)))) { + fprintf(stderr, "WARNING: Unknown key '%s' at line %i, ignoring.\n", t, line); + r = -1; + continue; + } + + new_keycode = k->id; } - if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) + + + if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) { + r = -1; goto fail; + } - if (evdev_set_keycode(fd, scancode, new_keycode) < 0) - goto fail; + if (evdev_set_keycode(fd, scancode, new_keycode) < 0) { + r = -1; + goto fail; + } if (args.verbose_flag && new_keycode != old_keycode) fprintf(stderr, "Remapped scancode 0x%02x to 0x%02x. (prior: 0x%02x)\n", scancode, new_keycode, old_keycode); } - r = 0; - fail: return r; } +static char *find_atkbd_sysfs(void) { + glob_t globbuf; + char **p; + int ret; + char *r = NULL; + + if ((ret = glob("/sys/class/input/event*", GLOB_ERR, NULL, &globbuf))) { + fprintf(stderr, "Warning! Failed to access sysfs: %s\n", + ret == GLOB_NOSPACE ? strerror(ENOMEM) : + (ret == GLOB_ABORTED ? strerror(errno) : + (ret == GLOB_NOMATCH ? strerror(ENOENT) : "Unknown error"))); + return NULL; + } + + for (p = globbuf.gl_pathv; *p; p++) { + FILE *f; + static char fn[PATH_MAX]; + char ln[16]; + + snprintf(fn, sizeof(fn), "%s/device/description", *p); + + if (!(f = fopen(fn, "r"))) + continue; + + if (fgets(ln, sizeof(ln), f)) { + + if (strcmp(ln, "i8042 KBD port\n") == 0) { + (fn+17)[strcspn(fn+17, "/")] = 0; + r = strdup(fn + 17); + fclose(f); + goto finish; + } + } + + fclose(f); + } + +finish: + globfree(&globbuf); + return r; +} + +static char *find_atkbd_procfs(void) { + FILE *f; + char *r = NULL; + int found = 0; + + if (!(f = fopen("/proc/bus/input/devices", "r"))) { + fprintf(stderr, "Warning! Failed to access procfs: %s\n", strerror(errno)); + return NULL; + } + + while (!feof(f)) { + char ln[128]; + + if (!(fgets(ln, sizeof(ln), f))) + break; + + if (!found) { + + if (strcmp(ln, "N: Name=\"AT Translated Set 2 keyboard\"\n") == 0) + found = 1; + + } else { + + if (strncmp(ln, "H: Handlers=", 12) == 0) { + char *e; + + if ((e = strstr(ln+12, "event"))) { + e[strcspn(e, " \n\t")] = 0; + r = strdup(e); + goto finish; + } + } + + if (strcmp(ln, "\n") == 0) + found = 0; + } + + } + +finish: + fclose(f); + return r; +} + int main(int argc, char *argv[]) { int fd = -1, r = 1; @@ -190,8 +302,17 @@ int main(int argc, char *argv[]) { cmdline_parser_print_help(); goto fail; } + + if (!args.device_arg) + args.device_arg = find_atkbd_sysfs(); + + if (!args.device_arg) + args.device_arg = find_atkbd_procfs(); + + if (!args.device_arg) + args.device_arg = "event0"; - if ((fd = evdev_open(args.device_arg ? args.device_arg : "event0")) < 0) + if ((fd = evdev_open(args.device_arg)) < 0) goto fail; if (args.get_flag) { -- cgit