diff --git a/Source/controls/controller_motion.cpp b/Source/controls/controller_motion.cpp index 48c749832..81e43f98a 100644 --- a/Source/controls/controller_motion.cpp +++ b/Source/controls/controller_motion.cpp @@ -12,9 +12,12 @@ #include "controls/plrctrls.h" #include "controls/touch/gamepad.h" #include "options.h" +#include "utils/log.hpp" namespace devilution { +bool SimulatingMouseWithSelectAndDPad; + namespace { void ScaleJoystickAxes(float *x, float *y, float deadzone) @@ -63,38 +66,78 @@ void ScaleJoystickAxes(float *x, float *y, float deadzone) } } +void SetSimulatingMouseWithDpad(bool value) +{ + if (SimulatingMouseWithSelectAndDPad == value) + return; + SimulatingMouseWithSelectAndDPad = value; + if (value) { + LogDebug("Control: begin simulating mouse with D-Pad"); + } else { + LogDebug("Control: end simulating mouse with D-Pad"); + } +} + // SELECT + D-Pad to simulate right stick movement. bool SimulateRightStickWithDpad(ControllerButtonEvent ctrlEvent) { if (sgOptions.Controller.bDpadHotkeys) return false; - static bool simulating = false; + if (ctrlEvent.button == ControllerButton_NONE || ctrlEvent.button == ControllerButton_IGNORE) + return false; if (ctrlEvent.button == ControllerButton_BUTTON_BACK) { - if (ctrlEvent.up && simulating) { - rightStickX = rightStickY = 0; - simulating = false; + if (SimulatingMouseWithSelectAndDPad) { + if (ctrlEvent.up) { + rightStickX = rightStickY = 0; + } + return true; } return false; } - if (!IsControllerButtonPressed(ControllerButton_BUTTON_BACK)) + + if (!IsControllerButtonPressed(ControllerButton_BUTTON_BACK)) { + SetSimulatingMouseWithDpad(false); return false; + } switch (ctrlEvent.button) { case ControllerButton_BUTTON_DPAD_LEFT: - rightStickX = ctrlEvent.up ? 0.F : -1.F; + if (ctrlEvent.up) { + rightStickX = 0; + } else { + rightStickX = -1.F; + SetSimulatingMouseWithDpad(true); + } break; case ControllerButton_BUTTON_DPAD_RIGHT: - rightStickX = ctrlEvent.up ? 0.F : 1.F; + if (ctrlEvent.up) { + rightStickX = 0; + } else { + rightStickX = 1.F; + SetSimulatingMouseWithDpad(true); + } break; case ControllerButton_BUTTON_DPAD_UP: - rightStickY = ctrlEvent.up ? 0.F : 1.F; + if (ctrlEvent.up) { + rightStickY = 0; + } else { + rightStickY = 1.F; + SetSimulatingMouseWithDpad(true); + } break; case ControllerButton_BUTTON_DPAD_DOWN: - rightStickY = ctrlEvent.up ? 0.F : -1.F; + if (ctrlEvent.up) { + rightStickY = 0; + } else { + rightStickY = -1.F; + SetSimulatingMouseWithDpad(true); + } break; default: + if (!IsSimulatedMouseClickBinding(ctrlEvent)) { + SetSimulatingMouseWithDpad(false); + } return false; } - simulating = !(rightStickX == 0 && rightStickY == 0); return true; } @@ -136,17 +179,21 @@ bool ProcessControllerMotion(const SDL_Event &event, ControllerButtonEvent ctrlE GameController *const controller = GameController::Get(event); if (controller != nullptr && devilution::GameController::ProcessAxisMotion(event)) { ScaleJoysticks(); + SetSimulatingMouseWithDpad(false); return true; } #endif Joystick *const joystick = Joystick::Get(event); if (joystick != nullptr && devilution::Joystick::ProcessAxisMotion(event)) { ScaleJoysticks(); + SetSimulatingMouseWithDpad(false); return true; } #if HAS_KBCTRL == 1 - if (ProcessKbCtrlAxisMotion(event)) + if (ProcessKbCtrlAxisMotion(event)) { + SetSimulatingMouseWithDpad(false); return true; + } #endif return SimulateRightStickWithDpad(ctrlEvent); } diff --git a/Source/controls/controller_motion.h b/Source/controls/controller_motion.h index 46748a554..b0c8c4952 100644 --- a/Source/controls/controller_motion.h +++ b/Source/controls/controller_motion.h @@ -9,6 +9,9 @@ namespace devilution { +// Whether we're currently simulating the mouse with SELECT + D-Pad. +extern bool SimulatingMouseWithSelectAndDPad; + // Raw axis values. extern float leftStickXUnscaled, leftStickYUnscaled, rightStickXUnscaled, rightStickYUnscaled; diff --git a/Source/controls/game_controls.cpp b/Source/controls/game_controls.cpp index 1c3524bdf..1496a28ae 100644 --- a/Source/controls/game_controls.cpp +++ b/Source/controls/game_controls.cpp @@ -441,6 +441,20 @@ bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrlEvent, Game return false; } +bool IsSimulatedMouseClickBinding(ControllerButtonEvent ctrlEvent) +{ + switch (ctrlEvent.button) { + case ControllerButton_BUTTON_LEFTSTICK: + case ControllerButton_BUTTON_LEFTSHOULDER: + case ControllerButton_BUTTON_RIGHTSHOULDER: + return select_modifier_active; + case ControllerButton_BUTTON_RIGHTSTICK: + return true; + default: + return false; + } +} + AxisDirection GetMoveDirection() { return GetLeftStickOrDpadDirection(/*allowDpad=*/!sgOptions.Controller.bDpadHotkeys); diff --git a/Source/controls/game_controls.h b/Source/controls/game_controls.h index a3eefe7a1..1ac06a21f 100644 --- a/Source/controls/game_controls.h +++ b/Source/controls/game_controls.h @@ -71,6 +71,8 @@ struct GameAction { bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrlEvent, GameAction *action); +bool IsSimulatedMouseClickBinding(ControllerButtonEvent ctrlEvent); + AxisDirection GetMoveDirection(); extern bool start_modifier_active; diff --git a/Source/controls/modifier_hints.cpp b/Source/controls/modifier_hints.cpp index acf15e811..6924a5293 100644 --- a/Source/controls/modifier_hints.cpp +++ b/Source/controls/modifier_hints.cpp @@ -5,8 +5,9 @@ #include "DiabloUI/art_draw.h" #include "DiabloUI/ui_flags.hpp" #include "control.h" -#include "controls/controller.h" +#include "controls/controller_motion.h" #include "controls/game_controls.h" +#include "controls/plrctrls.h" #include "engine/load_cel.hpp" #include "engine/render/text_render.hpp" #include "options.h" @@ -155,7 +156,7 @@ void DrawStartModifierMenu(const Surface &out) void DrawSelectModifierMenu(const Surface &out) { - if (!select_modifier_active) + if (!select_modifier_active || SimulatingMouseWithSelectAndDPad) return; if (sgOptions.Controller.bDpadHotkeys) { diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 7ae7d507b..0ef88e273 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -1443,7 +1443,7 @@ struct RightStickAccumulator { float hiresDY; }; -bool IsStickMovmentSignificant() +bool IsStickMovementSignificant() { return leftStickX >= 0.5 || leftStickX <= -0.5 || leftStickY >= 0.5 || leftStickY <= -0.5 @@ -1466,14 +1466,16 @@ ControlTypes GetInputTypeFromEvent(const SDL_Event &event) return event.wheel.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse; if (IsAnyOf(event.type, SDL_FINGERDOWN, SDL_FINGERUP, SDL_FINGERMOTION)) return ControlTypes::VirtualGamepad; - if (event.type == SDL_CONTROLLERAXISMOTION && IsStickMovmentSignificant()) + if (event.type == SDL_CONTROLLERAXISMOTION + && (event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT + || IsStickMovementSignificant())) return ControlTypes::Gamepad; if (event.type >= SDL_CONTROLLERBUTTONDOWN && event.type <= SDL_CONTROLLERDEVICEREMAPPED) return ControlTypes::Gamepad; if (IsAnyOf(event.type, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED)) return ControlTypes::Gamepad; #endif - if (event.type == SDL_JOYAXISMOTION && IsStickMovmentSignificant()) + if (event.type == SDL_JOYAXISMOTION && IsStickMovementSignificant()) return ControlTypes::Gamepad; if (event.type >= SDL_JOYBALLMOTION && event.type <= SDL_JOYBUTTONUP) return ControlTypes::Gamepad; @@ -1500,15 +1502,9 @@ bool ContinueSimulatedMouseEvent(const SDL_Event &event, const ControllerButtonE return true; } - if (IsAnyOf(gamepadEvent.button, ControllerButton_BUTTON_RIGHTSTICK, ControllerButton_BUTTON_BACK)) { - return true; - } - - return false; + return SimulatingMouseWithSelectAndDPad || IsSimulatedMouseClickBinding(gamepadEvent); } -bool IsNextMouseButtonClickEventSimulated = false; - void LogControlDeviceAndModeChange(ControlTypes newControlDevice, ControlTypes newControlMode) { if (SDL_LOG_PRIORITY_DEBUG < SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION)) @@ -1525,11 +1521,6 @@ void LogControlDeviceAndModeChange(ControlTypes newControlDevice, ControlTypes n } // namespace -void NextMouseButtonClickEventIsSimulated() -{ - IsNextMouseButtonClickEventSimulated = true; -} - string_view ControlTypeToString(ControlTypes controlType) { switch (controlType) { @@ -1566,20 +1557,7 @@ void DetectInputMethod(const SDL_Event &event, const ControllerButtonEvent &game ControlTypes newControlDevice = inputType; ControlTypes newControlMode = inputType; - const bool isSimulatedMouseButtonEvent = IsNextMouseButtonClickEventSimulated - && (event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) - && ControlDevice != ControlTypes::KeyboardAndMouse; - if (isSimulatedMouseButtonEvent) { - IsNextMouseButtonClickEventSimulated = false; - - // `inputType` here will be `KeyboardAndMouse` because this is a (simulated) mouse event. - // Restore it to the original control device. - newControlDevice = ControlDevice; - } - - if (isSimulatedMouseButtonEvent) { - newControlMode = ControlTypes::KeyboardAndMouse; - } else if (ContinueSimulatedMouseEvent(event, gamepadEvent)) { + if (ContinueSimulatedMouseEvent(event, gamepadEvent)) { newControlMode = ControlMode; } diff --git a/Source/controls/plrctrls.h b/Source/controls/plrctrls.h index 3b257e478..b814cb571 100644 --- a/Source/controls/plrctrls.h +++ b/Source/controls/plrctrls.h @@ -24,11 +24,6 @@ enum class ControlTypes : uint8_t { string_view ControlTypeToString(ControlTypes controlType); -/** - * @brief Call this after sending a simulated mouse button click event. - */ -void NextMouseButtonClickEventIsSimulated(); - extern ControlTypes ControlMode; /** diff --git a/Source/miniwin/misc_msg.cpp b/Source/miniwin/misc_msg.cpp index 73f8e9b76..2f3db3bd1 100644 --- a/Source/miniwin/misc_msg.cpp +++ b/Source/miniwin/misc_msg.cpp @@ -394,13 +394,6 @@ void ProcessGamepadEvents(GameAction &action) sbookflag = !sbookflag; } break; - case GameActionType_SEND_MOUSE_CLICK: - Uint8 simulatedButton = action.send_mouse_click.button == GameActionSendMouseClick::LEFT ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT; - SDL_Event clickEvent; - SetMouseButtonEvent(clickEvent, action.send_mouse_click.up ? SDL_MOUSEBUTTONUP : SDL_MOUSEBUTTONDOWN, simulatedButton, MousePosition); - NextMouseButtonClickEventIsSimulated(); - SDL_PushEvent(&clickEvent); - break; } } @@ -483,6 +476,12 @@ bool FetchMessage_Real(tagMSG *lpMsg) } else if (action.type == GameActionType_SEND_KEY) { lpMsg->message = action.send_key.up ? DVL_WM_KEYUP : DVL_WM_KEYDOWN; lpMsg->wParam = action.send_key.vk_code; + } else if (action.type == GameActionType_SEND_MOUSE_CLICK) { + lpMsg->message = action.send_mouse_click.up + ? (action.send_mouse_click.button == GameActionSendMouseClick::LEFT ? DVL_WM_LBUTTONUP : DVL_WM_RBUTTONUP) + : (action.send_mouse_click.button == GameActionSendMouseClick::LEFT ? DVL_WM_LBUTTONDOWN : DVL_WM_RBUTTONDOWN); + lpMsg->wParam = 0; + lpMsg->lParam = (static_cast(MousePosition.y) << 16) | static_cast(MousePosition.x); } else { ProcessGamepadEvents(action); }