From b344415329b05f68595321a1152d09773877f397 Mon Sep 17 00:00:00 2001 From: y5nw <37980625+y5nw@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:54:28 +0100 Subject: [PATCH] Implement secondary keybindings --- src/client/inputhandler.cpp | 25 +++++++++++++------------ src/client/inputhandler.h | 33 +++++++++++++++++++++++---------- src/client/keycode.cpp | 24 +++++++++++++++++++++--- src/client/keycode.h | 4 +++- src/gui/guiChatConsole.cpp | 2 +- src/gui/guiFormSpecMenu.cpp | 8 ++++---- src/gui/guiKeyChangeMenu.cpp | 3 ++- 7 files changed, 67 insertions(+), 32 deletions(-) diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp index 88969f008b1f4..832e1fab17606 100644 --- a/src/client/inputhandler.cpp +++ b/src/client/inputhandler.cpp @@ -14,7 +14,7 @@ void KeyCache::populate_nonchanging() { - key[KeyType::ESC] = EscapeKey; + key[KeyType::ESC] = std::vector{EscapeKey}; } void KeyCache::populate() @@ -77,8 +77,9 @@ void KeyCache::populate() if (handler) { // First clear all keys, then re-add the ones we listen for handler->dontListenForKeys(); - for (const KeyPress &k : key) { - handler->listenForKey(k); + for (const auto &keylist : key) { + for (const auto &kp: keylist) + handler->listenForKey(kp); } handler->listenForKey(EscapeKey); } @@ -112,7 +113,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event) // This is separate from other keyboard handling so that it also works in menus. if (event.EventType == EET_KEY_INPUT_EVENT) { const KeyPress keyCode(event.KeyInput); - if (keyCode == getKeySetting("keymap_fullscreen")) { + if (inKeySetting("keymap_fullscreen", keyCode)) { if (event.KeyInput.PressedDown && !fullscreen_is_down) { IrrlichtDevice *device = RenderingEngine::get_raw_device(); @@ -257,7 +258,7 @@ s32 RandomInputHandler::Rand(s32 min, s32 max) } struct RandomInputHandlerSimData { - std::string key; + GameKeyType key; float counter; int time_max; }; @@ -265,19 +266,19 @@ struct RandomInputHandlerSimData { void RandomInputHandler::step(float dtime) { static RandomInputHandlerSimData rnd_data[] = { - { "keymap_jump", 0.0f, 40 }, - { "keymap_aux1", 0.0f, 40 }, - { "keymap_forward", 0.0f, 40 }, - { "keymap_left", 0.0f, 40 }, - { "keymap_dig", 0.0f, 30 }, - { "keymap_place", 0.0f, 15 } + { KeyType::JUMP, 0.0f, 40 }, + { KeyType::AUX1, 0.0f, 40 }, + { KeyType::FORWARD, 0.0f, 40 }, + { KeyType::LEFT, 0.0f, 40 }, + { KeyType::DIG, 0.0f, 30 }, + { KeyType::PLACE, 0.0f, 15 } }; for (auto &i : rnd_data) { i.counter -= dtime; if (i.counter < 0.0) { i.counter = 0.1 * Rand(1, i.time_max); - keydown.toggle(getKeySetting(i.key.c_str())); + keydown[i.key] = !keydown[i.key]; } } { diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h index b34c22d7855a2..da2af6482f7e7 100644 --- a/src/client/inputhandler.h +++ b/src/client/inputhandler.h @@ -42,7 +42,7 @@ struct KeyCache // Keys that are not settings dependent void populate_nonchanging(); - KeyPress key[KeyType::INTERNAL_ENUM_COUNT]; + std::vector key[KeyType::INTERNAL_ENUM_COUNT]; InputHandler *handler; }; @@ -117,6 +117,14 @@ class KeyList : private std::list } bool operator[](const KeyPress &key) const { return find(key) != end(); } + + bool operator[](const std::vector &keylist) const + { + for (const auto &key: keylist) + if (find(key) != end()) + return true; + return false; + } }; class MyEventReceiver : public IEventReceiver @@ -126,23 +134,28 @@ class MyEventReceiver : public IEventReceiver virtual bool OnEvent(const SEvent &event); bool IsKeyDown(const KeyPress &keyCode) const { return keyIsDown[keyCode]; } + bool IsKeyDown(const std::vector &keyCode) const { return keyIsDown[keyCode]; } // Checks whether a key was down and resets the state - bool WasKeyDown(const KeyPress &keyCode) - { - bool b = keyWasDown[keyCode]; - if (b) - keyWasDown.unset(keyCode); + bool WasKeyDown(const std::vector &keylist) + { + bool b = false; + for (const auto &key: keylist) { + if (keyWasDown[key]) { + b = true; + keyWasDown.unset(key); + } + } return b; } // Checks whether a key was just pressed. State will be cleared // in the subsequent iteration of Game::processPlayerInteraction - bool WasKeyPressed(const KeyPress &keycode) const { return keyWasPressed[keycode]; } + bool WasKeyPressed(const std::vector &keycode) const { return keyWasPressed[keycode]; } // Checks whether a key was just released. State will be cleared // in the subsequent iteration of Game::processPlayerInteraction - bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; } + bool WasKeyReleased(const std::vector &keycode) const { return keyWasReleased[keycode]; } void listenForKey(const KeyPress &keyCode) { @@ -359,7 +372,7 @@ class RandomInputHandler final : public InputHandler return true; } - virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; } + virtual bool isKeyDown(GameKeyType k) { return keydown[k]; } virtual bool wasKeyDown(GameKeyType k) { return false; } virtual bool wasKeyPressed(GameKeyType k) { return false; } virtual bool wasKeyReleased(GameKeyType k) { return false; } @@ -376,7 +389,7 @@ class RandomInputHandler final : public InputHandler s32 Rand(s32 min, s32 max); private: - KeyList keydown; + std::bitset keydown; v2s32 mousepos; v2s32 mousespeed; float joystickSpeed; diff --git a/src/client/keycode.cpp b/src/client/keycode.cpp index 0a3b0db3f825f..dc3742a1f2be4 100644 --- a/src/client/keycode.cpp +++ b/src/client/keycode.cpp @@ -343,19 +343,37 @@ const KeyPress RMBKey("KEY_RBUTTON"); */ // A simple cache for quicker lookup -static std::unordered_map g_key_setting_cache; +static std::unordered_map> g_key_setting_cache; -const KeyPress &getKeySetting(const char *settingname) +const std::vector &getKeySetting(const std::string &settingname) { auto n = g_key_setting_cache.find(settingname); if (n != g_key_setting_cache.end()) return n->second; auto &ref = g_key_setting_cache[settingname]; - ref = g_settings->get(settingname).c_str(); + auto &settingvalue = g_settings->get(settingname); + + if (settingvalue == "|") { + // TODO: with SDL scancodes we should check that there is a key with "|" + ref.push_back("|"); + } else { + for (const auto &str: str_split(settingvalue, '|')) + if (KeyPress kp(str.c_str()); strlen(kp.sym()) > 0) + ref.push_back(kp); + } + return ref; } +bool inKeySetting(const std::string &settingname, const KeyPress &kp) +{ + for (const auto &key: getKeySetting(settingname)) + if (key == kp) + return true; + return false; +} + void clearKeyCache() { g_key_setting_cache.clear(); diff --git a/src/client/keycode.h b/src/client/keycode.h index 4c63be7fa0cb9..c19a0027f981c 100644 --- a/src/client/keycode.h +++ b/src/client/keycode.h @@ -9,6 +9,7 @@ #include #include #include +#include class UnknownKeycode : public BaseException { @@ -57,7 +58,8 @@ extern const KeyPress MMBKey; // Middle Mouse Button extern const KeyPress RMBKey; // Key configuration getter -const KeyPress &getKeySetting(const char *settingname); +const std::vector &getKeySetting(const std::string &settingname); +bool inKeySetting(const std::string &settingname, const KeyPress &kp); // Clear fast lookup cache void clearKeyCache(); diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp index 689ad22e07d47..224f120102cff 100644 --- a/src/gui/guiChatConsole.cpp +++ b/src/gui/guiChatConsole.cpp @@ -415,7 +415,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event) } // Key input - if (KeyPress(event.KeyInput) == getKeySetting("keymap_console")) { + if (inKeySetting("keymap_console", event.KeyInput)) { closeConsole(); // inhibit open so the_game doesn't reopen immediately diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 8a69f0429e496..54c27eaa910d5 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -3953,7 +3953,7 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) if (event.EventType == EET_KEY_INPUT_EVENT) { KeyPress kp(event.KeyInput); if (kp == EscapeKey - || kp == getKeySetting("keymap_inventory") + || inKeySetting("keymap_inventory", kp) || event.KeyInput.Key==KEY_RETURN) { gui::IGUIElement *focused = Environment->getFocus(); if (focused && isMyChild(focused) && @@ -4020,17 +4020,17 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) KeyPress kp(event.KeyInput); if (event.KeyInput.PressedDown && ( (kp == EscapeKey) || - ((m_client != NULL) && (kp == getKeySetting("keymap_inventory"))))) { + ((m_client != NULL) && (inKeySetting("keymap_inventory", kp))))) { tryClose(); return true; } if (m_client != NULL && event.KeyInput.PressedDown && - (kp == getKeySetting("keymap_screenshot"))) { + (inKeySetting("keymap_screenshot", kp))) { m_client->makeScreenshot(); } - if (event.KeyInput.PressedDown && kp == getKeySetting("keymap_toggle_debug")) { + if (event.KeyInput.PressedDown && inKeySetting("keymap_toggle_debug", kp)) { if (!m_client || m_client->checkPrivilege("debug")) m_show_debug = !m_show_debug; } diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp index 6d3a0c53198f9..5a83c7e6d2148 100644 --- a/src/gui/guiKeyChangeMenu.cpp +++ b/src/gui/guiKeyChangeMenu.cpp @@ -359,7 +359,8 @@ void GUIKeyChangeMenu::add_key(int id, std::wstring button_name, const std::stri k->button_name = std::move(button_name); k->setting_name = setting_name; - k->key = getKeySetting(k->setting_name.c_str()); + if (const auto &keylist = getKeySetting(k->setting_name.c_str()); keylist.size() > 0) + k->key = keylist.front(); key_settings.push_back(k); }