diff --git a/src/common/KeyIdentification.h b/src/common/KeyIdentification.h index e6b457ba31..3ce8f6b162 100644 --- a/src/common/KeyIdentification.h +++ b/src/common/KeyIdentification.h @@ -55,7 +55,6 @@ namespace Scancode { class Key { -public: public: enum class Kind { INVALID, // No key. diff --git a/src/engine/client/key_binding.cpp b/src/engine/client/key_binding.cpp index ecab744fb0..f1317125e6 100644 --- a/src/engine/client/key_binding.cpp +++ b/src/engine/client/key_binding.cpp @@ -274,16 +274,18 @@ void SetBinding(Key key, int team, std::string binding) bindingsModified = true; } -const std::vector& GetConsoleKeys() -{ - static std::vector consoleKeys; +static std::vector consoleKeys; +static std::string consoleKeysString; +void UpdateConsoleKeyCache() { // Only parse the variable when it changes Util::optional modifiedString = cl_consoleKeys.GetModifiedValue(); if ( modifiedString ) { const char* text_p = modifiedString.value().c_str(); consoleKeys.clear(); + consoleKeysString.clear(); + while ( true ) { const char* token = COM_Parse( &text_p ); @@ -294,13 +296,25 @@ const std::vector& GetConsoleKeys() Keyboard::Key k = Keyboard::StringToKey(token); if (k.IsBindable()) { consoleKeys.push_back(k); + consoleKeysString += KeyToStringUnprefixed( k ); } } } +} + +const std::vector& GetConsoleKeys() +{ + UpdateConsoleKeyCache(); return consoleKeys; } +const std::string& GetConsoleKeysString() { + UpdateConsoleKeyCache(); + + return consoleKeysString; +} + void SetConsoleKeys(const std::vector& keys) { std::string text; diff --git a/src/engine/client/key_identification.cpp b/src/engine/client/key_identification.cpp index 66c499d571..8a23cadb44 100644 --- a/src/engine/client/key_identification.cpp +++ b/src/engine/client/key_identification.cpp @@ -186,6 +186,32 @@ Key StringToKey(Str::StringRef str) return Key::NONE; } +std::string KeyToStringUnprefixed( Key key ) { + if ( key.kind() == Key::Kind::KEYNUM ) { + return KeynumToString( key.AsKeynum() ); + } + + if ( key.kind() == Key::Kind::UNICODE_CHAR ) { + return CharToString( key.AsCharacter() ); + } + + if ( key.kind() == Key::Kind::SCANCODE ) { + int sc = key.AsScancode(); + if ( char c = ScancodeToAscii( sc ) ) { + return CharToString( c ); + } + for ( auto& functionKey : leftRightFunctionKeys ) { + if ( sc == functionKey.scancode ) { + return functionKey.name; + } + } + // make a hex string + return Str::Format( "0x%02x", key.AsScancode() ); + } + + return ""; +} + std::string KeyToString(Key key) { if (key.kind() == Key::Kind::KEYNUM) { diff --git a/src/engine/client/key_identification.h b/src/engine/client/key_identification.h index 378f5b4d18..3f6e8006f7 100644 --- a/src/engine/client/key_identification.h +++ b/src/engine/client/key_identification.h @@ -39,6 +39,7 @@ namespace Keyboard { Key StringToKey(Str::StringRef name); std::string KeyToString(Key key); +std::string KeyToStringUnprefixed(Key key); // Returns the code point of a character typed by the given key, or 0 if none is found. int GetCharForScancode(int scancode); diff --git a/src/engine/client/keys.h b/src/engine/client/keys.h index b8467cb6da..52a2fcbba6 100644 --- a/src/engine/client/keys.h +++ b/src/engine/client/keys.h @@ -78,6 +78,7 @@ Util::optional GetBinding(Key key, BindTeam team, bool useDefault); // Get/set the keys which toggle (both open and close) the console. // The source of truth is cl_consoleKeys, but these provide an interface with Key objects. const std::vector& GetConsoleKeys(); +const std::string& GetConsoleKeysString(); void SetConsoleKeys(const std::vector& keys); // Gets all keys that, if pressed, would execute the given command, based on the current team. diff --git a/src/engine/framework/ConsoleField.cpp b/src/engine/framework/ConsoleField.cpp index b8d9cb7d12..743098cefb 100644 --- a/src/engine/framework/ConsoleField.cpp +++ b/src/engine/framework/ConsoleField.cpp @@ -92,7 +92,7 @@ namespace Console { Cmd::Args args(std::string(commandStart, commandEnd)); int argNum = args.Argc() - 1; std::string prefix; - if (!args.Argc() || Str::cisspace(GetText()[GetCursorPos() - 1])) { + if (!args.Argc() || !GetCursorPos() || Str::cisspace(GetText()[GetCursorPos() - 1])) { argNum++; } else { prefix = args.Argv(argNum); diff --git a/src/engine/sys/sdl_input.cpp b/src/engine/sys/sdl_input.cpp index fb9a0c851d..3c64d219ad 100644 --- a/src/engine/sys/sdl_input.cpp +++ b/src/engine/sys/sdl_input.cpp @@ -1113,6 +1113,24 @@ static void IN_ProcessEvents( bool dropInput ) { std::string text = e.text.text; + /* We can get a console key as a text event after we've opened the console from a key up/down event, + * in a separate execution of IN_ProcessEvents() + * The key character can also be anywhere in the text + * This might be an SDL bug */ + text.erase( + std::remove_if( text.begin(), text.end(), + []( unsigned char c ) { + for( const unsigned char key : Keyboard::GetConsoleKeysString() ) { + if ( c == key ) { + return true; + } + } + + return false; + } + ), text.end() + ); + const char* c = text.c_str(); while ( *c ) { int width = Q_UTF8_Width( c );