From acc335be17bc8536f1203e51f3e55a2ccc1dda15 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 13 Jan 2025 22:31:08 +0000 Subject: [PATCH] Options: Extract keymapper handling from options --- Source/CMakeLists.txt | 3 +- Source/controls/keymapper.cpp | 60 +++++++++++++++++++++++++++++++++++ Source/controls/keymapper.hpp | 16 ++++++++++ Source/diablo.cpp | 19 +++++------ Source/options.cpp | 50 +++-------------------------- Source/options.h | 14 ++++---- 6 files changed, 100 insertions(+), 62 deletions(-) create mode 100644 Source/controls/keymapper.cpp create mode 100644 Source/controls/keymapper.hpp diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1a686e455..e995fc7a9 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -38,11 +38,12 @@ set(libdevilutionx_SRCS track.cpp controls/axis_direction.cpp - controls/controller.cpp controls/controller_motion.cpp + controls/controller.cpp controls/devices/joystick.cpp controls/devices/kbcontroller.cpp controls/game_controls.cpp + controls/keymapper.cpp controls/menu_controls.cpp controls/modifier_hints.cpp controls/plrctrls.cpp diff --git a/Source/controls/keymapper.cpp b/Source/controls/keymapper.cpp new file mode 100644 index 000000000..d5bd6e5c6 --- /dev/null +++ b/Source/controls/keymapper.cpp @@ -0,0 +1,60 @@ +#include "controls/keymapper.hpp" + +#include + +#ifdef USE_SDL1 +#include "utils/sdl2_to_1_2_backports.h" +#endif + +#include "control.h" +#include "options.h" +#include "utils/is_of.hpp" + +namespace devilution { +namespace { + +bool IsTextEntryKey(SDL_Keycode vkey) +{ + return IsAnyOf(vkey, SDLK_ESCAPE, SDLK_RETURN, SDLK_KP_ENTER, SDLK_BACKSPACE, SDLK_DOWN, SDLK_UP) || (vkey >= SDLK_SPACE && vkey <= SDLK_z); +} + +bool IsNumberEntryKey(SDL_Keycode vkey) +{ + return ((vkey >= SDLK_0 && vkey <= SDLK_9) || vkey == SDLK_BACKSPACE); +} + +SDL_Keycode ToAsciiUpper(SDL_Keycode key) +{ + if (key >= SDLK_a && key <= SDLK_z) { + return static_cast(static_cast(key) - ('a' - 'A')); + } + return key; +} + +} // namespace + +void KeymapperPress(SDL_Keycode key) +{ + key = ToAsciiUpper(key); + const KeymapperOptions::Action *action = GetOptions().Keymapper.findAction(static_cast(key)); + if (action == nullptr || !action->actionPressed || !action->isEnabled()) return; + + // TODO: This should be handled outside of the keymapper. + if (ChatFlag) return; + + action->actionPressed(); +} + +void KeymapperRelease(SDL_Keycode key) +{ + key = ToAsciiUpper(key); + const KeymapperOptions::Action *action = GetOptions().Keymapper.findAction(static_cast(key)); + if (action == nullptr || !action->actionReleased || !action->isEnabled()) return; + + // TODO: This should be handled outside of the keymapper. + if ((ChatFlag && IsTextEntryKey(key)) || (DropGoldFlag && IsNumberEntryKey(key))) return; + + action->actionReleased(); +} + +} // namespace devilution diff --git a/Source/controls/keymapper.hpp b/Source/controls/keymapper.hpp new file mode 100644 index 000000000..048f6a4fb --- /dev/null +++ b/Source/controls/keymapper.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include + +#ifdef USE_SDL1 +#include "utils/sdl2_to_1_2_backports.h" +#endif + +namespace devilution { + +void KeymapperPress(SDL_Keycode key); +void KeymapperRelease(SDL_Keycode key); + +} // namespace devilution diff --git a/Source/diablo.cpp b/Source/diablo.cpp index aca3828d0..3d06e40d0 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -22,6 +22,7 @@ #include "debug.h" #endif #include "DiabloUI/diabloui.h" +#include "controls/keymapper.hpp" #include "controls/plrctrls.h" #include "controls/remap_keyboard.h" #include "diablo.h" @@ -457,7 +458,7 @@ void ReleaseKey(SDL_Keycode vkey) remap_keyboard_key(&vkey); if (sgnTimeoutCurs != CURSOR_NONE) return; - GetOptions().Keymapper.KeyReleased(vkey); + KeymapperRelease(vkey); } void ClosePanels() @@ -491,7 +492,7 @@ void PressKey(SDL_Keycode vkey, uint16_t modState) if (sgnTimeoutCurs != CURSOR_NONE) { return; } - options.Keymapper.KeyPressed(vkey); + KeymapperPress(vkey); if (vkey == SDLK_RETURN || vkey == SDLK_KP_ENTER) { if ((modState & KMOD_ALT) != 0) { options.Graphics.fullscreen.SetValue(!IsFullScreen()); @@ -525,7 +526,7 @@ void PressKey(SDL_Keycode vkey, uint16_t modState) return; } - options.Keymapper.KeyPressed(vkey); + KeymapperPress(vkey); if (PauseMode == 2) { if ((vkey == SDLK_RETURN || vkey == SDLK_KP_ENTER) && (modState & KMOD_ALT) != 0) { @@ -656,7 +657,7 @@ void HandleMouseButtonDown(Uint8 button, uint16_t modState) RightMouseDown((modState & KMOD_SHIFT) != 0); break; default: - GetOptions().Keymapper.KeyPressed(button | KeymapperMouseButtonMask); + KeymapperPress(static_cast(button | KeymapperMouseButtonMask)); break; } } @@ -672,7 +673,7 @@ void HandleMouseButtonUp(Uint8 button, uint16_t modState) LastMouseButtonAction = MouseActionType::None; sgbMouseDown = CLICK_NONE; } else { - GetOptions().Keymapper.KeyReleased(static_cast(button | KeymapperMouseButtonMask)); + KeymapperRelease(static_cast(button | KeymapperMouseButtonMask)); } } @@ -757,7 +758,7 @@ void GameEventHandler(const SDL_Event &event, uint16_t modState) } else if (IsStashOpen) { Stash.PreviousPage(); } else { - options.Keymapper.KeyPressed(MouseScrollUpButton); + KeymapperPress(MouseScrollUpButton); } } else if (event.wheel.y < 0) { // down if (ActiveStore != TalkID::None) { @@ -771,12 +772,12 @@ void GameEventHandler(const SDL_Event &event, uint16_t modState) } else if (IsStashOpen) { Stash.NextPage(); } else { - options.Keymapper.KeyPressed(MouseScrollDownButton); + KeymapperPress(MouseScrollDownButton); } } else if (event.wheel.x > 0) { // left - options.Keymapper.KeyPressed(MouseScrollLeftButton); + KeymapperPress(MouseScrollLeftButton); } else if (event.wheel.x < 0) { // right - options.Keymapper.KeyPressed(MouseScrollRightButton); + KeymapperPress(MouseScrollRightButton); } break; #endif diff --git a/Source/options.cpp b/Source/options.cpp index 45aa0bfc0..13e6a1c06 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -1167,9 +1167,9 @@ std::vector KeymapperOptions::GetEntries() KeymapperOptions::Action::Action(std::string_view key, const char *name, const char *description, uint32_t defaultKey, std::function actionPressed, std::function actionReleased, std::function enable, unsigned index) : OptionEntryBase(key, OptionEntryFlags::None, name, description) - , defaultKey(defaultKey) , actionPressed(std::move(actionPressed)) , actionReleased(std::move(actionReleased)) + , defaultKey(defaultKey) , enable(std::move(enable)) , dynamicIndex(index) { @@ -1278,53 +1278,11 @@ void KeymapperOptions::CommitActions() actions.reverse(); } -void KeymapperOptions::KeyPressed(uint32_t key) const +const KeymapperOptions::Action *KeymapperOptions::findAction(uint32_t key) const { - if (key >= SDLK_a && key <= SDLK_z) { - key -= 'a' - 'A'; - } - auto it = keyIDToAction.find(key); - if (it == keyIDToAction.end()) - return; // Ignore unmapped keys. - - const Action &action = it->second.get(); - - // Check that the action can be triggered and that the chat textbox is not - // open. - if (!action.actionPressed || (action.enable && !action.enable()) || ChatFlag) - return; - - action.actionPressed(); -} - -void KeymapperOptions::KeyReleased(SDL_Keycode key) const -{ - if (key >= SDLK_a && key <= SDLK_z) { - key = static_cast(static_cast(key) - ('a' - 'A')); - } - auto it = keyIDToAction.find(key); - if (it == keyIDToAction.end()) - return; // Ignore unmapped keys. - - const Action &action = it->second.get(); - - // Check that the action can be triggered and that the chat or gold textbox is not - // open. If either of those textboxes are open, only return if the key can be used for entry into the box - if (!action.actionReleased || (action.enable && !action.enable()) || ((ChatFlag && IsTextEntryKey(key)) || (DropGoldFlag && IsNumberEntryKey(key)))) - return; - - action.actionReleased(); -} - -bool KeymapperOptions::IsTextEntryKey(SDL_Keycode vkey) const -{ - return IsAnyOf(vkey, SDLK_ESCAPE, SDLK_RETURN, SDLK_KP_ENTER, SDLK_BACKSPACE, SDLK_DOWN, SDLK_UP) || (vkey >= SDLK_SPACE && vkey <= SDLK_z); -} - -bool KeymapperOptions::IsNumberEntryKey(SDL_Keycode vkey) const -{ - return ((vkey >= SDLK_0 && vkey <= SDLK_9) || vkey == SDLK_BACKSPACE); + if (it == keyIDToAction.end()) return nullptr; + return &it->second.get(); } std::string_view KeymapperOptions::KeyNameForAction(std::string_view actionName) const diff --git a/Source/options.h b/Source/options.h index fa0008898..98b672b02 100644 --- a/Source/options.h +++ b/Source/options.h @@ -700,10 +700,13 @@ struct KeymapperOptions : OptionCategoryBase { bool SetValue(int value); - private: - uint32_t defaultKey; + [[nodiscard]] bool isEnabled() const { return !enable || enable(); } + std::function actionPressed; std::function actionReleased; + + private: + uint32_t defaultKey; std::function enable; uint32_t boundKey = SDLK_UNKNOWN; unsigned dynamicIndex; @@ -723,10 +726,9 @@ struct KeymapperOptions : OptionCategoryBase { std::function enable = nullptr, unsigned index = 0); void CommitActions(); - void KeyPressed(uint32_t key) const; - void KeyReleased(SDL_Keycode key) const; - bool IsTextEntryKey(SDL_Keycode vkey) const; - bool IsNumberEntryKey(SDL_Keycode vkey) const; + + [[nodiscard]] const Action *findAction(uint32_t key) const; + std::string_view KeyNameForAction(std::string_view actionName) const; uint32_t KeyForAction(std::string_view actionName) const;