static bool _al_xwin_get_keyboard_mapping(void) { int i; int count; int missing = 0; ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver(); memset(used, 0, sizeof used); memset(keycode_to_scancode, 0, sizeof keycode_to_scancode); XDisplayKeycodes(system->x11display, &min_keycode, &max_keycode); count = 1 + max_keycode - min_keycode; if (keysyms) { XFree(keysyms); } keysyms = XGetKeyboardMapping(system->x11display, min_keycode, count, &sym_per_key); ALLEGRO_INFO("%i keys, %i symbols per key.\n", count, sym_per_key); if (sym_per_key <= 0) { return false; } missing = 0; for (i = min_keycode; i <= max_keycode; i++) { KeySym sym = keysyms[sym_per_key * (i - min_keycode)]; KeySym sym2 = keysyms[sym_per_key * (i - min_keycode) + 1]; char *sym_str, *sym2_str; int allegro_key = 0; char str[1024]; sym_str = XKeysymToString(sym); sym2_str = XKeysymToString(sym2); snprintf(str, sizeof str, "key [%i: %s %s]", i, sym_str ? sym_str : "NULL", sym2_str ? sym2_str : "NULL"); /* Hack for French keyboards, to correctly map ALLEGRO_KEY_0 to ALLEGRO_KEY_9. */ if (sym2 >= XK_0 && sym2 <= XK_9) { allegro_key = find_allegro_key(sym2); } if (!allegro_key) { if (sym != NoSymbol) { allegro_key = find_allegro_key(sym); if (allegro_key == 0) { missing++; ALLEGRO_DEBUG("%s defering.\n", str); } } else { /* No KeySym for this key - ignore it. */ keycode_to_scancode[i] = -1; ALLEGRO_DEBUG("%s not assigned.\n", str); } } if (allegro_key) { bool is_double = false; if (used[allegro_key]) { is_double = true; } keycode_to_scancode[i] = allegro_key; key_names[allegro_key] = XKeysymToString(keysyms[sym_per_key * (i - min_keycode)]); used[allegro_key] = 1; ALLEGRO_DEBUG("%s%s assigned to %i.\n", str, is_double ? " *double*" : "", allegro_key); } } if (missing) { /* The keys still not assigned are just assigned arbitrarily now. */ for (i = min_keycode; i <= max_keycode; i++) { if (keycode_to_scancode[i] == 0) { find_unknown_key_assignment(i); } } } if (xmodmap) XFreeModifiermap(xmodmap); xmodmap = XGetModifierMapping(system->x11display); for (i = 0; i < 8; i++) { int j; char str[1024]; sprintf(str, "Modifier %d:", i + 1); for (j = 0; j < xmodmap->max_keypermod; j++) { KeyCode keycode = xmodmap->modifiermap[i * xmodmap->max_keypermod + j]; // XKeycodeToKeysym is deprecated //KeySym sym = XKeycodeToKeysym(system->x11display, keycode, 0); KeySym sym = XkbKeycodeToKeysym(system->x11display, keycode, 0, 0); char *sym_str = XKeysymToString(sym); sprintf(str + strlen(str), " %s", sym_str ? sym_str : "NULL"); } ALLEGRO_DEBUG("%s\n", str); } /* The [xkeymap] section can be useful, e.g. if trying to play a * game which has X and Y hardcoded as ALLEGRO_KEY_X and ALLEGRO_KEY_Y to mean * left/right movement, but on the X11 keyboard X and Y are far apart. * For normal use, a user never should have to touch [xkeymap] anymore * though, and proper written programs will not hardcode such mappings. */ ALLEGRO_CONFIG *c = al_get_system_config(); char const *key; ALLEGRO_CONFIG_ENTRY *it; key = al_get_first_config_entry(c, "xkeymap", &it); while (key) { char const *val; val = al_get_config_value(c, "xkeymap", key); int keycode = strtol(key, NULL, 10); int scancode = strtol(val, NULL, 10); if (keycode > 0 && scancode > 0) { keycode_to_scancode[keycode] = scancode; ALLEGRO_WARN("User override: KeySym %i assigned to %i.\n", keycode, scancode); } key = al_get_next_config_entry(&it); } return true; }
/* x_get_keyboard_mapping: * Generate a mapping from X11 keycodes to Allegro KEY_* codes. We have * two goals: Every keypress should be mapped to a distinct Allegro KEY_* * code. And we want the KEY_* codes to match the pressed * key to some extent. To do the latter, the X11 KeySyms produced by a key * are examined. If a match is found in the table above, the mapping is * added to the mapping table. If no known KeySym is found for a key (or * the same KeySym is found for more keys) - the remaining keys are * distributed arbitrarily to the remaining KEY_* codes. * * In a future version, this could be simplified by mapping *all* the X11 * KeySyms to KEY_* codes. */ void _xwin_get_keyboard_mapping(void) { int i; int count; int missing = 0; memset(used, 0, sizeof used); memset(_xwin.keycode_to_scancode, 0, sizeof _xwin.keycode_to_scancode); XLOCK(); XDisplayKeycodes(_xwin.display, &min_keycode, &max_keycode); count = 1 + max_keycode - min_keycode; if (keysyms) { XFree(keysyms); } keysyms = XGetKeyboardMapping(_xwin.display, min_keycode, count, &sym_per_key); TRACE (PREFIX_I "%i keys, %i symbols per key.\n", count, sym_per_key); missing = 0; for (i = min_keycode; i <= max_keycode; i++) { KeySym sym = keysyms[sym_per_key * (i - min_keycode)]; KeySym sym2 = keysyms[sym_per_key * (i - min_keycode) + 1]; char *sym_str, *sym2_str; int allegro_key = 0; sym_str = XKeysymToString(sym); sym2_str = XKeysymToString(sym2); TRACE (PREFIX_I "key [%i: %s %s]", i, sym_str ? sym_str : "NULL", sym2_str ? sym2_str : "NULL"); /* Hack for French keyboards, to correctly map KEY_0 to KEY_9. */ if (sym2 >= XK_0 && sym2 <= XK_9) { allegro_key = find_allegro_key(sym2); } if (!allegro_key) { if (sym != NoSymbol) { allegro_key = find_allegro_key(sym); if (allegro_key == 0) { missing++; TRACE (" defering.\n"); } } else { /* No KeySym for this key - ignore it. */ _xwin.keycode_to_scancode[i] = -1; TRACE (" not assigned.\n"); } } if (allegro_key) { if (used[allegro_key]) { TRACE(" *double*"); } _xwin.keycode_to_scancode[i] = allegro_key; key_names[allegro_key] = XKeysymToString(keysyms[sym_per_key * (i - min_keycode)]); used[allegro_key] = 1; TRACE(" assigned to %i.\n", allegro_key); } } if (missing) { /* The keys still not assigned are just assigned arbitrarily now. */ for (i = min_keycode; i <= max_keycode; i++) { if (_xwin.keycode_to_scancode[i] == 0) { find_unknown_key_assignment(i); } } } if (xmodmap) XFreeModifiermap(xmodmap); xmodmap = XGetModifierMapping(_xwin.display); for (i = 0; i < 8; i++) { int j; TRACE (PREFIX_I "Modifier %d:", i + 1); for (j = 0; j < xmodmap->max_keypermod; j++) { KeySym sym = XKeycodeToKeysym(_xwin.display, xmodmap->modifiermap[i * xmodmap->max_keypermod + j], 0); char *sym_str = XKeysymToString(sym); TRACE(" %s", sym_str ? sym_str : "NULL"); } TRACE("\n"); } /* The [xkeymap] section can be useful, e.g. if trying to play a * game which has X and Y hardcoded as KEY_X and KEY_Y to mean * left/right movement, but on the X11 keyboard X and Y are far apart. * For normal use, a user never should have to touch [xkeymap] anymore * though, and proper written programs will not hardcode such mappings. */ { char *section, *option_format; char option[128], tmp1[128], tmp2[128]; section = uconvert_ascii("xkeymap", tmp1); option_format = uconvert_ascii("keycode%d", tmp2); for (i = min_keycode; i <= max_keycode; i++) { int scancode; uszprintf(option, sizeof(option), option_format, i); scancode = get_config_int(section, option, -1); if (scancode > 0) { _xwin.keycode_to_scancode[i] = scancode; TRACE(PREFIX_I "User override: KeySym %i assigned to %i.\n", i, scancode); } } } XUNLOCK(); }