/* * Test Xen keymaps * * Compile: * cc -o evconv evconv.c -lX11 * * Usage: * evconv /usr/share/xen/qemu/keymaps/ * * The keysyms coming from a keypress or keyrelease in a small X * window are matched to the corresponding scancode from a PS/2 * keyboard (and it must be a PS/2 keyboard: USB keyboards won't * work). Each distinct keypress or keyrelese is printed out as the * corresponding scancode and keysym. For example, "Q", "Shift-Q" * "AltGr-Q" and "Shift-Altgr-Q" should all produce the scancode 0x10 * although they will, of course, result in four different keysyms. * */ #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_VNC_KEYSYM #include "vnc_keysym.h" #endif #define MAX_SCANCODE 255 struct ks { int keysym; int scancode; }; typedef struct { int n; struct ks k[MAX_SCANCODE]; } keysym_map_t; #define KEY_LOCALSTATE 0x1 #define KEY_KEYPAD 0x2 typedef struct { keysym_map_t plain; keysym_map_t shift; keysym_map_t altgr; keysym_map_t shift_altgr; keysym_map_t numlock; unsigned char flags [MAX_SCANCODE]; } keysym_maps_t; const char *keyboard_name = "AT Translated Set 2 keyboard"; static Display *open_display (char *display_name, int argc, char **argv); static void get_keyboard_info (Display *dpy, int *numlock_mask, int *altgr_mask); static void load_keymap (char *path, keysym_maps_t *map); static void load_keymap1 (char *file, keysym_maps_t *map); static void handler (int sig); static void prepare_keymap(keysym_maps_t *); static int lookup_scancode(keysym_map_t *map, int keysym); static int lookup_keysym (const char *name); static volatile bool done = false; int main (int argc, char **argv) { Display *dpy; int numlock_mask = 0; int altgr_mask = 0; keysym_maps_t map; KeySym last = NoSymbol; dpy = open_display(NULL, argc, argv); get_keyboard_info(dpy, &numlock_mask, &altgr_mask); memset(&map, 0, sizeof(map)); if (argv[1]) load_keymap(argv[1], &map); prepare_keymap(&map); sigaction(SIGINT, &((struct sigaction) { .sa_handler = handler }), NULL); while (!done) { XEvent event; XNextEvent(dpy, &event); if (event.type == KeyPress || event.type == KeyRelease) { XKeyEvent *ev = (XKeyEvent *) &event; KeySym ks = NoSymbol; char *keyname; char str[256]; int scancode; XLookupString(ev, str, sizeof(str)-1, &ks, NULL); if (last == ks) { if (event.type == KeyRelease) last = NoSymbol; continue; } if (event.type == KeyPress) last = ks; keyname = XKeysymToString(ks) ?: "VoidSymbol"; if ((scancode = lookup_scancode(&map.plain, ks))) printf("%02x %s%s%s\n", scancode, keyname, (map.flags[scancode] & KEY_LOCALSTATE) ? " (localstate)" : "", (map.flags[scancode] & KEY_KEYPAD) ? " (numlock off)" : ""); if ((scancode = lookup_scancode(&map.shift, ks))) printf("%02x %s (shift)\n", scancode, keyname); if ((scancode = lookup_scancode(&map.altgr, ks))) printf("%02x %s (altgr)\n", scancode, keyname); if ((scancode = lookup_scancode(&map.shift_altgr, ks))) printf("%02x %s (shift altgr)\n", scancode, keyname); if ((scancode = lookup_scancode(&map.numlock, ks))) printf("%02x %s (numlock on)\n", scancode, keyname); fflush(stdout); } } exit(0); } static Display *open_display (char *display_name, int argc, char **argv) { Display *dpy; XSizeHints hints; XSetWindowAttributes attr; Window w; if (!(dpy = XOpenDisplay(display_name))) { fprintf(stderr, "Can't open display\n"); exit(1); } hints.width = hints.min_width = 100; hints.height = hints.min_height = 100; hints.flags = PMinSize; hints.x = hints.y = 0; memset(&attr, 0, sizeof(attr)); attr.background_pixel = WhitePixel(dpy, DefaultScreen(dpy)); attr.border_pixel = BlackPixel(dpy, DefaultScreen(dpy)); attr.event_mask = KeyPressMask | KeyReleaseMask; w = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 100, 0, 0, InputOutput, CopyFromParent, CWBackPixel | CWBorderPixel | CWEventMask, &attr); XSetStandardProperties(dpy, w, "evkey", NULL, 0, argv, argc, &hints); XMapWindow(dpy, w); return dpy; } static void get_keyboard_info (Display *dpy, int *numlock_mask, int *altgr_mask) { int min_keycode, max_keycode, keysyms_per_keycode; XModifierKeymap *map; int i, j; XDisplayKeycodes(dpy, &min_keycode, &max_keycode); XGetKeyboardMapping(dpy, min_keycode, max_keycode - min_keycode + 1, &keysyms_per_keycode); map = XGetModifierMapping(dpy); for (i = 0; i < 8*map->max_keypermod; i += map->max_keypermod) { for (j = 0; j < map->max_keypermod; j++) { if (map->modifiermap[i+j]) { int index = 0; KeySym ks = NoSymbol; while (ks == NoSymbol && index < keysyms_per_keycode) ks = XKeycodeToKeysym(dpy, map->modifiermap[i+j], index++); if (*numlock_mask == 0 && ks == XK_Num_Lock) *numlock_mask = 1 << (i / map->max_keypermod); else if (*altgr_mask == 0 && ks == XK_ISO_Level3_Shift) *altgr_mask = 1 << (i / map->max_keypermod); } } } } static void load_keymap (char *path, keysym_maps_t *map) { if (strchr(path, '/')) { char *dir = strdup(path); char *file = strrchr(dir, '/'); *file++ = '\0'; chdir(dir); load_keymap1(file, map); free(dir); } else { load_keymap1(path, map); } } static void load_keymap1 (char *file, keysym_maps_t *map) { char line[1024]; FILE *f; if (!(f = fopen(file, "r"))) { perror(file); exit(1); } while (fgets(line, sizeof(line), f)) { char *ptr = strchr(line, '#'); char *keyname, *p1, *p2; KeySym ks; int code = -1; bool shift = false; bool altgr = false; bool addupper = false; bool numlock = false; bool inhibit = false; if (ptr) *ptr-- = '\0'; else ptr = &line[strlen(line)-1]; while (isspace(*ptr)) *ptr-- = '\0'; if (sscanf(line, "include %as", &p1) == 1) { load_keymap(p1, map); free(p1); continue; } else if (sscanf(line, "map %i", &code) == 1) { continue; } else if (sscanf(line, "%as %i %as %as", &keyname, &code, &p1, &p2) == 4) { altgr = (strcmp(p1, "altgr") == 0 || strcmp(p2, "altgr") == 0); shift = (strcmp(p1, "shift") == 0 || strcmp(p2, "shift") == 0); free(p1); free(p2); } else if (sscanf(line, "%as %i %as", &keyname, &code, &p1) == 3) { altgr = (strcmp(p1, "altgr") == 0); shift = (strcmp(p1, "shift") == 0); addupper = (strcmp(p1, "addupper") == 0); numlock = (strcmp(p1, "numlock") == 0); inhibit = (strcmp(p1, "inhibit") == 0); free(p1); } else if (sscanf(line, "%as %i", &keyname, &code) != 2) { continue; } if (!keyname) { fprintf(stderr, "malformed line: \"%s\"\n", line); continue; } if ((ks = lookup_keysym(keyname)) == 0) { fprintf(stderr, "Unknown keysym \"%s\"\n", keyname); free(keyname); continue; } free(keyname); if (inhibit) continue; if (code <= 0 || code >= MAX_SCANCODE) { fprintf(stderr, "Scancode out of range at \"%s\"\n", line); continue; } if (numlock) map->numlock.k[code].keysym = ks; else if (shift && altgr) map->shift_altgr.k[code].keysym = ks; else if (shift) map->shift.k[code].keysym = ks; else if (altgr) map->altgr.k[code].keysym = ks; else { map->plain.k[code].keysym = ks; if (addupper) /* this is somewhat dubious */ map->shift.k[code].keysym = ks + 'A' - 'a'; } } } static void handler (int sig) { done = true; exit(0); } int cmp (const void *a, const void *b) { return ((struct ks *) b)->keysym - ((struct ks *) a)->keysym; } static void sort_map (keysym_map_t *map) { int i; for (i = 0; i < MAX_SCANCODE; i++) map->k[i].scancode = i; qsort(map->k, MAX_SCANCODE, sizeof(struct ks), cmp); for (map->n = 0; map->n < MAX_SCANCODE; map->n++) if (!map->k[map->n].keysym) break; } static void prepare_keymap (keysym_maps_t *map) { int i; for (i = 0; i < MAX_SCANCODE; i++) { if (!(map->shift.k[i].keysym || map->altgr.k[i].keysym || map->shift_altgr.k[i].keysym)) map->flags[i] |= KEY_LOCALSTATE; if (map->numlock.k[i].keysym) map->flags[i] |= KEY_KEYPAD; } sort_map(&map->plain); sort_map(&map->shift); sort_map(&map->altgr); sort_map(&map->shift_altgr); sort_map(&map->numlock); } static int lookup_scancode (keysym_map_t *map, int keysym) { int l = 0, r = map->n-1; while (l <= r) { int m = (l + r)/2; if (map->k[m].keysym == keysym) return map->k[m].scancode; else if (map->k[m].keysym < keysym) r = m-1; else l = m+1; } return 0; } #ifdef USE_VNC_KEYSYM static int keysym_cmp (const void *a, const void *b) { return strcmp(((name2keysym_t *) a)->name, ((name2keysym_t *) b)->name); } static int lookup_keysym (const char *name) { int l, r; static int n = -1; if (n < 0) { for (n = 0; name2keysym[n].name; n++); qsort(name2keysym, n, sizeof(name2keysym_t), keysym_cmp); } l = 0; r = n-1; while (l <= r) { int m = (l + r)/2; int cmp = strcmp(name2keysym[m].name, name); if (cmp < 0) l = m + 1; else if (cmp > 0) r = m - 1; else return name2keysym[m].keysym; } if (name[0] == 'U') { /* unicode symbol key */ char *ptr; int k = strtol(name+1, &ptr, 16); return *ptr ? 0 : k; } return 0; } #else static int lookup_keysym (const char *name) { return XStringToKeysym(name); } #endif