You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
12 KiB

#include "controls/game_controls.h"
#include <cstdint>
#include "controls/controller_motion.h"
#ifndef USE_SDL1
#include "controls/devices/game_controller.h"
#endif
#include "controls/devices/joystick.h"
#include "controls/plrctrls.h"
#include "controls/touch/gamepad.h"
#include "doom.h"
#include "gamemenu.h"
#include "gmenu.h"
#include "options.h"
#include "qol/stash.h"
#include "stores.h"
namespace devilution {
bool PadMenuNavigatorActive = false;
bool PadHotspellMenuActive = false;
ControllerButton SuppressedButton = ControllerButton_NONE;
namespace {
SDL_Keycode TranslateControllerButtonToGameMenuKey(ControllerButton controllerButton)
{
switch (TranslateTo(GamepadType, controllerButton)) {
case ControllerButton_BUTTON_A:
case ControllerButton_BUTTON_Y:
return SDLK_RETURN;
case ControllerButton_BUTTON_B:
case ControllerButton_BUTTON_BACK:
case ControllerButton_BUTTON_START:
return SDLK_ESCAPE;
case ControllerButton_BUTTON_LEFTSTICK:
return SDLK_TAB; // Map
default:
return SDLK_UNKNOWN;
}
}
SDL_Keycode TranslateControllerButtonToMenuKey(ControllerButton controllerButton)
{
switch (TranslateTo(GamepadType, controllerButton)) {
case ControllerButton_BUTTON_A:
return SDLK_SPACE;
case ControllerButton_BUTTON_B:
case ControllerButton_BUTTON_BACK:
case ControllerButton_BUTTON_START:
return SDLK_ESCAPE;
case ControllerButton_BUTTON_Y:
return SDLK_RETURN;
case ControllerButton_BUTTON_LEFTSTICK:
return SDLK_TAB; // Map
case ControllerButton_BUTTON_DPAD_LEFT:
return SDLK_LEFT;
case ControllerButton_BUTTON_DPAD_RIGHT:
return SDLK_RIGHT;
case ControllerButton_BUTTON_DPAD_UP:
return SDLK_UP;
case ControllerButton_BUTTON_DPAD_DOWN:
return SDLK_DOWN;
default:
return SDLK_UNKNOWN;
}
}
SDL_Keycode TranslateControllerButtonToQuestLogKey(ControllerButton controllerButton)
{
switch (TranslateTo(GamepadType, controllerButton)) {
case ControllerButton_BUTTON_A:
case ControllerButton_BUTTON_Y:
return SDLK_RETURN;
case ControllerButton_BUTTON_B:
return SDLK_SPACE;
case ControllerButton_BUTTON_LEFTSTICK:
return SDLK_TAB; // Map
default:
return SDLK_UNKNOWN;
}
}
SDL_Keycode TranslateControllerButtonToSpellbookKey(ControllerButton controllerButton)
{
switch (TranslateTo(GamepadType, controllerButton)) {
case ControllerButton_BUTTON_B:
return SDLK_SPACE;
case ControllerButton_BUTTON_Y:
return SDLK_RETURN;
case ControllerButton_BUTTON_LEFTSTICK:
return SDLK_TAB; // Map
case ControllerButton_BUTTON_DPAD_LEFT:
return SDLK_LEFT;
case ControllerButton_BUTTON_DPAD_RIGHT:
return SDLK_RIGHT;
case ControllerButton_BUTTON_DPAD_UP:
return SDLK_UP;
case ControllerButton_BUTTON_DPAD_DOWN:
return SDLK_DOWN;
default:
return SDLK_UNKNOWN;
}
}
bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrlEvent, GameAction *action)
{
const bool inGameMenu = InGameMenu();
#ifndef USE_SDL1
if (ControlMode == ControlTypes::VirtualGamepad) {
if (event.type == SDL_FINGERDOWN) {
if (VirtualGamepadState.menuPanel.charButton.isHeld && VirtualGamepadState.menuPanel.charButton.didStateChange) {
*action = GameAction(GameActionType_TOGGLE_CHARACTER_INFO);
return true;
}
if (VirtualGamepadState.menuPanel.questsButton.isHeld && VirtualGamepadState.menuPanel.questsButton.didStateChange) {
*action = GameAction(GameActionType_TOGGLE_QUEST_LOG);
return true;
}
if (VirtualGamepadState.menuPanel.inventoryButton.isHeld && VirtualGamepadState.menuPanel.inventoryButton.didStateChange) {
*action = GameAction(GameActionType_TOGGLE_INVENTORY);
return true;
}
if (VirtualGamepadState.menuPanel.mapButton.isHeld && VirtualGamepadState.menuPanel.mapButton.didStateChange) {
*action = GameActionSendKey { SDLK_TAB, false };
return true;
}
if (VirtualGamepadState.primaryActionButton.isHeld && VirtualGamepadState.primaryActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag) {
*action = GameAction(GameActionType_PRIMARY_ACTION);
if (ControllerActionHeld == GameActionType_NONE) {
ControllerActionHeld = GameActionType_PRIMARY_ACTION;
}
} else if (sgpCurrentMenu != nullptr || stextflag != TalkID::None || QuestLogIsOpen) {
*action = GameActionSendKey { SDLK_RETURN, false };
} else {
*action = GameActionSendKey { SDLK_SPACE, false };
}
return true;
}
if (VirtualGamepadState.secondaryActionButton.isHeld && VirtualGamepadState.secondaryActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag) {
*action = GameAction(GameActionType_SECONDARY_ACTION);
if (ControllerActionHeld == GameActionType_NONE)
ControllerActionHeld = GameActionType_SECONDARY_ACTION;
}
return true;
}
if (VirtualGamepadState.spellActionButton.isHeld && VirtualGamepadState.spellActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag) {
*action = GameAction(GameActionType_CAST_SPELL);
if (ControllerActionHeld == GameActionType_NONE)
ControllerActionHeld = GameActionType_CAST_SPELL;
}
return true;
}
if (VirtualGamepadState.cancelButton.isHeld && VirtualGamepadState.cancelButton.didStateChange) {
if (inGameMenu || DoomFlag || spselflag)
*action = GameActionSendKey { SDLK_ESCAPE, false };
else if (invflag)
*action = GameAction(GameActionType_TOGGLE_INVENTORY);
else if (sbookflag)
*action = GameAction(GameActionType_TOGGLE_SPELL_BOOK);
else if (QuestLogIsOpen)
*action = GameAction(GameActionType_TOGGLE_QUEST_LOG);
else if (chrflag)
*action = GameAction(GameActionType_TOGGLE_CHARACTER_INFO);
return true;
}
if (VirtualGamepadState.healthButton.isHeld && VirtualGamepadState.healthButton.didStateChange) {
if (!QuestLogIsOpen && !sbookflag && stextflag == TalkID::None)
*action = GameAction(GameActionType_USE_HEALTH_POTION);
return true;
}
if (VirtualGamepadState.manaButton.isHeld && VirtualGamepadState.manaButton.didStateChange) {
if (!QuestLogIsOpen && !sbookflag && stextflag == TalkID::None)
*action = GameAction(GameActionType_USE_MANA_POTION);
return true;
}
} else if (event.type == SDL_FINGERUP) {
if ((!VirtualGamepadState.primaryActionButton.isHeld && ControllerActionHeld == GameActionType_PRIMARY_ACTION)
|| (!VirtualGamepadState.secondaryActionButton.isHeld && ControllerActionHeld == GameActionType_SECONDARY_ACTION)
|| (!VirtualGamepadState.spellActionButton.isHeld && ControllerActionHeld == GameActionType_CAST_SPELL)) {
ControllerActionHeld = GameActionType_NONE;
LastMouseButtonAction = MouseActionType::None;
}
}
}
#endif
if (PadMenuNavigatorActive || PadHotspellMenuActive)
return false;
SDL_Keycode translation = SDLK_UNKNOWN;
if (gmenu_is_active() || stextflag != TalkID::None)
translation = TranslateControllerButtonToGameMenuKey(ctrlEvent.button);
else if (inGameMenu)
translation = TranslateControllerButtonToMenuKey(ctrlEvent.button);
else if (QuestLogIsOpen)
translation = TranslateControllerButtonToQuestLogKey(ctrlEvent.button);
else if (sbookflag)
translation = TranslateControllerButtonToSpellbookKey(ctrlEvent.button);
if (translation != SDLK_UNKNOWN) {
*action = GameActionSendKey { static_cast<uint32_t>(translation), ctrlEvent.up };
return true;
}
return false;
}
void PressControllerButton(ControllerButton button)
{
if (IsStashOpen) {
switch (button) {
case ControllerButton_BUTTON_BACK:
StartGoldWithdraw();
return;
case ControllerButton_BUTTON_LEFTSHOULDER:
Stash.PreviousPage();
return;
case ControllerButton_BUTTON_RIGHTSHOULDER:
Stash.NextPage();
return;
default:
break;
}
}
if (PadHotspellMenuActive) {
auto quickSpellAction = [](size_t slot) {
if (spselflag) {
SetSpeedSpell(slot);
return;
}
if (!*sgOptions.Gameplay.quickCast)
ToggleSpell(slot);
else
QuickCast(slot);
};
switch (button) {
case devilution::ControllerButton_BUTTON_A:
quickSpellAction(2);
return;
case devilution::ControllerButton_BUTTON_B:
quickSpellAction(3);
return;
case devilution::ControllerButton_BUTTON_X:
quickSpellAction(0);
return;
case devilution::ControllerButton_BUTTON_Y:
quickSpellAction(1);
return;
default:
break;
}
}
if (PadMenuNavigatorActive) {
switch (button) {
case devilution::ControllerButton_BUTTON_DPAD_UP:
PressEscKey();
LastMouseButtonAction = MouseActionType::None;
PadHotspellMenuActive = false;
PadMenuNavigatorActive = false;
gamemenu_on();
return;
case devilution::ControllerButton_BUTTON_DPAD_DOWN:
CycleAutomapType();
return;
case devilution::ControllerButton_BUTTON_DPAD_LEFT:
ProcessGameAction(GameAction { GameActionType_TOGGLE_CHARACTER_INFO });
return;
case devilution::ControllerButton_BUTTON_DPAD_RIGHT:
ProcessGameAction(GameAction { GameActionType_TOGGLE_INVENTORY });
return;
case devilution::ControllerButton_BUTTON_A:
ProcessGameAction(GameAction { GameActionType_TOGGLE_SPELL_BOOK });
return;
case devilution::ControllerButton_BUTTON_B:
return;
case devilution::ControllerButton_BUTTON_X:
ProcessGameAction(GameAction { GameActionType_TOGGLE_QUEST_LOG });
return;
case devilution::ControllerButton_BUTTON_Y:
#ifdef __3DS__
sgOptions.Graphics.zoom.SetValue(!*sgOptions.Graphics.zoom);
CalcViewportGeometry();
#endif
return;
default:
break;
}
}
sgOptions.Padmapper.ButtonPressed(button);
}
} // namespace
ControllerButton TranslateTo(GamepadLayout layout, ControllerButton button)
{
if (layout != GamepadLayout::Nintendo)
return button;
switch (button) {
case ControllerButton_BUTTON_A:
return ControllerButton_BUTTON_B;
case ControllerButton_BUTTON_B:
return ControllerButton_BUTTON_A;
case ControllerButton_BUTTON_X:
return ControllerButton_BUTTON_Y;
case ControllerButton_BUTTON_Y:
return ControllerButton_BUTTON_X;
default:
return button;
}
}
bool SkipsMovie(ControllerButtonEvent ctrlEvent)
{
return IsAnyOf(ctrlEvent.button,
ControllerButton_BUTTON_A,
ControllerButton_BUTTON_B,
ControllerButton_BUTTON_START,
ControllerButton_BUTTON_BACK);
}
bool IsSimulatedMouseClickBinding(ControllerButtonEvent ctrlEvent)
{
if (ctrlEvent.button == ControllerButton_NONE)
return false;
if (!ctrlEvent.up && ctrlEvent.button == SuppressedButton)
return false;
std::string_view actionName = sgOptions.Padmapper.ActionNameTriggeredByButtonEvent(ctrlEvent);
return IsAnyOf(actionName, "LeftMouseClick1", "LeftMouseClick2", "RightMouseClick1", "RightMouseClick2");
}
AxisDirection GetMoveDirection()
{
return GetLeftStickOrDpadDirection(true);
}
bool HandleControllerButtonEvent(const SDL_Event &event, const ControllerButtonEvent ctrlEvent, GameAction &action)
{
if (ctrlEvent.button == ControllerButton_IGNORE) {
return false;
}
struct ButtonReleaser {
~ButtonReleaser()
{
if (ctrlEvent.up)
sgOptions.Padmapper.ButtonReleased(ctrlEvent.button, false);
}
ControllerButtonEvent ctrlEvent;
};
const ButtonReleaser buttonReleaser { ctrlEvent };
bool isGamepadMotion = IsControllerMotion(event);
if (!isGamepadMotion) {
SimulateRightStickWithPadmapper(ctrlEvent);
}
DetectInputMethod(event, ctrlEvent);
if (isGamepadMotion) {
return true;
}
if (ctrlEvent.button != ControllerButton_NONE && ctrlEvent.button == SuppressedButton) {
if (!ctrlEvent.up)
return true;
SuppressedButton = ControllerButton_NONE;
}
if (ctrlEvent.up && sgOptions.Padmapper.ActionNameTriggeredByButtonEvent(ctrlEvent) != "") {
// Button press may have brought up a menu;
// don't confuse release of that button with intent to interact with the menu
sgOptions.Padmapper.ButtonReleased(ctrlEvent.button);
return true;
} else if (GetGameAction(event, ctrlEvent, &action)) {
ProcessGameAction(action);
return true;
} else if (ctrlEvent.button != ControllerButton_NONE) {
if (!ctrlEvent.up)
PressControllerButton(ctrlEvent.button);
return true;
}
return false;
}
} // namespace devilution