summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2007-05-08 17:11:46 +0000
committerLennart Poettering <lennart@poettering.net>2007-05-08 17:11:46 +0000
commit15699204a55b00f190719629a9eb70f1858d12f3 (patch)
tree28a84dd862d6cbe028355ed38fa3f2ecdebe1bce
parent2c375a713a93f1afda3a25378c196de155e74be3 (diff)
* 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
-rw-r--r--src/Makefile.am19
-rw-r--r--src/keyfuzz.c143
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 <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <linux/input.h>
+#include <glob.h>
+#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) {