From bbde4e2a8182f9e49a6882ba21df1aa9a6705b97 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Wed, 8 Apr 2020 04:41:59 +0200 Subject: [PATCH] Support scancodes as fallback for unknown keyboard keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we can't map a SDL_KEYDOWN/KEYUP events SDL_Keycode to a known Quake2 K_* keycode, we try to map the SDL_Scancode to one of the new K_SC_* YQ2 scancodes instead. The scancode name corresponds to the key at that position on US-QWERTY keyboards *not* the one in the local layout, for example the German 'Ö' key is K_SC_SEMICOLON. This way (hopefully!) all keys on common keyboards can be bound, regardless of their layout. The key name won't be immediately obvious to the user, but it's only a fallback and better than nothing. fixes #543 --- src/client/cl_keyboard.c | 58 ++++++++++++++++++++++++ src/client/header/keyboard.h | 63 ++++++++++++++++++++++++++ src/client/input/sdl.c | 88 ++++++++++++++++++++++++++++++++++-- 3 files changed, 206 insertions(+), 3 deletions(-) diff --git a/src/client/cl_keyboard.c b/src/client/cl_keyboard.c index 4e445bcd..6fde0d59 100644 --- a/src/client/cl_keyboard.c +++ b/src/client/cl_keyboard.c @@ -228,6 +228,64 @@ keyname_t keynames[] = { {"MENU", K_MENU}, {"UNDO", K_UNDO}, + // entries for the mapped scancodes, see comment above K_SC_A in keyboard.h +#define MY_SC_ENTRY(X) { #X , K_ ## X } + + // { "SC_A", K_SC_A }, + MY_SC_ENTRY(SC_A), + MY_SC_ENTRY(SC_B), + MY_SC_ENTRY(SC_C), + MY_SC_ENTRY(SC_D), + MY_SC_ENTRY(SC_E), + MY_SC_ENTRY(SC_F), + MY_SC_ENTRY(SC_G), + MY_SC_ENTRY(SC_H), + MY_SC_ENTRY(SC_I), + MY_SC_ENTRY(SC_J), + MY_SC_ENTRY(SC_K), + MY_SC_ENTRY(SC_L), + MY_SC_ENTRY(SC_M), + MY_SC_ENTRY(SC_N), + MY_SC_ENTRY(SC_O), + MY_SC_ENTRY(SC_P), + MY_SC_ENTRY(SC_Q), + MY_SC_ENTRY(SC_R), + MY_SC_ENTRY(SC_S), + MY_SC_ENTRY(SC_T), + MY_SC_ENTRY(SC_U), + MY_SC_ENTRY(SC_V), + MY_SC_ENTRY(SC_W), + MY_SC_ENTRY(SC_X), + MY_SC_ENTRY(SC_Y), + MY_SC_ENTRY(SC_Z), + MY_SC_ENTRY(SC_MINUS), + MY_SC_ENTRY(SC_EQUALS), + MY_SC_ENTRY(SC_LEFTBRACKET), + MY_SC_ENTRY(SC_RIGHTBRACKET), + MY_SC_ENTRY(SC_BACKSLASH), + MY_SC_ENTRY(SC_NONUSHASH), + MY_SC_ENTRY(SC_SEMICOLON), + MY_SC_ENTRY(SC_APOSTROPHE), + MY_SC_ENTRY(SC_GRAVE), // console key + MY_SC_ENTRY(SC_COMMA), + MY_SC_ENTRY(SC_PERIOD), + MY_SC_ENTRY(SC_SLASH), + MY_SC_ENTRY(SC_NONUSBACKSLASH), + MY_SC_ENTRY(SC_INTERNATIONAL1), + MY_SC_ENTRY(SC_INTERNATIONAL2), + MY_SC_ENTRY(SC_INTERNATIONAL3), + MY_SC_ENTRY(SC_INTERNATIONAL4), + MY_SC_ENTRY(SC_INTERNATIONAL5), + MY_SC_ENTRY(SC_INTERNATIONAL6), + MY_SC_ENTRY(SC_INTERNATIONAL7), + MY_SC_ENTRY(SC_INTERNATIONAL8), + MY_SC_ENTRY(SC_INTERNATIONAL9), + MY_SC_ENTRY(SC_THOUSANDSSEPARATOR), + MY_SC_ENTRY(SC_DECIMALSEPARATOR), + MY_SC_ENTRY(SC_CURRENCYUNIT), + MY_SC_ENTRY(SC_CURRENCYSUBUNIT), + +#undef MY_SC_ENTRY {NULL, 0} }; diff --git a/src/client/header/keyboard.h b/src/client/header/keyboard.h index d36ea804..95a766e4 100644 --- a/src/client/header/keyboard.h +++ b/src/client/header/keyboard.h @@ -222,6 +222,69 @@ enum QKEYS { K_MENU, K_UNDO, + // The following are mapped from SDL_Scancodes, used as a *fallback* for keys + // whose SDL_KeyCode we don't have a K_ constant for, like German Umlaut keys. + // The scancode name corresponds to the key at that position on US-QWERTY keyboards + // *not* the one in the local layout (e.g. German 'Ö' key is K_SC_SEMICOLON) + // !!! NOTE: if you add a scancode here, make sure to also add it to: + // 1. keynames[] in cl_keyboard.c + // 2. IN_TranslateScancodeToQ2Key() in input/sdl.c + K_SC_A, + K_SC_B, + K_SC_C, + K_SC_D, + K_SC_E, + K_SC_F, + K_SC_G, + K_SC_H, + K_SC_I, + K_SC_J, + K_SC_K, + K_SC_L, + K_SC_M, + K_SC_N, + K_SC_O, + K_SC_P, + K_SC_Q, + K_SC_R, + K_SC_S, + K_SC_T, + K_SC_U, + K_SC_V, + K_SC_W, + K_SC_X, + K_SC_Y, + K_SC_Z, + // leaving out SDL_SCANCODE_1 ... _0, we handle them separately already + // also return, escape, backspace, tab, space, already handled as keycodes + K_SC_MINUS, + K_SC_EQUALS, + K_SC_LEFTBRACKET, + K_SC_RIGHTBRACKET, + K_SC_BACKSLASH, + K_SC_NONUSHASH, + K_SC_SEMICOLON, + K_SC_APOSTROPHE, + K_SC_GRAVE, // console key + K_SC_COMMA, + K_SC_PERIOD, + K_SC_SLASH, + // leaving out lots of key incl. from keypad, we already handle them as normal keys + K_SC_NONUSBACKSLASH, + K_SC_INTERNATIONAL1, /**< used on Asian keyboards, see footnotes in USB doc */ + K_SC_INTERNATIONAL2, + K_SC_INTERNATIONAL3, /**< Yen */ + K_SC_INTERNATIONAL4, + K_SC_INTERNATIONAL5, + K_SC_INTERNATIONAL6, + K_SC_INTERNATIONAL7, + K_SC_INTERNATIONAL8, + K_SC_INTERNATIONAL9, + K_SC_THOUSANDSSEPARATOR, + K_SC_DECIMALSEPARATOR, + K_SC_CURRENCYUNIT, + K_SC_CURRENCYSUBUNIT, + K_LAST }; diff --git a/src/client/input/sdl.c b/src/client/input/sdl.c index b04cf54e..d750d197 100644 --- a/src/client/input/sdl.c +++ b/src/client/input/sdl.c @@ -369,6 +369,74 @@ IN_TranslateSDLtoQ2Key(unsigned int keysym) return key; } +static int +IN_TranslateScancodeToQ2Key(SDL_Scancode sc) +{ + +#define MY_SC_CASE(X) case SDL_SCANCODE_ ## X : return K_SC_ ## X; + + switch( (int)sc ) // cast to int to shut -Wswitch up + { + // case SDL_SCANCODE_A : return K_SC_A; + MY_SC_CASE(A) + MY_SC_CASE(B) + MY_SC_CASE(C) + MY_SC_CASE(D) + MY_SC_CASE(E) + MY_SC_CASE(F) + MY_SC_CASE(G) + MY_SC_CASE(H) + MY_SC_CASE(I) + MY_SC_CASE(J) + MY_SC_CASE(K) + MY_SC_CASE(L) + MY_SC_CASE(M) + MY_SC_CASE(N) + MY_SC_CASE(O) + MY_SC_CASE(P) + MY_SC_CASE(Q) + MY_SC_CASE(R) + MY_SC_CASE(S) + MY_SC_CASE(T) + MY_SC_CASE(U) + MY_SC_CASE(V) + MY_SC_CASE(W) + MY_SC_CASE(X) + MY_SC_CASE(Y) + MY_SC_CASE(Z) + MY_SC_CASE(MINUS) + MY_SC_CASE(EQUALS) + MY_SC_CASE(LEFTBRACKET) + MY_SC_CASE(RIGHTBRACKET) + MY_SC_CASE(BACKSLASH) + MY_SC_CASE(NONUSHASH) + MY_SC_CASE(SEMICOLON) + MY_SC_CASE(APOSTROPHE) + MY_SC_CASE(GRAVE) + MY_SC_CASE(COMMA) + MY_SC_CASE(PERIOD) + MY_SC_CASE(SLASH) + MY_SC_CASE(NONUSBACKSLASH) + MY_SC_CASE(INTERNATIONAL1) + MY_SC_CASE(INTERNATIONAL2) + MY_SC_CASE(INTERNATIONAL3) + MY_SC_CASE(INTERNATIONAL4) + MY_SC_CASE(INTERNATIONAL5) + MY_SC_CASE(INTERNATIONAL6) + MY_SC_CASE(INTERNATIONAL7) + MY_SC_CASE(INTERNATIONAL8) + MY_SC_CASE(INTERNATIONAL9) + MY_SC_CASE(THOUSANDSSEPARATOR) + MY_SC_CASE(DECIMALSEPARATOR) + MY_SC_CASE(CURRENCYUNIT) + MY_SC_CASE(CURRENCYSUBUNIT) + } + +#undef MY_SC_CASE + + return 0; +} + /* ------------------------------------------------------------------ */ /* @@ -466,13 +534,27 @@ IN_Update(void) } else { - if ((event.key.keysym.sym >= SDLK_SPACE) && (event.key.keysym.sym < SDLK_DELETE)) + SDL_Keycode kc = event.key.keysym.sym; + if ((kc >= SDLK_SPACE) && (kc < SDLK_DELETE)) { - Key_Event(event.key.keysym.sym, down, false); + Key_Event(kc, down, false); } else { - Key_Event(IN_TranslateSDLtoQ2Key(event.key.keysym.sym), down, true); + int key = IN_TranslateSDLtoQ2Key(kc); + if(key == 0) + { + // fallback to scancodes if we don't know the keycode + key = IN_TranslateScancodeToQ2Key(sc); + } + if(key != 0) + { + Key_Event(key, down, true); + } + else + { + Com_Printf("Pressed unknown key with SDL_Keycode %d, SDL_Scancode %d.\n", kc, (int)sc); + } } }