Browse Source

Controller mouse emulation fixes

1. Do not interrupt mouse mode on virtual clicks.
2. Handle virtual clicks directly instead of sending an SDL event.
3. Fix D-Pad mouse emulation state handling.
4. Hides the modifier hints during D-Pad mouse emulation.
pull/4373/head
Gleb Mazovetskiy 4 years ago committed by Anders Jenbo
parent
commit
4c2fa76e49
  1. 69
      Source/controls/controller_motion.cpp
  2. 3
      Source/controls/controller_motion.h
  3. 14
      Source/controls/game_controls.cpp
  4. 2
      Source/controls/game_controls.h
  5. 5
      Source/controls/modifier_hints.cpp
  6. 36
      Source/controls/plrctrls.cpp
  7. 5
      Source/controls/plrctrls.h
  8. 13
      Source/miniwin/misc_msg.cpp

69
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);
}

3
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;

14
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);

2
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;

5
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) {

36
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;
}

5
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;
/**

13
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<int16_t>(MousePosition.y) << 16) | static_cast<int16_t>(MousePosition.x);
} else {
ProcessGamepadEvents(action);
}

Loading…
Cancel
Save