From 5986d3f1f39d8c8bdb83f6973202d6c2394f0bc0 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 13 Jan 2025 21:09:54 +0000 Subject: [PATCH 1/6] Options: Remove dependency on demomode --- Source/diablo.cpp | 14 ++++++++------ Source/gamemenu.cpp | 3 ++- Source/gmenu.cpp | 4 +++- Source/options.cpp | 7 ------- test/timedemo_test.cpp | 1 + 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 2b403b840a9..aca3828d0fa 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -495,7 +495,7 @@ void PressKey(SDL_Keycode vkey, uint16_t modState) if (vkey == SDLK_RETURN || vkey == SDLK_KP_ENTER) { if ((modState & KMOD_ALT) != 0) { options.Graphics.fullscreen.SetValue(!IsFullScreen()); - SaveOptions(); + if (!demo::IsRunning()) SaveOptions(); } else { TypeChatMessage(); } @@ -530,7 +530,7 @@ void PressKey(SDL_Keycode vkey, uint16_t modState) if (PauseMode == 2) { if ((vkey == SDLK_RETURN || vkey == SDLK_KP_ENTER) && (modState & KMOD_ALT) != 0) { options.Graphics.fullscreen.SetValue(!IsFullScreen()); - SaveOptions(); + if (!demo::IsRunning()) SaveOptions(); } return; } @@ -568,7 +568,7 @@ void PressKey(SDL_Keycode vkey, uint16_t modState) case SDLK_KP_ENTER: if ((modState & KMOD_ALT) != 0) { options.Graphics.fullscreen.SetValue(!IsFullScreen()); - SaveOptions(); + if (!demo::IsRunning()) SaveOptions(); } else if (ActiveStore != TalkID::None) { StoreEnter(); } else if (QuestLogIsOpen) { @@ -1234,7 +1234,7 @@ void DiabloSplash() play_movie("gendata\\diablo1.smk", true); if (*intro == StartUpIntro::Once) { intro.SetValue(StartUpIntro::Off); - SaveOptions(); + if (!demo::IsRunning()) SaveOptions(); } } @@ -2565,12 +2565,14 @@ int DiabloMain(int argc, char **argv) // Read settings including translation next. This will use the presence of fonts.mpq and look for assets in devilutionx.mpq LoadOptions(); + if (demo::IsRunning()) demo::OverrideOptions(); + // Then look for a voice pack file based on the selected translation LoadLanguageArchive(); ApplicationInit(); LuaInitialize(); - SaveOptions(); + if (!demo::IsRunning()) SaveOptions(); // Finally load game data LoadGameArchives(); @@ -2589,7 +2591,7 @@ int DiabloMain(int argc, char **argv) #ifdef __UWP__ onInitialized(); #endif - SaveOptions(); + if (!demo::IsRunning()) SaveOptions(); DiabloSplash(); mainmenu_loop(); diff --git a/Source/gamemenu.cpp b/Source/gamemenu.cpp index 23d05b430ae..6ad584a4c9a 100644 --- a/Source/gamemenu.cpp +++ b/Source/gamemenu.cpp @@ -8,6 +8,7 @@ #include "cursor.h" #include "diablo_msg.hpp" #include "engine/backbuffer_state.hpp" +#include "engine/demomode.h" #include "engine/events.hpp" #include "engine/sound.h" #include "engine/sound_defs.hpp" @@ -358,7 +359,7 @@ void gamemenu_save_game(bool /*bActivate*/) NewCursor(CURSOR_HAND); if (CornerStone.activated) { CornerstoneSave(); - SaveOptions(); + if (!demo::IsRunning()) SaveOptions(); } interface_msg_pump(); SetEventHandler(saveProc); diff --git a/Source/gmenu.cpp b/Source/gmenu.cpp index c5fb3b2d3fd..051d52852e5 100644 --- a/Source/gmenu.cpp +++ b/Source/gmenu.cpp @@ -14,6 +14,7 @@ #include "controls/axis_direction.h" #include "controls/controller_motion.h" #include "engine/clx_sprite.hpp" +#include "engine/demomode.h" #include "engine/load_cel.hpp" #include "engine/render/clx_render.hpp" #include "engine/render/primitive_render.hpp" @@ -232,8 +233,9 @@ void gmenu_set_items(TMenuItem *pItem, void (*gmFunc)()) // BUGFIX: OOB access when sgCurrentMenuIdx is 0; should be set to NULL instead. (fixed) sgpCurrItem = sgCurrentMenuIdx > 0 ? &sgpCurrentMenu[sgCurrentMenuIdx - 1] : nullptr; GmenuUpDown(true); - if (sgpCurrentMenu == nullptr) + if (sgpCurrentMenu == nullptr && !demo::IsRunning()) { SaveOptions(); + } } void gmenu_draw(const Surface &out) diff --git a/Source/options.cpp b/Source/options.cpp index fb2c1ab133e..b77a6bd8ca9 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -27,7 +27,6 @@ #include "controls/game_controls.h" #include "controls/plrctrls.h" #include "engine/assets.hpp" -#include "engine/demomode.h" #include "engine/sound_defs.hpp" #include "platform/locale.hpp" #include "quick_messages.hpp" @@ -193,16 +192,10 @@ void LoadOptions() #ifdef __vita__ options.Controller.bRearTouch = ini->getBool("Controller", "Enable Rear Touchpad", true); #endif - - if (demo::IsRunning()) - demo::OverrideOptions(); } void SaveOptions() { - if (demo::IsRunning()) - return; - Options &options = GetOptions(); for (OptionCategoryBase *pCategory : options.GetCategories()) { for (const OptionEntryBase *pEntry : pCategory->GetEntries()) { diff --git a/test/timedemo_test.cpp b/test/timedemo_test.cpp index d8c19de5183..6ebb3f4ffcd 100644 --- a/test/timedemo_test.cpp +++ b/test/timedemo_test.cpp @@ -50,6 +50,7 @@ void RunTimedemo(std::string timedemoFolderName) InitKeymapActions(); LoadOptions(); + demo::OverrideOptions(); LuaInitialize(); const int demoNumber = 0; From 533152e850f479859e28c6905969ab9bd573f831 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 13 Jan 2025 21:17:15 +0000 Subject: [PATCH 2/6] Options: Remove dependency on gbRunGame --- Source/controls/controller_motion.cpp | 3 ++- Source/controls/plrctrls.cpp | 2 +- Source/options.cpp | 3 --- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/controls/controller_motion.cpp b/Source/controls/controller_motion.cpp index 18020e05828..f26e64dca40 100644 --- a/Source/controls/controller_motion.cpp +++ b/Source/controls/controller_motion.cpp @@ -91,7 +91,8 @@ bool TriggersQuickSpellAction(ControllerButton button) bool IsPressedForMovement(ControllerButton button) { - return !PadMenuNavigatorActive + return gbRunGame + && !PadMenuNavigatorActive && IsControllerButtonPressed(button) && !IsMovementOverriddenByPadmapper(button) && !(SpellSelectFlag && TriggersQuickSpellAction(button)); diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index e8dd0c2da36..0edfdfbc0c2 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -1542,7 +1542,7 @@ float rightStickLastMove = 0; bool ContinueSimulatedMouseEvent(const SDL_Event &event, const ControllerButtonEvent &gamepadEvent) { - if (AutomapActive) + if (!gbRunGame || AutomapActive) return false; #if !defined(USE_SDL1) && !defined(JOY_AXIS_RIGHTX) && !defined(JOY_AXIS_RIGHTY) diff --git a/Source/options.cpp b/Source/options.cpp index b77a6bd8ca9..0de3edf3a77 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -1598,9 +1598,6 @@ bool PadmapperOptions::IsActive(std::string_view actionName) const std::string_view PadmapperOptions::ActionNameTriggeredByButtonEvent(ControllerButtonEvent ctrlEvent) const { - if (!gbRunGame) - return ""; - if (!ctrlEvent.up) { const Action *pressAction = FindAction(ctrlEvent.button); return pressAction != nullptr ? pressAction->key : ""; From 6dfa432a22e74559d9f89ea3ca234d8b9a28c65f Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 13 Jan 2025 22:02:38 +0000 Subject: [PATCH 3/6] Options: Extract padmapper handling from options Options now only contain the padmapper settings, not the padmapping handling code. --- Source/CMakeLists.txt | 9 +++ Source/controls/controller.h | 11 ---- Source/controls/controller_buttons.h | 11 ++++ Source/controls/controller_motion.cpp | 28 ++++----- Source/controls/game_controls.cpp | 37 +++++++++-- Source/controls/padmapper.cpp | 66 ++++++++++++++++++++ Source/controls/padmapper.hpp | 16 +++++ Source/engine/events.cpp | 3 +- Source/options.cpp | 88 +-------------------------- Source/options.h | 27 ++++---- 10 files changed, 164 insertions(+), 132 deletions(-) create mode 100644 Source/controls/padmapper.cpp create mode 100644 Source/controls/padmapper.hpp diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index f9d0ac17043..1a686e45507 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -219,6 +219,14 @@ target_link_dependencies(libdevilutionx_controller_buttons DevilutionX::SDL ) +add_devilutionx_object_library(libdevilutionx_padmapper + controls/padmapper.cpp +) +target_link_dependencies(libdevilutionx_padmapper PUBLIC + libdevilutionx_controller_buttons + libdevilutionx_options +) + add_devilutionx_object_library(libdevilutionx_crawl crawl.cpp ) @@ -662,6 +670,7 @@ target_link_dependencies(libdevilutionx PUBLIC libdevilutionx_mpq libdevilutionx_multiplayer libdevilutionx_options + libdevilutionx_padmapper libdevilutionx_parse_int libdevilutionx_pathfinding libdevilutionx_pkware_encrypt diff --git a/Source/controls/controller.h b/Source/controls/controller.h index bef3d210bfb..e8185d838a7 100644 --- a/Source/controls/controller.h +++ b/Source/controls/controller.h @@ -7,17 +7,6 @@ namespace devilution { -struct ControllerButtonEvent { - ControllerButtonEvent(ControllerButton button, bool up) - : button(button) - , up(up) - { - } - - ControllerButton button; - bool up; -}; - // Must be called exactly once at the start of each SDL input event. void UnlockControllerState(const SDL_Event &event); diff --git a/Source/controls/controller_buttons.h b/Source/controls/controller_buttons.h index bfe02a00330..b27894a8b28 100644 --- a/Source/controls/controller_buttons.h +++ b/Source/controls/controller_buttons.h @@ -55,6 +55,17 @@ struct ControllerButtonCombo { ControllerButton button; }; +struct ControllerButtonEvent { + ControllerButtonEvent(ControllerButton button, bool up) + : button(button) + , up(up) + { + } + + ControllerButton button; + bool up; +}; + inline bool IsDPadButton(ControllerButton button) { return button == ControllerButton_BUTTON_DPAD_UP diff --git a/Source/controls/controller_motion.cpp b/Source/controls/controller_motion.cpp index f26e64dca40..3ef886fd5b5 100644 --- a/Source/controls/controller_motion.cpp +++ b/Source/controls/controller_motion.cpp @@ -9,6 +9,7 @@ #endif #include "controls/devices/joystick.h" #include "controls/game_controls.h" +#include "controls/padmapper.hpp" #include "controls/plrctrls.h" #include "controls/touch/gamepad.h" #include "engine/demomode.h" @@ -71,16 +72,15 @@ void ScaleJoystickAxes(float *x, float *y, float deadzone) bool IsMovementOverriddenByPadmapper(ControllerButton button) { ControllerButtonEvent releaseEvent { button, true }; - const Options &options = GetOptions(); - std::string_view actionName = options.Padmapper.ActionNameTriggeredByButtonEvent(releaseEvent); - ControllerButtonCombo buttonCombo = options.Padmapper.ButtonComboForAction(actionName); + std::string_view actionName = PadmapperActionNameTriggeredByButtonEvent(releaseEvent); + ControllerButtonCombo buttonCombo = GetOptions().Padmapper.ButtonComboForAction(actionName); return buttonCombo.modifier != ControllerButton_NONE; } bool TriggersQuickSpellAction(ControllerButton button) { ControllerButtonEvent releaseEvent { button, true }; - std::string_view actionName = GetOptions().Padmapper.ActionNameTriggeredByButtonEvent(releaseEvent); + std::string_view actionName = PadmapperActionNameTriggeredByButtonEvent(releaseEvent); std::string_view prefix { "QuickSpell" }; if (actionName.size() < prefix.size()) @@ -211,12 +211,11 @@ AxisDirection GetLeftStickOrDpadDirection(bool usePadmapper) bool isLeftPressed = stickX <= -0.5; bool isRightPressed = stickX >= 0.5; - const Options &options = GetOptions(); if (usePadmapper) { - isUpPressed |= options.Padmapper.IsActive("MoveUp"); - isDownPressed |= options.Padmapper.IsActive("MoveDown"); - isLeftPressed |= options.Padmapper.IsActive("MoveLeft"); - isRightPressed |= options.Padmapper.IsActive("MoveRight"); + isUpPressed |= PadmapperIsActionActive("MoveUp"); + isDownPressed |= PadmapperIsActionActive("MoveDown"); + isLeftPressed |= PadmapperIsActionActive("MoveLeft"); + isRightPressed |= PadmapperIsActionActive("MoveRight"); } else if (!SimulatingMouseWithPadmapper) { isUpPressed |= IsPressedForMovement(ControllerButton_BUTTON_DPAD_UP); isDownPressed |= IsPressedForMovement(ControllerButton_BUTTON_DPAD_DOWN); @@ -255,8 +254,7 @@ void SimulateRightStickWithPadmapper(ControllerButtonEvent ctrlEvent) if (!ctrlEvent.up && ctrlEvent.button == SuppressedButton) return; - const Options &options = GetOptions(); - std::string_view actionName = options.Padmapper.ActionNameTriggeredByButtonEvent(ctrlEvent); + std::string_view actionName = PadmapperActionNameTriggeredByButtonEvent(ctrlEvent); bool upTriggered = actionName == "MouseUp"; bool downTriggered = actionName == "MouseDown"; bool leftTriggered = actionName == "MouseLeft"; @@ -267,10 +265,10 @@ void SimulateRightStickWithPadmapper(ControllerButtonEvent ctrlEvent) return; } - bool upActive = (upTriggered && !ctrlEvent.up) || (!upTriggered && options.Padmapper.IsActive("MouseUp")); - bool downActive = (downTriggered && !ctrlEvent.up) || (!downTriggered && options.Padmapper.IsActive("MouseDown")); - bool leftActive = (leftTriggered && !ctrlEvent.up) || (!leftTriggered && options.Padmapper.IsActive("MouseLeft")); - bool rightActive = (rightTriggered && !ctrlEvent.up) || (!rightTriggered && options.Padmapper.IsActive("MouseRight")); + bool upActive = (upTriggered && !ctrlEvent.up) || (!upTriggered && PadmapperIsActionActive("MouseUp")); + bool downActive = (downTriggered && !ctrlEvent.up) || (!downTriggered && PadmapperIsActionActive("MouseDown")); + bool leftActive = (leftTriggered && !ctrlEvent.up) || (!leftTriggered && PadmapperIsActionActive("MouseLeft")); + bool rightActive = (rightTriggered && !ctrlEvent.up) || (!rightTriggered && PadmapperIsActionActive("MouseRight")); rightStickX = 0; rightStickY = 0; diff --git a/Source/controls/game_controls.cpp b/Source/controls/game_controls.cpp index 32d13e410be..21fafcde80f 100644 --- a/Source/controls/game_controls.cpp +++ b/Source/controls/game_controls.cpp @@ -7,6 +7,7 @@ #include "controls/devices/game_controller.h" #endif #include "controls/devices/joystick.h" +#include "controls/padmapper.hpp" #include "controls/plrctrls.h" #include "controls/touch/gamepad.h" #include "doom.h" @@ -214,6 +215,28 @@ bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrlEvent, Game return false; } +bool CanDeferToMovementHandler(const PadmapperOptions::Action &action) +{ + if (action.boundInput.modifier != ControllerButton_NONE) + return false; + + if (SpellSelectFlag) { + const std::string_view prefix { "QuickSpell" }; + const std::string_view key { action.key }; + if (key.size() >= prefix.size()) { + const std::string_view truncated { key.data(), prefix.size() }; + if (truncated == prefix) + return false; + } + } + + return IsAnyOf(action.boundInput.button, + ControllerButton_BUTTON_DPAD_UP, + ControllerButton_BUTTON_DPAD_DOWN, + ControllerButton_BUTTON_DPAD_LEFT, + ControllerButton_BUTTON_DPAD_RIGHT); +} + void PressControllerButton(ControllerButton button) { if (IsStashOpen) { @@ -298,7 +321,10 @@ void PressControllerButton(ControllerButton button) } } - GetOptions().Padmapper.ButtonPressed(button); + const PadmapperOptions::Action *action = GetOptions().Padmapper.findAction(button, IsControllerButtonPressed); + if (action == nullptr) return; + if (IsMovementHandlerActive() && CanDeferToMovementHandler(*action)) return; + PadmapperPress(button, *action); } } // namespace @@ -337,7 +363,7 @@ bool IsSimulatedMouseClickBinding(ControllerButtonEvent ctrlEvent) return false; if (!ctrlEvent.up && ctrlEvent.button == SuppressedButton) return false; - std::string_view actionName = GetOptions().Padmapper.ActionNameTriggeredByButtonEvent(ctrlEvent); + const std::string_view actionName = PadmapperActionNameTriggeredByButtonEvent(ctrlEvent); return IsAnyOf(actionName, "LeftMouseClick1", "LeftMouseClick2", "RightMouseClick1", "RightMouseClick2"); } @@ -355,8 +381,7 @@ bool HandleControllerButtonEvent(const SDL_Event &event, const ControllerButtonE struct ButtonReleaser { ~ButtonReleaser() { - if (ctrlEvent.up) - GetOptions().Padmapper.ButtonReleased(ctrlEvent.button, false); + if (ctrlEvent.up) PadmapperRelease(ctrlEvent.button, /*invokeAction=*/false); } ControllerButtonEvent ctrlEvent; }; @@ -377,10 +402,10 @@ bool HandleControllerButtonEvent(const SDL_Event &event, const ControllerButtonE SuppressedButton = ControllerButton_NONE; } - if (ctrlEvent.up && GetOptions().Padmapper.ActionNameTriggeredByButtonEvent(ctrlEvent) != "") { + if (ctrlEvent.up && !PadmapperActionNameTriggeredByButtonEvent(ctrlEvent).empty()) { // Button press may have brought up a menu; // don't confuse release of that button with intent to interact with the menu - GetOptions().Padmapper.ButtonReleased(ctrlEvent.button); + PadmapperRelease(ctrlEvent.button, /*invokeAction=*/true); return true; } else if (GetGameAction(event, ctrlEvent, &action)) { ProcessGameAction(action); diff --git a/Source/controls/padmapper.cpp b/Source/controls/padmapper.cpp new file mode 100644 index 00000000000..3250d3185ab --- /dev/null +++ b/Source/controls/padmapper.cpp @@ -0,0 +1,66 @@ +#include "controls/padmapper.hpp" + +#include + +#include "options.h" + +namespace devilution { + +namespace { +std::array::value> ButtonToReleaseAction; +} // namespace + +void PadmapperPress(ControllerButton button, const PadmapperOptions::Action &action) +{ + if (action.actionPressed) action.actionPressed(); + SuppressedButton = action.boundInput.modifier; + ButtonToReleaseAction[static_cast(button)] = &action; +} + +void PadmapperRelease(ControllerButton button, bool invokeAction) +{ + if (invokeAction) { + const PadmapperOptions::Action *action = ButtonToReleaseAction[static_cast(button)]; + if (action == nullptr) + return; // Ignore unmapped buttons. + + // Check that the action can be triggered. + if (action->actionReleased && action->isEnabled()) + action->actionReleased(); + } + ButtonToReleaseAction[static_cast(button)] = nullptr; +} + +bool PadmapperIsActionActive(std::string_view actionName) +{ + for (const PadmapperOptions::Action &action : GetOptions().Padmapper.actions) { + if (action.key != actionName) + continue; + const PadmapperOptions::Action *releaseAction = ButtonToReleaseAction[static_cast(action.boundInput.button)]; + return releaseAction != nullptr && releaseAction->key == actionName; + } + return false; +} + +void PadmapperReleaseAllActiveButtons() +{ + for (const PadmapperOptions::Action *action : ButtonToReleaseAction) { + if (action != nullptr) { + PadmapperRelease(action->boundInput.button, /*invokeAction=*/true); + } + } +} + +std::string_view PadmapperActionNameTriggeredByButtonEvent(ControllerButtonEvent ctrlEvent) +{ + if (!ctrlEvent.up) { + const PadmapperOptions::Action *pressAction = GetOptions().Padmapper.findAction(ctrlEvent.button, IsControllerButtonPressed); + if (pressAction == nullptr) return {}; + return pressAction->key; + } + const PadmapperOptions::Action *releaseAction = ButtonToReleaseAction[static_cast(ctrlEvent.button)]; + if (releaseAction == nullptr) return {}; + return releaseAction->key; +} + +} // namespace devilution diff --git a/Source/controls/padmapper.hpp b/Source/controls/padmapper.hpp new file mode 100644 index 00000000000..563321cb494 --- /dev/null +++ b/Source/controls/padmapper.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "controls/controller_buttons.h" +#include "options.h" + +namespace devilution { + +void PadmapperPress(ControllerButton button, const PadmapperOptions::Action &action); +void PadmapperRelease(ControllerButton button, bool invokeAction); +void PadmapperReleaseAllActiveButtons(); +[[nodiscard]] bool PadmapperIsActionActive(std::string_view actionName); +[[nodiscard]] std::string_view PadmapperActionNameTriggeredByButtonEvent(ControllerButtonEvent ctrlEvent); + +} // namespace devilution diff --git a/Source/engine/events.cpp b/Source/engine/events.cpp index 7652dd668a1..d4492bac9e4 100644 --- a/Source/engine/events.cpp +++ b/Source/engine/events.cpp @@ -3,6 +3,7 @@ #include #include "controls/input.h" +#include "controls/padmapper.hpp" #include "engine/demomode.h" #include "engine/render/primitive_render.hpp" #include "interfac.h" @@ -143,7 +144,7 @@ EventHandler CurrentEventHandler; EventHandler SetEventHandler(EventHandler eventHandler) { - GetOptions().Padmapper.ReleaseAllActiveButtons(); + PadmapperReleaseAllActiveButtons(); EventHandler previousHandler = CurrentEventHandler; CurrentEventHandler = eventHandler; diff --git a/Source/options.cpp b/Source/options.cpp index 0de3edf3a77..3fbade61da4 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -1387,9 +1387,9 @@ std::vector PadmapperOptions::GetEntries() PadmapperOptions::Action::Action(std::string_view key, const char *name, const char *description, ControllerButtonCombo defaultInput, std::function actionPressed, std::function actionReleased, std::function enable, unsigned index) : OptionEntryBase(key, OptionEntryFlags::None, name, description) - , defaultInput(defaultInput) , actionPressed(std::move(actionPressed)) , actionReleased(std::move(actionReleased)) + , defaultInput(defaultInput) , enable(std::move(enable)) , dynamicIndex(index) { @@ -1548,66 +1548,6 @@ void PadmapperOptions::CommitActions() committed = true; } -void PadmapperOptions::ButtonPressed(ControllerButton button) -{ - const Action *action = FindAction(button); - if (action == nullptr) - return; - if (IsMovementHandlerActive() && CanDeferToMovementHandler(*action)) - return; - if (action->actionPressed) - action->actionPressed(); - SuppressedButton = action->boundInput.modifier; - buttonToReleaseAction[static_cast(button)] = action; -} - -void PadmapperOptions::ButtonReleased(ControllerButton button, bool invokeAction) -{ - if (invokeAction) { - const Action *action = buttonToReleaseAction[static_cast(button)]; - if (action == nullptr) - return; // Ignore unmapped buttons. - - // Check that the action can be triggered. - if (action->actionReleased && (!action->enable || action->enable())) - action->actionReleased(); - } - buttonToReleaseAction[static_cast(button)] = nullptr; -} - -void PadmapperOptions::ReleaseAllActiveButtons() -{ - for (auto *action : buttonToReleaseAction) { - if (action == nullptr) - continue; - ControllerButton button = action->boundInput.button; - ButtonReleased(button, true); - } -} - -bool PadmapperOptions::IsActive(std::string_view actionName) const -{ - for (const Action &action : actions) { - if (action.key != actionName) - continue; - const Action *releaseAction = buttonToReleaseAction[static_cast(action.boundInput.button)]; - return releaseAction != nullptr && releaseAction->key == actionName; - } - return false; -} - -std::string_view PadmapperOptions::ActionNameTriggeredByButtonEvent(ControllerButtonEvent ctrlEvent) const -{ - if (!ctrlEvent.up) { - const Action *pressAction = FindAction(ctrlEvent.button); - return pressAction != nullptr ? pressAction->key : ""; - } - const Action *releaseAction = buttonToReleaseAction[static_cast(ctrlEvent.button)]; - if (releaseAction == nullptr) - return ""; - return releaseAction->key; -} - std::string_view PadmapperOptions::InputNameForAction(std::string_view actionName, bool useShortName) const { for (const Action &action : actions) { @@ -1628,7 +1568,7 @@ ControllerButtonCombo PadmapperOptions::ButtonComboForAction(std::string_view ac return ControllerButton_NONE; } -const PadmapperOptions::Action *PadmapperOptions::FindAction(ControllerButton button) const +const PadmapperOptions::Action *PadmapperOptions::findAction(ControllerButton button, tl::function_ref isModifierPressed) const { // To give preference to button combinations, // first pass ignores mappings where no modifier is bound @@ -1638,7 +1578,7 @@ const PadmapperOptions::Action *PadmapperOptions::FindAction(ControllerButton bu continue; if (button != combo.button) continue; - if (!IsControllerButtonPressed(combo.modifier)) + if (!isModifierPressed(combo.modifier)) continue; if (action.enable && !action.enable()) continue; @@ -1659,28 +1599,6 @@ const PadmapperOptions::Action *PadmapperOptions::FindAction(ControllerButton bu return nullptr; } -bool PadmapperOptions::CanDeferToMovementHandler(const Action &action) const -{ - if (action.boundInput.modifier != ControllerButton_NONE) - return false; - - if (SpellSelectFlag) { - const std::string_view prefix { "QuickSpell" }; - const std::string_view key { action.key }; - if (key.size() >= prefix.size()) { - const std::string_view truncated { key.data(), prefix.size() }; - if (truncated == prefix) - return false; - } - } - - return IsAnyOf(action.boundInput.button, - ControllerButton_BUTTON_DPAD_UP, - ControllerButton_BUTTON_DPAD_DOWN, - ControllerButton_BUTTON_DPAD_LEFT, - ControllerButton_BUTTON_DPAD_RIGHT); -} - ModOptions::ModOptions() : OptionCategoryBase("Mods", N_("Mods"), N_("Mod Settings")) { diff --git a/Source/options.h b/Source/options.h index 4431c0730a3..5a29974ac5d 100644 --- a/Source/options.h +++ b/Source/options.h @@ -131,8 +131,10 @@ class OptionEntryBase { OptionEntryFlags flags; -protected: +public: std::string_view key; + +protected: const char *name; const char *description; void NotifyValueChanged(); @@ -763,12 +765,15 @@ struct PadmapperOptions : OptionCategoryBase { bool SetValue(ControllerButtonCombo value); - private: - ControllerButtonCombo defaultInput; + [[nodiscard]] bool isEnabled() const { return !enable || enable(); } + std::function actionPressed; std::function actionReleased; + ControllerButtonCombo boundInput; + + private: + ControllerButtonCombo defaultInput; std::function enable; - ControllerButtonCombo boundInput {}; mutable GamepadLayout boundInputDescriptionType = GamepadLayout::Generic; mutable std::string boundInputDescription; mutable std::string boundInputShortDescription; @@ -792,23 +797,17 @@ struct PadmapperOptions : OptionCategoryBase { std::function enable = nullptr, unsigned index = 0); void CommitActions(); - void ButtonPressed(ControllerButton button); - void ButtonReleased(ControllerButton button, bool invokeAction = true); - void ReleaseAllActiveButtons(); - bool IsActive(std::string_view actionName) const; - std::string_view ActionNameTriggeredByButtonEvent(ControllerButtonEvent ctrlEvent) const; std::string_view InputNameForAction(std::string_view actionName, bool useShortName = false) const; ControllerButtonCombo ButtonComboForAction(std::string_view actionName) const; -private: + [[nodiscard]] const Action *findAction(ControllerButton button, tl::function_ref isModifierPressed) const; + std::forward_list actions; - std::array::value> buttonToReleaseAction; + +private: std::array::value> buttonToButtonName; ankerl::unordered_dense::segmented_map buttonNameToButton; bool committed = false; - - const Action *FindAction(ControllerButton button) const; - bool CanDeferToMovementHandler(const Action &action) const; }; struct ModOptions : OptionCategoryBase { From 2e132cdfaf45880c231f3d461cd60e061761600a Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 13 Jan 2025 22:31:08 +0000 Subject: [PATCH 4/6] 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 1a686e45507..e995fc7a95d 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 00000000000..d5bd6e5c644 --- /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 00000000000..048f6a4fbc4 --- /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 aca3828d0fa..3d06e40d0b9 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 3fbade61da4..762b97d26d1 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 5a29974ac5d..56386f79bea 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; From 583b32d543aca82fe7f066d11dc8be49cdbb400a Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 13 Jan 2025 22:48:01 +0000 Subject: [PATCH 5/6] Extract current input mode into its own library Removes a transitive dependency on the entire plrctrl from options. --- Source/CMakeLists.txt | 9 ++++++++ Source/DiabloUI/diabloui.cpp | 1 + Source/DiabloUI/hero/selhero.cpp | 1 + Source/control.cpp | 1 + Source/controls/control_mode.cpp | 16 ++++++++++++++ Source/controls/control_mode.hpp | 30 ++++++++++++++++++++++++++ Source/controls/controller_buttons.cpp | 10 ++------- Source/controls/controller_buttons.h | 9 +++++++- Source/controls/controller_motion.cpp | 1 + Source/controls/game_controls.cpp | 1 + Source/controls/game_controls.h | 7 ------ Source/controls/menu_controls.cpp | 1 + Source/controls/plrctrls.cpp | 10 +-------- Source/controls/plrctrls.h | 22 ------------------- Source/cursor.cpp | 1 + Source/diablo.cpp | 1 + Source/engine/demomode.cpp | 1 + Source/engine/dx.cpp | 1 + Source/engine/render/scrollrt.cpp | 1 + Source/inv.cpp | 1 + Source/items.cpp | 5 +++-- Source/levels/trigs.cpp | 1 + Source/missiles.cpp | 1 + Source/movie.cpp | 1 + Source/options.cpp | 10 +++------ Source/panels/spell_list.cpp | 1 + Source/player.cpp | 1 + Source/stores.cpp | 1 + Source/track.cpp | 1 + 29 files changed, 91 insertions(+), 56 deletions(-) create mode 100644 Source/controls/control_mode.cpp create mode 100644 Source/controls/control_mode.hpp diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e995fc7a95d..719733c9bd4 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -220,6 +220,13 @@ target_link_dependencies(libdevilutionx_controller_buttons DevilutionX::SDL ) +add_devilutionx_object_library(libdevilutionx_control_mode + controls/control_mode.cpp +) +target_link_dependencies(libdevilutionx_control_mode PUBLIC + libdevilutionx_controller_buttons +) + add_devilutionx_object_library(libdevilutionx_padmapper controls/padmapper.cpp ) @@ -428,6 +435,7 @@ target_link_dependencies(libdevilutionx_options PUBLIC fmt::fmt tl libdevilutionx_controller_buttons + libdevilutionx_control_mode libdevilutionx_logged_fstream libdevilutionx_quick_messages libdevilutionx_strings @@ -654,6 +662,7 @@ target_link_dependencies(libdevilutionx PUBLIC libdevilutionx_codec libdevilutionx_config libdevilutionx_controller_buttons + libdevilutionx_control_mode libdevilutionx_crawl libdevilutionx_direction libdevilutionx_surface diff --git a/Source/DiabloUI/diabloui.cpp b/Source/DiabloUI/diabloui.cpp index c12c69a375d..3191f6b01ed 100644 --- a/Source/DiabloUI/diabloui.cpp +++ b/Source/DiabloUI/diabloui.cpp @@ -10,6 +10,7 @@ #include "DiabloUI/dialogs.h" #include "DiabloUI/scrollbar.h" #include "DiabloUI/text_input.hpp" +#include "controls/control_mode.hpp" #include "controls/controller.h" #include "controls/input.h" #include "controls/menu_controls.h" diff --git a/Source/DiabloUI/hero/selhero.cpp b/Source/DiabloUI/hero/selhero.cpp index b2c7be7af0e..456a9bb64d1 100644 --- a/Source/DiabloUI/hero/selhero.cpp +++ b/Source/DiabloUI/hero/selhero.cpp @@ -14,6 +14,7 @@ #include "DiabloUI/selok.h" #include "DiabloUI/selyesno.h" #include "control.h" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "engine/assets.hpp" #include "game_mode.hpp" diff --git a/Source/control.cpp b/Source/control.cpp index 429bdb63c91..d41ebaa3394 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -17,6 +17,7 @@ #include "DiabloUI/text_input.hpp" #include "automap.h" +#include "controls/control_mode.hpp" #include "controls/modifier_hints.h" #include "controls/plrctrls.h" #include "cursor.h" diff --git a/Source/controls/control_mode.cpp b/Source/controls/control_mode.cpp new file mode 100644 index 00000000000..a81220d8ea6 --- /dev/null +++ b/Source/controls/control_mode.cpp @@ -0,0 +1,16 @@ +#include "controls/control_mode.hpp" + +namespace devilution { + +ControlTypes ControlMode = ControlTypes::None; +ControlTypes ControlDevice = ControlTypes::None; + +GamepadLayout GamepadType = +#if defined(DEVILUTIONX_GAMEPAD_TYPE) + GamepadLayout:: + DEVILUTIONX_GAMEPAD_TYPE; +#else + GamepadLayout::Generic; +#endif + +} // namespace devilution diff --git a/Source/controls/control_mode.hpp b/Source/controls/control_mode.hpp new file mode 100644 index 00000000000..6363c5195c2 --- /dev/null +++ b/Source/controls/control_mode.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "controls/controller_buttons.h" + +namespace devilution { + +enum class ControlTypes : uint8_t { + None, + KeyboardAndMouse, + Gamepad, + VirtualGamepad, +}; + +extern ControlTypes ControlMode; + +/** + * @brief Controlling device type. + * + * While simulating a mouse, `ControlMode` is set to `KeyboardAndMouse`, + * even though a gamepad is used to control it. + * + * This value is always set to the actual active device type. + */ +extern ControlTypes ControlDevice; + +extern GamepadLayout GamepadType; + +} // namespace devilution diff --git a/Source/controls/controller_buttons.cpp b/Source/controls/controller_buttons.cpp index 20133aa7326..db9e2497724 100644 --- a/Source/controls/controller_buttons.cpp +++ b/Source/controls/controller_buttons.cpp @@ -1,7 +1,5 @@ #include "controller_buttons.h" -#include "controls/game_controls.h" - namespace devilution { namespace { namespace controller_button_icon { @@ -280,13 +278,9 @@ std::string_view ToXboxIcon(ControllerButton button) } // namespace -// Defined in `plrctrls.cpp`. -// Declared here to avoid having to depend on it in tests. -extern GamepadLayout GamepadType; - -std::string_view ToString(ControllerButton button) +std::string_view ToString(GamepadLayout gamepadType, ControllerButton button) { - switch (GamepadType) { + switch (gamepadType) { case GamepadLayout::PlayStation: return ToPlayStationIcon(button); case GamepadLayout::Nintendo: diff --git a/Source/controls/controller_buttons.h b/Source/controls/controller_buttons.h index b27894a8b28..c7526315408 100644 --- a/Source/controls/controller_buttons.h +++ b/Source/controls/controller_buttons.h @@ -74,6 +74,13 @@ inline bool IsDPadButton(ControllerButton button) || button == ControllerButton_BUTTON_DPAD_RIGHT; } -std::string_view ToString(ControllerButton button); +enum class GamepadLayout : uint8_t { + Generic, + Nintendo, + PlayStation, + Xbox, +}; + +[[nodiscard]] std::string_view ToString(GamepadLayout gamepadType, ControllerButton button); } // namespace devilution diff --git a/Source/controls/controller_motion.cpp b/Source/controls/controller_motion.cpp index 3ef886fd5b5..1175be85561 100644 --- a/Source/controls/controller_motion.cpp +++ b/Source/controls/controller_motion.cpp @@ -3,6 +3,7 @@ #include #include "control.h" +#include "controls/control_mode.hpp" #include "controls/controller.h" #ifndef USE_SDL1 #include "controls/devices/game_controller.h" diff --git a/Source/controls/game_controls.cpp b/Source/controls/game_controls.cpp index 21fafcde80f..2849a9d5179 100644 --- a/Source/controls/game_controls.cpp +++ b/Source/controls/game_controls.cpp @@ -2,6 +2,7 @@ #include +#include "controls/control_mode.hpp" #include "controls/controller_motion.h" #ifndef USE_SDL1 #include "controls/devices/game_controller.h" diff --git a/Source/controls/game_controls.h b/Source/controls/game_controls.h index 5288d5ca328..e8589e26b83 100644 --- a/Source/controls/game_controls.h +++ b/Source/controls/game_controls.h @@ -8,13 +8,6 @@ namespace devilution { -enum class GamepadLayout : uint8_t { - Generic, - Nintendo, - PlayStation, - Xbox, -}; - enum GameActionType : uint8_t { GameActionType_NONE, GameActionType_USE_HEALTH_POTION, diff --git a/Source/controls/menu_controls.cpp b/Source/controls/menu_controls.cpp index 732525e84f8..7153f16e209 100644 --- a/Source/controls/menu_controls.cpp +++ b/Source/controls/menu_controls.cpp @@ -2,6 +2,7 @@ #include "DiabloUI/diabloui.h" #include "controls/axis_direction.h" +#include "controls/control_mode.hpp" #include "controls/controller.h" #include "controls/controller_motion.h" #include "controls/plrctrls.h" diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 0edfdfbc0c2..8ce42dae390 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -15,6 +15,7 @@ #ifndef USE_SDL1 #include "controls/devices/game_controller.h" #endif +#include "controls/control_mode.hpp" #include "controls/game_controls.h" #include "controls/touch/gamepad.h" #include "cursor.h" @@ -44,16 +45,7 @@ namespace devilution { -ControlTypes ControlMode = ControlTypes::None; -ControlTypes ControlDevice = ControlTypes::None; GameActionType ControllerActionHeld = GameActionType_NONE; -GamepadLayout GamepadType = -#if defined(DEVILUTIONX_GAMEPAD_TYPE) - GamepadLayout:: - DEVILUTIONX_GAMEPAD_TYPE; -#else - GamepadLayout::Generic; -#endif bool StandToggle = false; diff --git a/Source/controls/plrctrls.h b/Source/controls/plrctrls.h index bc220c2e8bd..c02689c44a8 100644 --- a/Source/controls/plrctrls.h +++ b/Source/controls/plrctrls.h @@ -17,29 +17,7 @@ enum class BeltItemType : uint8_t { Mana, }; -enum class ControlTypes : uint8_t { - None, - KeyboardAndMouse, - Gamepad, - VirtualGamepad, -}; - -extern ControlTypes ControlMode; - -/** - * @brief Controlling device type. - * - * While simulating a mouse, `ControlMode` is set to `KeyboardAndMouse`, - * even though a gamepad is used to control it. - * - * This value is always set to the actual active device type. - */ -extern ControlTypes ControlDevice; - extern GameActionType ControllerActionHeld; - -extern GamepadLayout GamepadType; - extern bool StandToggle; // Runs every frame. diff --git a/Source/cursor.cpp b/Source/cursor.cpp index 5655896dfc8..a877e083ad9 100644 --- a/Source/cursor.cpp +++ b/Source/cursor.cpp @@ -15,6 +15,7 @@ #include "DiabloUI/diabloui.h" #include "control.h" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "doom.h" #include "engine/backbuffer_state.hpp" diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 3d06e40d0b9..48ff1d6b1dd 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -22,6 +22,7 @@ #include "debug.h" #endif #include "DiabloUI/diabloui.h" +#include "controls/control_mode.hpp" #include "controls/keymapper.hpp" #include "controls/plrctrls.h" #include "controls/remap_keyboard.h" diff --git a/Source/engine/demomode.cpp b/Source/engine/demomode.cpp index 31f085fadf6..21cb4de8bcb 100644 --- a/Source/engine/demomode.cpp +++ b/Source/engine/demomode.cpp @@ -11,6 +11,7 @@ #include "utils/sdl2_to_1_2_backports.h" #endif +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "engine/events.hpp" #include "gmenu.h" diff --git a/Source/engine/dx.cpp b/Source/engine/dx.cpp index e3cbe5e25a0..37bac7d06ad 100644 --- a/Source/engine/dx.cpp +++ b/Source/engine/dx.cpp @@ -8,6 +8,7 @@ #include #include +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "engine/render/primitive_render.hpp" #include "headless_mode.hpp" diff --git a/Source/engine/render/scrollrt.cpp b/Source/engine/render/scrollrt.cpp index 2f1d50e3d1c..d8f3bfcad41 100644 --- a/Source/engine/render/scrollrt.cpp +++ b/Source/engine/render/scrollrt.cpp @@ -13,6 +13,7 @@ #include "DiabloUI/ui_flags.hpp" #include "automap.h" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "cursor.h" #include "dead.h" diff --git a/Source/inv.cpp b/Source/inv.cpp index bb07acf8fe0..e64b8206650 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -12,6 +12,7 @@ #include #include "DiabloUI/ui_flags.hpp" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "cursor.h" #include "engine/backbuffer_state.hpp" diff --git a/Source/items.cpp b/Source/items.cpp index bb817163d8b..46f955cde4c 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -16,6 +16,7 @@ #include #include "DiabloUI/ui_flags.hpp" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "cursor.h" #include "doom.h" @@ -1800,8 +1801,8 @@ void printItemMiscGamepad(const Item &item, bool isOil, bool isCastOnTarget) printItemMiscGenericGamepad(item, isOil, isCastOnTarget); return; } - const std::string_view activateButton = ToString(ControllerButton_BUTTON_Y); - const std::string_view castButton = ToString(ControllerButton_BUTTON_X); + const std::string_view activateButton = ToString(GamepadType, ControllerButton_BUTTON_Y); + const std::string_view castButton = ToString(GamepadType, ControllerButton_BUTTON_X); if (item._iMiscId == IMISC_MAPOFDOOM) { AddInfoBoxString(fmt::format(fmt::runtime(_("{} to view")), activateButton)); diff --git a/Source/levels/trigs.cpp b/Source/levels/trigs.cpp index c51edec19a8..51235e42831 100644 --- a/Source/levels/trigs.cpp +++ b/Source/levels/trigs.cpp @@ -11,6 +11,7 @@ #include #include "control.h" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "cursor.h" #include "diablo_msg.hpp" diff --git a/Source/missiles.cpp b/Source/missiles.cpp index d693e7363c4..9b17f9ddbcb 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -10,6 +10,7 @@ #include #include "control.h" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "crawl.hpp" #include "cursor.h" diff --git a/Source/movie.cpp b/Source/movie.cpp index fa93e6c9d87..4cf094dcbe9 100644 --- a/Source/movie.cpp +++ b/Source/movie.cpp @@ -6,6 +6,7 @@ #include +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "diablo.h" #include "effects.h" diff --git a/Source/options.cpp b/Source/options.cpp index 762b97d26d1..0378f5567de 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -21,11 +21,8 @@ #include #include "appfat.h" -#include "control.h" -#include "controls/controller.h" +#include "controls/control_mode.hpp" #include "controls/controller_buttons.h" -#include "controls/game_controls.h" -#include "controls/plrctrls.h" #include "engine/assets.hpp" #include "engine/sound_defs.hpp" #include "platform/locale.hpp" @@ -33,7 +30,6 @@ #include "utils/algorithm/container.hpp" #include "utils/file_util.h" #include "utils/ini.hpp" -#include "utils/is_of.hpp" #include "utils/language.h" #include "utils/log.hpp" #include "utils/logged_fstream.hpp" @@ -1444,13 +1440,13 @@ void PadmapperOptions::Action::UpdateValueDescription() const boundInputShortDescription = ""; return; } - std::string_view buttonName = ToString(boundInput.button); + std::string_view buttonName = ToString(GamepadType, boundInput.button); if (boundInput.modifier == ControllerButton_NONE) { boundInputDescription = std::string(buttonName); boundInputShortDescription = std::string(Shorten(buttonName)); return; } - std::string_view modifierName = ToString(boundInput.modifier); + std::string_view modifierName = ToString(GamepadType, boundInput.modifier); boundInputDescription = StrCat(modifierName, "+", buttonName); boundInputShortDescription = StrCat(Shorten(modifierName), "+", Shorten(buttonName)); } diff --git a/Source/panels/spell_list.cpp b/Source/panels/spell_list.cpp index c29d5a804f7..217ca80899d 100644 --- a/Source/panels/spell_list.cpp +++ b/Source/panels/spell_list.cpp @@ -5,6 +5,7 @@ #include #include "control.h" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "engine/backbuffer_state.hpp" #include "engine/palette.h" diff --git a/Source/player.cpp b/Source/player.cpp index 871a3218127..d0b2edb93a7 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -10,6 +10,7 @@ #include #include "control.h" +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "cursor.h" #include "dead.h" diff --git a/Source/stores.cpp b/Source/stores.cpp index 24c922a8d5e..47341b9d16c 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -11,6 +11,7 @@ #include +#include "controls/control_mode.hpp" #include "controls/plrctrls.h" #include "cursor.h" #include "engine/backbuffer_state.hpp" diff --git a/Source/track.cpp b/Source/track.cpp index 9ec9fca6c0a..12fe591aacd 100644 --- a/Source/track.cpp +++ b/Source/track.cpp @@ -7,6 +7,7 @@ #include +#include "controls/control_mode.hpp" #include "controls/game_controls.h" #include "controls/plrctrls.h" #include "cursor.h" From 9e54c9064c5afd43bc54df09fc01e10d31e46575 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 13 Jan 2025 22:49:03 +0000 Subject: [PATCH 6/6] language_for_testing: Fix GetLocales namespace --- test/language_for_testing.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/language_for_testing.cpp b/test/language_for_testing.cpp index 292d04ce60b..b45b1c40902 100644 --- a/test/language_for_testing.cpp +++ b/test/language_for_testing.cpp @@ -8,4 +8,7 @@ void LanguageInitialize() { } std::string_view LanguageTranslate(const char *key) { return key; } std::string_view LanguagePluralTranslate(const char *singular, std::string_view plural, int count) { return count == 1 ? singular : plural; } std::string_view LanguageParticularTranslate(std::string_view context, std::string_view message) { return message; } + +namespace devilution { std::vector GetLocales() { return {}; } +} // namespace devilution