Support scancodes as fallback for unknown keyboard keys

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
This commit is contained in:
Daniel Gibson 2020-04-08 04:41:59 +02:00
parent 3015995d04
commit bbde4e2a81
3 changed files with 206 additions and 3 deletions

View file

@ -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}
};

View file

@ -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
};

View file

@ -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);
}
}
}