From 135f9f4a901d6fec9fa91f018987a433a2e5fbe3 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Tue, 4 Jul 2017 14:47:24 +0200 Subject: [PATCH] fully automatic keymap generation If a key is not listed in keymap.cfg but SDL provides a good enough name for the corresponding scancode, a keymap entry is generated automatically. If a key can't be found when adding a bind, it is checked, if SDL can resolve the key name. The resolved keybind is then used to recreate the keymap entry - and the bind can succeed. Some SDL names for scancodes may not be usable as keymap names: if the name contains (, ), $ or ", it will be rejected. Also, SDL does not provide names for all scancodes. Scancode names provided by SDL can be platform-dependant, therefore recreating the bind may fail on a different platform. However, the feature should work fine with most nonstandard keys - and the information written to clientlog can be used to amend keymap.cfg --- source/src/console.cpp | 30 +++++++++++++++++++++++++++++- source/src/protocol.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/source/src/console.cpp b/source/src/console.cpp index e27b9d07..b2452794 100644 --- a/source/src/console.cpp +++ b/source/src/console.cpp @@ -153,7 +153,6 @@ void keymap(int *code, char *key) km.code = *code; km.name = newstring(key); } - COMMAND(keymap, "is"); keym *findbind(const char *key) @@ -176,6 +175,21 @@ keym *findbindc(int code) return keyms.access(code); } +keym *autokeymap(int keycode, int scancode) +{ + static bool scdone[SDL_NUM_SCANCODES] = { false }; + int sc = keycode <= SDLK_SCANCODE_MASK ? scancode : (keycode & (SDLK_SCANCODE_MASK - 1)); + if(sc < 0 || sc >= SDL_NUM_SCANCODES || scdone[sc]) return NULL; + scdone[sc] = true; + string text; + filtertext(text, SDL_GetScancodeName((SDL_Scancode) sc), FTXT__AUTOKEYMAPNAME); + if(!*text || (int)SDL_GetScancodeFromName(text) != sc || findbind(text)) return NULL; // name is not unique (collision probably caused by filtertext) or can't be properly resolved in reverse + clientlogf("autokeymap: create keymap entry for scancode %d, \"%s\"", sc, text); + sc |= SDLK_SCANCODE_MASK; + keymap(&sc, text); + return keyms.access(sc); +} + void findkey(int *code) { const char *res = "-255"; @@ -228,6 +242,19 @@ bool bindkey(keym *km, const char *action, int type) void bindk(const char *key, const char *action, int type) { keym *km = findbind(key); + if(!km) + { + string text; + filtertext(text, key, FTXT__AUTOKEYMAPNAME); + int sc = *text && !strcmp(key, text) ? (int)SDL_GetScancodeFromName(text) : SDL_SCANCODE_UNKNOWN; + if(sc != SDL_SCANCODE_UNKNOWN) + { + clientlogf("autokeymap: re-create keymap entry for scancode %d, \"%s\"", sc, text); + sc |= SDLK_SCANCODE_MASK; + keymap(&sc, text); + km = findbind(key); + } + } if(!km) { conoutf("unknown key \"%s\"", key); return; } bindkey(km, action, type); } @@ -567,6 +594,7 @@ void keypress(int keycode, int scancode, bool isdown, SDL_Keymod mod) { keym *haskey = keyms.access(keycode); if(!haskey && !(keycode & SDLK_SCANCODE_MASK) && scancode) haskey = keyms.access(scancode | SDLK_SCANCODE_MASK); // keycode not found: maybe we know the scancode + if(!haskey && isdown) haskey = autokeymap(keycode, scancode); if(haskey && haskey->pressed) execbind(*haskey, isdown); // allow pressed keys to release else if(saycommandon) consolekey(keycode, isdown, mod); // keystrokes go to commandline else if(!menukey(keycode, isdown)) // keystrokes go to menu diff --git a/source/src/protocol.h b/source/src/protocol.h index fd30d6a7..cefbb5a0 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -223,3 +223,4 @@ enum #define FTXT__ZIPDESC (FTXT_NOWHITE | FTXT_ALLOWBLANKS | FTXT_TABTOBLANK | FTXT_NOCOLOR | FTXT_SAFECS) #define FTXT__CERTFILENAME (FTXT_MAPNAME | FTXT_TOLOWER) #define FTXT__CONSOLEPASTE (FTXT_TABTOBLANK) +#define FTXT__AUTOKEYMAPNAME (FTXT_SAFECS)