From c9e53001dc0dba6262ae3ba8182db7ad7903172b Mon Sep 17 00:00:00 2001 From: y5nw <37980625+y5nw@users.noreply.github.com> Date: Sat, 14 Dec 2024 00:15:03 +0100 Subject: [PATCH] Use std::variant for scancode to properly handle mouse keys --- irr/include/IrrlichtDevice.h | 27 +++++++++------------------ irr/src/CIrrDeviceSDL.cpp | 15 +++++++++++++-- irr/src/CIrrDeviceSDL.h | 4 ++-- src/client/keycode.cpp | 34 ++++++++++++++++++++++++++-------- src/client/keycode.h | 19 +++++++++---------- src/unittest/test_keycode.cpp | 7 ++++++- 6 files changed, 65 insertions(+), 41 deletions(-) diff --git a/irr/include/IrrlichtDevice.h b/irr/include/IrrlichtDevice.h index 095738ba3..8bccec6f1 100644 --- a/irr/include/IrrlichtDevice.h +++ b/irr/include/IrrlichtDevice.h @@ -16,6 +16,7 @@ #include "IrrCompileConfig.h" #include "position2d.h" #include "SColor.h" // video::ECOLOR_FORMAT +#include namespace irr { @@ -343,29 +344,19 @@ public: return video::isDriverSupported(driver); } - // This is a trivial (near-identity) mapping for converting between scancodes and keycodes for devices that do - // not implement this. - +#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) || USE_SDL2 //! Get the scancode of the corresponding keycode. - virtual u32 getScancodeFromKey(const Keycode &key) const - { - if (const auto *keycode = std::get_if(&key)) - // treat KEY_UNKNOWN and KEY_KEY_CODES_COUNT as the same and return 0. - return Keycode::isValid(*keycode) ? *keycode : 0; - const auto keychar = std::get(key); - return keychar == 0 ? 0 : KEY_KEY_CODES_COUNT + keychar; + virtual std::variant getScancodeFromKey(const Keycode &key) const { + if (auto pv = std::get_if(&key)) + return *pv; + return (u32)std::get(key); } //! Get the keycode of the corresponding scancode. - virtual Keycode getKeyFromScancode(const u32 scancode) const - { - Keycode key; - if (scancode < KEY_KEY_CODES_COUNT) - key.emplace((EKEY_CODE)scancode); - else - key.emplace(scancode - KEY_KEY_CODES_COUNT); - return key; + virtual Keycode getKeyFromScancode(const u32 scancode) const { + return Keycode(KEY_UNKNOWN, (wchar_t)scancode); } +#endif }; } // end namespace irr diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index ff5c5b965..543113a7c 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -18,6 +18,7 @@ #include "COSOperator.h" #include #include +#include #include "SIrrCreationParameters.h" #include @@ -27,6 +28,14 @@ #include "CSDLManager.h" +// Since SDL doesn't have mouse keys as keycodes we fall back to EKEY_CODE +static const std::unordered_set fake_keys = { + irr::KEY_LBUTTON, irr::KEY_MBUTTON, irr::KEY_RBUTTON, irr::KEY_XBUTTON1, irr::KEY_XBUTTON2 +}; +static inline bool is_fake_key(irr::EKEY_CODE key) { + return fake_keys.find(key) != fake_keys.end(); +} + static int SDLDeviceInstances = 0; namespace irr @@ -220,10 +229,12 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtK } } -u32 CIrrDeviceSDL::getScancodeFromKey(const Keycode &key) const +std::variant CIrrDeviceSDL::getScancodeFromKey(const Keycode &key) const { u32 keynum = 0; if (const auto *keycode = std::get_if(&key)) { + if (is_fake_key(*keycode)) + return *keycode; for (const auto &entry: KeyMap) { if (entry.second == *keycode) { keynum = entry.first; @@ -233,7 +244,7 @@ u32 CIrrDeviceSDL::getScancodeFromKey(const Keycode &key) const } else { keynum = std::get(key); } - return SDL_GetScancodeFromKey(keynum); + return (u32)SDL_GetScancodeFromKey(keynum); } Keycode CIrrDeviceSDL::getKeyFromScancode(const u32 scancode) const diff --git a/irr/src/CIrrDeviceSDL.h b/irr/src/CIrrDeviceSDL.h index 4a74693d1..3dcfac0b4 100644 --- a/irr/src/CIrrDeviceSDL.h +++ b/irr/src/CIrrDeviceSDL.h @@ -288,8 +288,8 @@ private: // Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0). static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock); - virtual u32 getScancodeFromKey(const Keycode &key) const override; - virtual Keycode getKeyFromScancode(const u32 scancode) const override; + std::variant getScancodeFromKey(const Keycode &key) const override; + Keycode getKeyFromScancode(const u32 scancode) const override; // Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus. void resetReceiveTextInputEvents(); diff --git a/src/client/keycode.cpp b/src/client/keycode.cpp index 76074aa75..10c1531ca 100644 --- a/src/client/keycode.cpp +++ b/src/client/keycode.cpp @@ -280,6 +280,13 @@ static const table_key &lookup_scancode(const u32 scancode) lookup_keykey(std::get(key)) : lookup_keychar(std::get(key)); } + +static const table_key &lookup_scancode(const std::variant &scancode) +{ + return std::holds_alternative(scancode) ? + lookup_keykey(std::get(scancode)) : + lookup_scancode(std::get(scancode)); +} #endif KeyPress::KeyPress(std::string_view name) @@ -297,18 +304,30 @@ KeyPress::KeyPress(std::string_view name) #endif } -KeyPress::KeyPress(const irr::SEvent::SKeyInput &in) : +KeyPress::KeyPress(const irr::SEvent::SKeyInput &in) #if USE_SDL2 - scancode(in.SystemKeyCode) {} +{ + if (in.SystemKeyCode) + scancode.emplace(in.SystemKeyCode); + else + scancode.emplace(in.Key); +} #else - Key(in.Key), Char(in.Char ? in.Char : lookup_keykey(in.Key).Char) {} + : Key(in.Key), Char(in.Char ? in.Char : lookup_keykey(in.Key).Char) {} +#endif + +#if USE_SDL2 +std::string KeyPress::formatScancode() const +{ + if (auto pv = std::get_if(&scancode)) + return *pv == 0 ? "" : "<" + std::to_string(*pv) + ">"; + return lookup_keykey(std::get(scancode)).Name; +} #endif std::string KeyPress::sym(const bool force_scancode) const { #if USE_SDL2 - if (scancode == 0) - return ""; if (force_scancode) return formatScancode(); const auto &name = lookup_scancode(scancode).Name; @@ -327,8 +346,7 @@ std::string KeyPress::name() const { #if USE_SDL2 const auto &name = lookup_scancode(scancode).LangName; - auto table_key = lookup_scancode(scancode); - if (!name.empty() || scancode == 0) + if (!name.empty()) return name; return formatScancode(); #else @@ -363,7 +381,7 @@ bool KeyPress::loadFromScancode(std::string_view name) const auto code = strtoul(name.data()+1, &p, 10); if (p != name.data() + name.size() - 1) return false; - scancode = code; + scancode.emplace(code); return true; } #endif diff --git a/src/client/keycode.h b/src/client/keycode.h index 0fc636b45..d13544e8e 100644 --- a/src/client/keycode.h +++ b/src/client/keycode.h @@ -10,6 +10,7 @@ #include #include #include +#include /* A key press, consisting of a scancode or a keycode */ class KeyPress @@ -31,10 +32,10 @@ public: u32 getScancode() const { #if USE_SDL2 - return scancode; -#else - return 0; + if (auto pv = std::get_if(&scancode)) + return *pv; #endif + return 0; } irr::SEvent toKeyEvent(bool pressedDown = false) const @@ -57,7 +58,9 @@ public: operator bool() const { #if USE_SDL2 - return scancode != 0; + return std::holds_alternative(scancode) ? + Keycode::isValid(std::get(scancode)) : + std::get(scancode) != 0; #else return Char > 0 || Keycode::isValid(Key); #endif @@ -68,13 +71,9 @@ public: private: #if USE_SDL2 bool loadFromScancode(std::string_view name); + std::string formatScancode() const; - inline std::string formatScancode() const - { - return "<" + std::to_string(scancode) + ">"; - } - - u32 scancode = 0; + std::variant scancode = irr::KEY_UNKNOWN; #else irr::EKEY_CODE Key = irr::KEY_KEY_CODES_COUNT; wchar_t Char = L'\0'; diff --git a/src/unittest/test_keycode.cpp b/src/unittest/test_keycode.cpp index e2c7ddf6a..5f89f9cd5 100644 --- a/src/unittest/test_keycode.cpp +++ b/src/unittest/test_keycode.cpp @@ -80,7 +80,12 @@ void TestKeycode::testCreateFromString() template static u32 toScancode(Args... args) { - return RenderingEngine::get_raw_device()->getScancodeFromKey(Keycode(args...)); +#if USE_SDL2 + if (const auto &scancode = RenderingEngine::get_raw_device()->getScancodeFromKey(Keycode(args...)); + const auto &pv = std::get_if(&scancode)) + return *pv; +#endif + return 0; } void TestKeycode::testCreateFromSKeyInput()