#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/ioctl.h>
+#include <linux/limits.h>
#include <linux/input.h>
const struct key* lookup_key (const char *str, unsigned int len);
int keycode;
if ((keycode = evdev_get_keycode(fd, scancode, 1)) < 0) {
- if (keycode != -2)
- r = -1;
+ if (keycode == -2)
+ continue;
+ r = -1;
break;
}
f = fopen(filename, "r");
if (!f) {
perror(filename);
- r = -1;
- goto fail;
+ return -1;
}
while (!feof(f)) {
scancode, new_keycode, old_keycode);
}
fail:
+ fclose(f);
return r;
}
{
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;
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 */