Improve handling of "console key", add in_ignoreConsoleKey CVar

If in_ignoreConsoleKey is set, the console can only be opened with
Shift+Esc, not `/^/whatever, so you can easily type whatever character
is on your "console key" into the game, or even bind that key.
Otherwise, with SDL2, that key (KEY_SCANCODE_GRAVE) always generates the
newly added K_CONSOLE.
in_kbd has a new (SDL2-only) "auto" mode which tries to detect the
keyboard layout based on SDL_GetKeyFromScancode( SDL_SCANCODE_GRAVE ).
Wherever Sys_GetConsoleKey() is called, I now take the current state of
Shift into account, so we don't discard more chars than necessary, esp.
when they keyboard-layout (in_kbd) is *not* correctly set.

(TBH the only reason besides SDL1.2 to keep in_kbd around is to ignore
 the char generated by the "console key" in the console..)
This commit is contained in:
Daniel Gibson 2021-07-12 06:15:22 +02:00
parent 786e5a3694
commit 78ab625edd
4 changed files with 111 additions and 54 deletions

View file

@ -797,8 +797,9 @@ bool idConsoleLocal::ProcessEvent( const sysEvent_t *event, bool forceAccept ) {
bool consoleKey = false; bool consoleKey = false;
if(event->evType == SE_KEY) if(event->evType == SE_KEY)
{ {
if( event->evValue == Sys_GetConsoleKey( false ) || event->evValue == Sys_GetConsoleKey( true ) bool shiftPressed = idKeyInput::IsDown( K_SHIFT );
|| (event->evValue == K_ESCAPE && idKeyInput::IsDown( K_SHIFT )) ) // shift+esc should also open console if( event->evValue == K_CONSOLE || event->evValue == Sys_GetConsoleKey( shiftPressed )
|| (event->evValue == K_ESCAPE && shiftPressed) ) // shift+esc should also open console
{ {
consoleKey = true; consoleKey = true;
} }
@ -850,7 +851,7 @@ bool idConsoleLocal::ProcessEvent( const sysEvent_t *event, bool forceAccept ) {
// handle key and character events // handle key and character events
if ( event->evType == SE_CHAR ) { if ( event->evType == SE_CHAR ) {
// never send the console key as a character // never send the console key as a character
if ( event->evValue != Sys_GetConsoleKey( false ) && event->evValue != Sys_GetConsoleKey( true ) ) { if ( event->evValue != Sys_GetConsoleKey( idKeyInput::IsDown( K_SHIFT ) ) ) {
consoleField.CharEvent( event->evValue ); consoleField.CharEvent( event->evValue );
} }
return true; return true;

View file

@ -267,6 +267,7 @@ typedef enum {
K_LAST_SCANCODE = K_SC_CURRENCYSUBUNIT, // TODO: keep up to date! K_LAST_SCANCODE = K_SC_CURRENCYSUBUNIT, // TODO: keep up to date!
K_CONSOLE, // special keycode used for the "console key" and only to open/close the console (not bindable)
// FIXME: maybe move everything joystick related here // FIXME: maybe move everything joystick related here

View file

@ -60,10 +60,16 @@ If you have questions concerning this license or the applicable additional terms
#endif #endif
static const char *kbdNames[] = { static const char *kbdNames[] = {
#if SDL_VERSION_ATLEAST(2, 0, 0) // auto-detection is only available for SDL2
"auto",
#endif
"english", "french", "german", "italian", "spanish", "turkish", "norwegian", "brazilian", NULL "english", "french", "german", "italian", "spanish", "turkish", "norwegian", "brazilian", NULL
}; };
static idCVar in_kbd("in_kbd", "english", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", kbdNames, idCmdSystem::ArgCompletion_String<kbdNames> ); static idCVar in_kbd("in_kbd", kbdNames[0], CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", kbdNames, idCmdSystem::ArgCompletion_String<kbdNames> );
// TODO: I'd really like to make in_ignoreConsoleKey default to 1, but I guess there would be too much confusion :-/
static idCVar in_ignoreConsoleKey("in_ignoreConsoleKey", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL,
"Console only opens with Shift+Esc, not ` or ^ etc");
static idCVar in_grabKeyboard("in_grabKeyboard", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL, static idCVar in_grabKeyboard("in_grabKeyboard", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL,
"if enabled, grabs all keyboard input if mouse is grabbed (so keyboard shortcuts from the OS like Alt-Tab or Windows Key won't work)"); "if enabled, grabs all keyboard input if mouse is grabbed (so keyboard shortcuts from the OS like Alt-Tab or Windows Key won't work)");
@ -451,6 +457,7 @@ void Sys_InitInput() {
#endif #endif
in_kbd.SetModified(); in_kbd.SetModified();
Sys_GetConsoleKey(false); // initialize consoleKeymappingIdx from in_kbd
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
const char* grabKeyboardEnv = SDL_getenv(SDL_HINT_GRAB_KEYBOARD); const char* grabKeyboardEnv = SDL_getenv(SDL_HINT_GRAB_KEYBOARD);
if ( grabKeyboardEnv ) { if ( grabKeyboardEnv ) {
@ -485,46 +492,89 @@ void Sys_InitScanTable() {
} }
#endif #endif
struct ConsoleKeyMapping {
const char* langName;
unsigned char key;
unsigned char keyShifted;
};
static ConsoleKeyMapping consoleKeyMappings[] = {
#if SDL_VERSION_ATLEAST(2, 0, 0)
{ "auto", 0 , 0 }, // special case: set current keycode for SDL_SCANCODE_GRAVE (no shifted keycode, though)
#endif
{ "english", '`', '~' },
{ "french", '<', '>' },
{ "german", '^', 176 }, // °
{ "italian", '\\', '|' },
{ "spanish", 186, 170 }, // º ª
{ "turkish", '"', 233 }, // é
{ "norwegian", 124, 167 }, // | §
{ "brazilian", '\'', '"' },
};
static int consoleKeyMappingIdx = 0;
static void initConsoleKeyMapping() {
const int numMappings = sizeof(consoleKeyMappings)/sizeof(consoleKeyMappings[0]);
idStr lang = in_kbd.GetString();
consoleKeyMappingIdx = 0;
#if SDL_VERSION_ATLEAST(2, 0, 0)
consoleKeyMappings[0].key = 0;
if ( lang.Length() == 0 || lang.Icmp( "auto") == 0 ) {
// auto-detection (SDL2-only)
int keycode = SDL_GetKeyFromScancode( SDL_SCANCODE_GRAVE );
if ( keycode > 0 && keycode <= 0xFF ) {
// the SDL keycode and dhewm3 keycode should be identical for the mappings,
// as it's ISO-8859-1 ("High ASCII") chars
for( int i=1; i<numMappings; ++i ) {
if ( consoleKeyMappings[i].key == keycode ) {
consoleKeyMappingIdx = i;
common->Printf( "Detected keyboard layout as \"%s\"\n", consoleKeyMappings[i].langName );
break;
}
}
if ( consoleKeyMappingIdx == 0 ) { // not found in known mappings
consoleKeyMappings[0].key = keycode;
}
}
} else
#endif
{
for( int i=1; i<numMappings; ++i ) {
if( lang.Icmp( consoleKeyMappings[i].langName ) == 0 ) {
consoleKeyMappingIdx = i;
#if SDL_VERSION_ATLEAST(2, 0, 0)
int keycode = SDL_GetKeyFromScancode( SDL_SCANCODE_GRAVE );
if ( keycode && keycode != consoleKeyMappings[i].key ) {
common->Warning( "in_kbd is set to \"%s\", but the actual keycode of the 'console key' is %c (%d), not %c (%d), so this might not work that well..\n",
lang.c_str(), (unsigned char)keycode, keycode, consoleKeyMappings[i].key, consoleKeyMappings[i].key );
}
#endif
break;
}
}
}
}
/* /*
=============== ===============
Sys_GetConsoleKey Sys_GetConsoleKey
=============== ===============
*/ */
unsigned char Sys_GetConsoleKey(bool shifted) { unsigned char Sys_GetConsoleKey( bool shifted ) {
static unsigned char keys[2] = { '`', '~' };
if (in_kbd.IsModified()) { if ( in_ignoreConsoleKey.GetBool() ) {
idStr lang = in_kbd.GetString(); return 0;
}
if (lang.Length()) {
if (!lang.Icmp("french")) {
keys[0] = '<';
keys[1] = '>';
} else if (!lang.Icmp("german")) {
keys[0] = '^';
keys[1] = 176; // °
} else if (!lang.Icmp("italian")) {
keys[0] = '\\';
keys[1] = '|';
} else if (!lang.Icmp("spanish")) {
keys[0] = 186; // º
keys[1] = 170; // ª
} else if (!lang.Icmp("turkish")) {
keys[0] = '"';
keys[1] = 233; // é
} else if (!lang.Icmp("norwegian")) {
keys[0] = 124; // |
keys[1] = 167; // §
} else if (!lang.Icmp("brazilian")) {
keys[0] = '\'';
keys[1] = '"';
}
}
if ( in_kbd.IsModified() ) {
initConsoleKeyMapping();
in_kbd.ClearModified(); in_kbd.ClearModified();
} }
return shifted ? keys[1] : keys[0]; return shifted ? consoleKeyMappings[consoleKeyMappingIdx].keyShifted : consoleKeyMappings[consoleKeyMappingIdx].key;
} }
/* /*
@ -665,15 +715,17 @@ sysEvent_t Sys_GetEvent() {
#if !SDL_VERSION_ATLEAST(2, 0, 0) #if !SDL_VERSION_ATLEAST(2, 0, 0)
key = mapkey(ev.key.keysym.sym); key = mapkey(ev.key.keysym.sym);
if (!key) { if (!key) {
unsigned char c; if ( !in_ignoreConsoleKey.GetBool() ) {
// check if its an unmapped console key // check if its an unmapped console key
if (ev.key.keysym.unicode == (c = Sys_GetConsoleKey(false))) { int c = Sys_GetConsoleKey( (ev.key.keysym.mod & KMOD_SHIFT) != 0 );
key = c; if (ev.key.keysym.unicode == c) {
} else if (ev.key.keysym.unicode == (c = Sys_GetConsoleKey(true))) { key = c;
key = c; }
} else { }
if (!key) {
if (ev.type == SDL_KEYDOWN) if (ev.type == SDL_KEYDOWN)
common->Warning("unmapped SDL key %d (0x%x)", ev.key.keysym.sym, ev.key.keysym.unicode); common->Warning( "unmapped SDL key %d (0x%x) - if possible use SDL2 for better keyboard support",
ev.key.keysym.sym, ev.key.keysym.unicode );
continue; // handle next event continue; // handle next event
} }
} }
@ -699,18 +751,19 @@ sysEvent_t Sys_GetEvent() {
key = mapkey(ev.key.keysym.sym); key = mapkey(ev.key.keysym.sym);
} }
if(!key) { if ( !in_ignoreConsoleKey.GetBool() && ev.key.keysym.scancode == SDL_SCANCODE_GRAVE ) {
if (ev.key.keysym.scancode == SDL_SCANCODE_GRAVE) { // TODO: always do this check? // that key between Esc, Tab and 1 is the console key
key = Sys_GetConsoleKey(true); key = K_CONSOLE;
} else { }
// if the key couldn't be mapped so far, try to map the scancode to K_SC_*
key = getKeynumForSDLscancode(sc); if ( !key ) {
if(!key) { // if the key couldn't be mapped so far, try to map the scancode to K_SC_*
if (ev.type == SDL_KEYDOWN) { key = getKeynumForSDLscancode(sc);
common->Warning("unmapped SDL key %d (scancode %d)", ev.key.keysym.sym, (int)sc); if(!key) {
} if (ev.type == SDL_KEYDOWN) {
continue; // handle next event common->Warning("unmapped SDL key %d (scancode %d)", ev.key.keysym.sym, (int)sc);
} }
continue; // handle next event
} }
} }
} }
@ -738,6 +791,8 @@ sysEvent_t Sys_GetEvent() {
res.evType = SE_CHAR; res.evType = SE_CHAR;
res.evValue = ev.text.text[0]; res.evValue = ev.text.text[0];
// TODO: translate to "ISO-8859-1" with SDL_iconv() ?
if (ev.text.text[1] != '\0') if (ev.text.text[1] != '\0')
{ {
memcpy(s, ev.text.text, SDL_TEXTINPUTEVENT_TEXT_SIZE); memcpy(s, ev.text.text, SDL_TEXTINPUTEVENT_TEXT_SIZE);

View file

@ -210,7 +210,7 @@ const char *idEditWindow::HandleEvent(const sysEvent_t *event, bool *updateVisua
int len = text.Length(); int len = text.Length();
if ( event->evType == SE_CHAR ) { if ( event->evType == SE_CHAR ) {
if ( event->evValue == Sys_GetConsoleKey( false ) || event->evValue == Sys_GetConsoleKey( true ) ) { if ( event->evValue == Sys_GetConsoleKey( idKeyInput::IsDown( K_SHIFT ) ) ) {
return ""; return "";
} }