X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=extras%2Fkeymap%2Fkeymap.c;h=597a53b467c20094b0233fb4d234f2ec38d438d2;hb=b3ca87a04a6bc32d852774211b35313ec8a09da1;hp=18e577a3a44cd209becb9531de3f4d19d1bdca7d;hpb=d03a6f20df9037b060ed28bac7b7e6b1c94b1be8;p=elogind.git diff --git a/extras/keymap/keymap.c b/extras/keymap/keymap.c index 18e577a3a..597a53b46 100644 --- a/extras/keymap/keymap.c +++ b/extras/keymap/keymap.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include const struct key* lookup_key (const char *str, unsigned int len); @@ -139,8 +141,9 @@ static int dump_table(int fd) { int keycode; if ((keycode = evdev_get_keycode(fd, scancode, 1)) < 0) { - if (keycode != -2) - r = -1; + if (keycode == -2) + continue; + r = -1; break; } @@ -189,8 +192,7 @@ static int merge_table(int fd, const char *filename) { f = fopen(filename, "r"); if (!f) { perror(filename); - r = -1; - goto fail; + return -1; } while (!feof(f)) { @@ -240,6 +242,7 @@ static int merge_table(int fd, const char *filename) { scancode, new_keycode, old_keycode); } fail: + fclose(f); return r; } @@ -247,7 +250,7 @@ static const char* default_keymap_path(const char* path) { static char result[PATH_MAX]; - /* If keymap file is given without a path, assume udev diretory; must end with '/' * */ + /* If keymap file is given without a path, assume udev directory; must end with '/' * */ if (!strchr(path, '/')) { snprintf(result, sizeof(result), "%s%s", LIBEXECDIR "/keymaps/", path); return result; @@ -255,45 +258,105 @@ static const char* default_keymap_path(const char* path) return path; } -static void print_key(struct input_event *event) +/* read one event; return 1 if valid */ +static int read_event(int fd, struct input_event* ev) { - static int cur_scancode = 0; + int ret; + ret = read(fd, ev, sizeof(struct input_event)); - /* save scan code for next EV_KEY event */ - if (event->type == EV_MSC && event->code == MSC_SCAN) - cur_scancode = event->value; + if (ret < 0) { + perror("read"); + return 0; + } + if (ret != sizeof(struct input_event)) { + fprintf(stderr, "did not get enough data for event struct, aborting\n"); + return 0; + } - /* key press */ - if (event->type == EV_KEY && event->value) - printf("scan code: 0x%02X key code: %s\n", cur_scancode, - format_keyname(key_names[event->code])); + return 1; +} + +static void print_key(uint32_t scancode, uint16_t keycode, int has_scan, int has_key) +{ + const char *keyname; + + /* ignore key release events */ + if (has_key == 1) + return; + + if (has_key == 0 && has_scan != 0) { + fprintf(stderr, "got scan code event 0x%02X without a key code event\n", + scancode); + return; + } + + if (has_scan != 0) + printf("scan code: 0x%02X ", scancode); + else + printf("(no scan code received) "); + + keyname = key_names[keycode]; + if (keyname != NULL) + printf("key code: %s\n", format_keyname(keyname)); + else + printf("key code: %03X\n", keycode); } static void interactive(int fd) { struct input_event ev; - int run = 1; + uint32_t last_scan = 0; + uint16_t last_key = 0; + int has_scan; /* boolean */ + int has_key; /* 0: none, 1: release, 2: press */ /* grab input device */ ioctl(fd, EVIOCGRAB, 1); + puts("Press ESC to finish, or Control-C if this device is not your primary keyboard"); + + has_scan = has_key = 0; + while (read_event(fd, &ev)) { + /* Drivers usually send the scan code first, then the key code, + * then a SYN. Some drivers (like thinkpad_acpi) send the key + * code first, and some drivers might not send SYN events, so + * keep a robust state machine which can deal with any of those + */ + + if (ev.type == EV_MSC && ev.code == MSC_SCAN) { + if (has_scan) { + fputs("driver did not send SYN event in between key events; previous event:\n", + stderr); + print_key(last_scan, last_key, has_scan, has_key); + has_key = 0; + } - puts("Press ESC to finish"); - while (run) { - switch (read(fd, &ev, sizeof(ev))) { - case -1: - perror("read"); - run = 0; - break; - case 0: - run = 0; - break; - default: - print_key(&ev); - /* stop on Escape key release */ - if (ev.type == EV_KEY && ev.code == KEY_ESC && ev.value == 0) - run = 0; - break; + last_scan = ev.value; + has_scan = 1; + /*printf("--- got scan %u; has scan %i key %i\n", last_scan, has_scan, has_key); */ } + else if (ev.type == EV_KEY) { + if (has_key) { + fputs("driver did not send SYN event in between key events; previous event:\n", + stderr); + print_key(last_scan, last_key, has_scan, has_key); + has_scan = 0; + } + + last_key = ev.code; + has_key = 1 + ev.value; + /*printf("--- got key %hu; has scan %i key %i\n", last_key, has_scan, has_key);*/ + + /* Stop on ESC */ + if (ev.code == KEY_ESC && ev.value == 0) + break; + } + else if (ev.type == EV_SYN) { + /*printf("--- got SYN; has scan %i key %i\n", has_scan, has_key);*/ + print_key(last_scan, last_key, has_scan, has_key); + + has_scan = has_key = 0; + } + } /* release input device */