From e5077d0226d0ef8b53e0d4d67a977da7b154721c Mon Sep 17 00:00:00 2001 From: ac-stef Date: Sun, 25 Jun 2017 17:51:38 +0200 Subject: [PATCH] use both keycodes and scancodes of keypress events If a keycode can not be found on the list from keymap.cfg a second search is done for the scancode. This should be helpful to assign layout-dependent keys with rare keycodes. Also: use a hash table for the keys (instead of a list). Add two new scan codes for dead keys on german layouts: LEFTOF1 and LEFTOFDEL. --- config/keymap.cfg | 2 ++ source/src/console.cpp | 70 ++++++++++++++++++++---------------------- source/src/main.cpp | 12 ++++---- source/src/protos.h | 2 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/config/keymap.cfg b/config/keymap.cfg index 0d4013bf..f739968c 100644 --- a/config/keymap.cfg +++ b/config/keymap.cfg @@ -149,6 +149,8 @@ keymap 223 SZ keymap 252 UE keymap 246 OE keymap 228 AE +keymap (sc 53) LEFTOF1 +keymap (sc 46) LEFTOFDEL //keymap 37 PERCENT //keymap (sc 102) POWER //keymap (sc 107) F16 diff --git a/source/src/console.cpp b/source/src/console.cpp index adb7b9d7..e27b9d07 100644 --- a/source/src/console.cpp +++ b/source/src/console.cpp @@ -141,14 +141,15 @@ int rendercommand(int x, int y, int w) // keymap is defined externally in keymap.cfg -vector keyms; +hashtable keyms(256); const char *keycmds[keym::NUMACTIONS] = { "bind", "editbind", "specbind" }; inline const char *keycmd(int type) { return type >= 0 && type < keym::NUMACTIONS ? keycmds[type] : ""; } void keymap(int *code, char *key) { - keym &km = keyms.add(); + if(findbindc(*code)) { clientlogf("keymap: double assignment for code %d ignored", *code); return; } + keym &km = keyms[*code]; km.code = *code; km.name = newstring(key); } @@ -157,7 +158,7 @@ COMMAND(keymap, "is"); keym *findbind(const char *key) { - loopv(keyms) if(!strcasecmp(keyms[i].name, key)) return &keyms[i]; + enumerate(keyms, keym, km, if(!strcasecmp(km.name, key)) return &km;); return NULL; } @@ -165,28 +166,26 @@ keym **findbinda(const char *action, int type) { static vector res; res.setsize(0); - loopv(keyms) if(!strcasecmp(keyms[i].actions[type], action)) res.add(&keyms[i]); + enumerate(keyms, keym, km, if(!strcasecmp(km.actions[type], action)) res.add(&km);); res.add(NULL); return res.getbuf(); } keym *findbindc(int code) { - loopv(keyms) if(keyms[i].code==code) return &keyms[i]; - return NULL; + return keyms.access(code); } void findkey(int *code) { const char *res = "-255"; - loopv(keyms) - { - if(keyms[i].code == *code) + enumerate(keyms, keym, km, + if(km.code == *code) { - res = keyms[i].name; + res = km.name; break; } - } + ); result(res); } COMMAND(findkey, "i"); @@ -194,14 +193,13 @@ COMMAND(findkey, "i"); void findkeycode(const char* s) { int res = -255; - loopv(keyms) - { - if(!strcmp(s, keyms[i].name)) + enumerate(keyms, keym, km, + if(!strcmp(s, km.name)) { - res = keyms[i].code; + res = km.code; break; } - } + ); intret(res); } COMMAND(findkeycode, "s"); @@ -213,7 +211,7 @@ char *keyaction = NULL; VAR(_defaultbinds, 0, 0, 1); -COMMANDF(_resetallbinds, "", () { if(_defaultbinds) loopv(keyms) loopj(keym::NUMACTIONS) bindkey(&keyms[i], "", j); }); +COMMANDF(_resetallbinds, "", () { if(_defaultbinds) enumerate(keyms, keym, km, loopj(keym::NUMACTIONS) bindkey(&km, "", j);); }); bool bindkey(keym *km, const char *action, int type) { @@ -254,14 +252,13 @@ void searchbinds(const char *action, int type) if(!action || !action[0]) return; if(type < keym::ACTION_DEFAULT || type >= keym::NUMACTIONS) { conoutf("invalid bind type \"%d\"", type); return; } vector names; - loopv(keyms) - { - if(!strcmp(keyms[i].actions[type], action)) + enumerate(keyms, keym, km, + if(!strcmp(km.actions[type], action)) { if(names.length()) names.add(' '); - names.put(keyms[i].name, strlen(keyms[i].name)); + names.put(km.name, strlen(km.name)); } - } + ); resultcharvector(names, 0); } @@ -566,18 +563,19 @@ void processtextinput(const char *text) } } -void keypress(int code, bool isdown, SDL_Keymod mod) +void keypress(int keycode, int scancode, bool isdown, SDL_Keymod mod) { - keym *haskey = NULL; - loopv(keyms) if(keyms[i].code==code) { haskey = &keyms[i]; break; } + 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 && haskey->pressed) execbind(*haskey, isdown); // allow pressed keys to release - else if(saycommandon) consolekey(code, isdown, mod); // keystrokes go to commandline - else if(!menukey(code, isdown)) // keystrokes go to menu + else if(saycommandon) consolekey(keycode, isdown, mod); // keystrokes go to commandline + else if(!menukey(keycode, isdown)) // keystrokes go to menu { if(haskey) execbind(*haskey, isdown); } - if(isdown) exechook(HOOK_SP, "KEYPRESS", "KEYPRESS %d", code); - else exechook(HOOK_SP, "KEYRELEASE", "%d", code); + if(keycode & SDLK_SCANCODE_MASK) scancode = keycode & ~SDLK_SCANCODE_MASK; + if(isdown) exechook(HOOK_SP, "KEYPRESS", "KEYPRESS %d %d", keycode, scancode); + else exechook(HOOK_SP, "KEYRELEASE", "%d %d", keycode, scancode); } char *getcurcommand(int *pos) @@ -590,12 +588,10 @@ VARP(omitunchangeddefaultbinds, 0, 1, 2); void writebinds(stream *f) { - loopv(keyms) - { - keym *km = &keyms[i]; - loopj(3) if(*km->actions[j] && (!km->unchangeddefault[j] || omitunchangeddefaultbinds < 2)) - f->printf("%s%s \"%s\" %s\n", km->unchangeddefault[j] && omitunchangeddefaultbinds ? "//" : "", keycmd(j), km->name, escapestring(km->actions[j])); - } + enumerate(keyms, keym, km, + loopj(3) if(*km.actions[j] && (!km.unchangeddefault[j] || omitunchangeddefaultbinds < 2)) + f->printf("%s%s \"%s\" %s\n", km.unchangeddefault[j] && omitunchangeddefaultbinds ? "//" : "", keycmd(j), km.name, escapestring(km.actions[j])); + ); } bool textinputbuffer::say(const char *c) @@ -784,6 +780,8 @@ void writekeymap() // create keymap.cfg with proper constants from SDL2 header f { 252, "UE" }, { 246, "OE" }, { 228, "AE" }, + { SDL_SCANCODE_GRAVE | SDLK_SCANCODE_MASK, "LEFTOF1" }, // may not produce a proper keycode if the layout has dead keys + { SDL_SCANCODE_EQUALS | SDLK_SCANCODE_MASK, "LEFTOFDEL" }, { -1, " " }, // keys below are commented out by default { SDLK_PERCENT, "PERCENT" }, { SDLK_POWER, "POWER" }, @@ -902,7 +900,7 @@ void writekeymap() // create keymap.cfg with proper constants from SDL2 header f for(int i = 0; keymaptab[i].keycode; i++) { if(keymaptab[i].keyname[0] == ' ') c = "//"; - else f->printf(keymaptab[i].keycode < (1<<30) ? "%skeymap %d %s\n" : "%skeymap (sc %d) %s\n", c, keymaptab[i].keycode & (keymaptab[i].keycode > 0 ? ((1<<30)-1) : -1), keymaptab[i].keyname); + else f->printf(keymaptab[i].keycode < SDLK_SCANCODE_MASK ? "%skeymap %d %s\n" : "%skeymap (sc %d) %s\n", c, keymaptab[i].keycode & (keymaptab[i].keycode > 0 ? (SDLK_SCANCODE_MASK-1) : -1), keymaptab[i].keyname); } f->printf("\npop sc\nexec config/resetbinds.cfg\n"); delete f; diff --git a/source/src/main.cpp b/source/src/main.cpp index 68fb1fdc..e92af365 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -819,7 +819,7 @@ void checkinput() entropy_add_byte(event.key.keysym.sym ^ totalmillis); EVENTDEBUG(concatformatstring(eb, " sym %d (%Xh), scancode %d (%Xh), state %d, repeat %d", event.key.keysym.sym, event.key.keysym.sym, event.key.keysym.scancode, event.key.keysym.scancode, event.key.state, event.key.repeat)); if(event.key.keysym.sym == SDLK_SCANCODE_MASK) event.key.keysym.sym |= event.key.keysym.scancode; // workaround SDL 2.0.5 bug which returns sym == 40000000h for all dead keys - if(!event.key.repeat || keyrepeatmask) keypress(event.key.keysym.sym, event.key.state==SDL_PRESSED, (SDL_Keymod)event.key.keysym.mod); + if(!event.key.repeat || keyrepeatmask) keypress(event.key.keysym.sym, event.key.keysym.scancode, event.key.state==SDL_PRESSED, (SDL_Keymod)event.key.keysym.mod); break; case SDL_TEXTINPUT: @@ -924,7 +924,7 @@ void checkinput() case SDL_MOUSEBUTTONUP: EVENTDEBUG(concatformatstring(eb, "(SDL_MOUSEBUTTON%s) button %d, state %d, clicks %d, x %d, y %d", event.type == SDL_MOUSEBUTTONUP ? "UP" : "DOWN", event.button.button, event.button.state, event.button.clicks, event.button.x, event.button.y)); if(lasttype==event.type && lastbut==event.button.button) break; - keypress(-(event.button.button > 3 ? (event.button.button + 4) : event.button.button), event.button.state != SDL_RELEASED); + keypress(-(event.button.button > 3 ? (event.button.button + 4) : event.button.button), 0, event.button.state != SDL_RELEASED); lasttype = event.type; lastbut = event.button.button; break; @@ -934,14 +934,14 @@ void checkinput() if(event.wheel.y) { int key = event.wheel.y > 0 ? SDL_AC_BUTTON_WHEELUP : SDL_AC_BUTTON_WHEELDOWN; - keypress(key, true); // Emulate SDL1-style mouse wheel events by immediately "releasing" the wheel "button" - keypress(key, false); + keypress(key, 0, true); // Emulate SDL1-style mouse wheel events by immediately "releasing" the wheel "button" + keypress(key, 0, false); } if(event.wheel.x) { int key = event.wheel.x > 0 ? SDL_AC_BUTTON_RIGHT : SDL_AC_BUTTON_LEFT; - keypress(key, true); - keypress(key, false); + keypress(key, 0, true); + keypress(key, 0, false); } break; } diff --git a/source/src/protos.h b/source/src/protos.h index 2eef34ea..126340a0 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -124,7 +124,7 @@ struct color extern stream *clientlogfile; extern vector *bootclientlog; -extern void keypress(int code, bool isdown, SDL_Keymod mod = KMOD_NONE); +extern void keypress(int keycode, int scancode, bool isdown, SDL_Keymod mod = KMOD_NONE); extern int rendercommand(int x, int y, int w); extern void renderconsole(); extern char *getcurcommand(int *pos);