Browse Source

Touch support on all SDL2 platforms

pull/3888/head
Anders Jenbo 4 years ago
parent
commit
6b2481a76c
  1. 2
      CMake/Assets.cmake
  2. 1
      CMake/Definitions.cmake
  3. 1
      CMake/platforms/android.cmake
  4. 1
      CMake/platforms/ios.cmake
  5. 1
      CMake/platforms/switch.cmake
  6. 4
      CMakeLists.txt
  7. 4
      Source/CMakeLists.txt
  8. 19
      Source/DiabloUI/diabloui.cpp
  9. 3
      Source/DiabloUI/selhero.cpp
  10. 66
      Source/control.cpp
  11. 1
      Source/control.h
  12. 2
      Source/controls/controller.cpp
  13. 15
      Source/controls/controller_motion.cpp
  14. 7
      Source/controls/devices/game_controller.cpp
  15. 3
      Source/controls/devices/game_controller.h
  16. 5
      Source/controls/devices/joystick.cpp
  17. 120
      Source/controls/game_controls.cpp
  18. 9
      Source/controls/menu_controls.cpp
  19. 177
      Source/controls/plrctrls.cpp
  20. 14
      Source/controls/plrctrls.h
  21. 11
      Source/controls/touch/event_handlers.cpp
  22. 4
      Source/controls/touch/event_handlers.h
  23. 4
      Source/controls/touch/gamepad.h
  24. 1
      Source/controls/touch/renderers.cpp
  25. 4
      Source/controls/touch/renderers.h
  26. 16
      Source/diablo.cpp
  27. 13
      Source/dx.cpp
  28. 2
      Source/inv.cpp
  29. 3
      Source/miniwin/miniwin.h
  30. 68
      Source/miniwin/misc_msg.cpp
  31. 13
      Source/missiles.cpp
  32. 221
      Source/platform/vita/touch.cpp
  33. 6
      Source/platform/vita/touch.h
  34. 5
      Source/player.cpp
  35. 9
      Source/scrollrt.cpp
  36. 5
      Source/scrollrt.h
  37. 3
      Source/trigs.cpp
  38. 10
      Source/utils/display.cpp

2
CMake/Assets.cmake

@ -145,7 +145,7 @@ set(devilutionx_assets
ui_art/mainmenuw.pcx
ui_art/supportw.pcx)
if(VIRTUAL_GAMEPAD)
if(NOT USE_SDL1 AND NOT VITA)
list(APPEND devilutionx_assets
ui_art/button.png
ui_art/directions2.png

1
CMake/Definitions.cmake

@ -14,7 +14,6 @@ foreach(
GPERF_HEAP_FIRST_GAME_ITERATION
STREAM_ALL_AUDIO
PACKET_ENCRYPTION
VIRTUAL_GAMEPAD
)
if(${def_name})
list(APPEND DEVILUTIONX_DEFINITIONS ${def_name})

1
CMake/platforms/android.cmake

@ -1,6 +1,5 @@
# General build options.
set(BUILD_TESTING OFF)
set(VIRTUAL_GAMEPAD ON)
# Disable all system dependencies.
# All of these will be fetched via FetchContent and linked statically.

1
CMake/platforms/ios.cmake

@ -1,6 +1,5 @@
# General build options.
set(BUILD_TESTING OFF)
set(VIRTUAL_GAMEPAD ON)
# Disable all system dependencies.
# All of these will be fetched via FetchContent and linked statically.

1
CMake/platforms/switch.cmake

@ -4,6 +4,7 @@ set(ASAN OFF)
set(UBSAN OFF)
set(BUILD_TESTING OFF)
set(DEVILUTIONX_SYSTEM_SDL_IMAGE OFF)
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
set(DISABLE_ZERO_TIER ON)
set(PREFILL_PLAYER_NAME ON)

4
CMakeLists.txt

@ -63,10 +63,6 @@ if(TSAN)
set(ASAN OFF)
endif()
if(USE_SDL1)
set(VIRTUAL_GAMEPAD OFF)
endif()
# By default, devilutionx.mpq is built only if smpq is installed.
if(NOT DEFINED BUILD_ASSETS_MPQ AND NOT SRC_DIST)
find_program(SMPQ smpq)

4
Source/CMakeLists.txt

@ -74,7 +74,6 @@ set(libdevilutionx_SRCS
controls/axis_direction.cpp
controls/controller.cpp
controls/controller_motion.cpp
controls/devices/game_controller.cpp
controls/devices/joystick.cpp
controls/devices/kbcontroller.cpp
controls/game_controls.cpp
@ -178,8 +177,9 @@ if(NOT NONET)
endif()
endif()
if(VIRTUAL_GAMEPAD)
if(NOT USE_SDL1)
list(APPEND libdevilutionx_SRCS
controls/devices/game_controller.cpp
controls/touch/event_handlers.cpp
controls/touch/gamepad.cpp
controls/touch/renderers.cpp)

19
Source/DiabloUI/diabloui.cpp

@ -15,6 +15,7 @@
#include "controls/controller.h"
#include "controls/input.h"
#include "controls/menu_controls.h"
#include "controls/plrctrls.h"
#include "discord/discord.h"
#include "dx.h"
#include "hwcursor.hpp"
@ -340,20 +341,6 @@ void UiFocusNavigation(SDL_Event *event)
break;
}
#ifndef USE_SDL1
// SDL generates mouse events from touch-based inputs to provide basic
// touchscreeen support for apps that don't explicitly handle touch events
sgbTouchActive = false;
if (IsAnyOf(event->type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP) && event->button.which == SDL_TOUCH_MOUSEID)
sgbTouchActive = true;
if (event->type == SDL_MOUSEMOTION && event->motion.which == SDL_TOUCH_MOUSEID)
sgbTouchActive = true;
if (event->type == SDL_MOUSEWHEEL && event->wheel.which == SDL_TOUCH_MOUSEID)
sgbTouchActive = true;
if (IsAnyOf(event->type, SDL_FINGERDOWN, SDL_FINGERUP, SDL_FINGERMOTION))
sgbTouchActive = true;
#endif
if (HandleMenuAction(GetMenuAction(*event)))
return;
@ -762,7 +749,7 @@ void UiPollAndRender(std::function<bool(SDL_Event &)> eventHandler)
// Must happen after the very first UiFadeIn, which sets the cursor.
if (IsHardwareCursor())
SetHardwareCursorVisible(!sgbControllerActive);
SetHardwareCursorVisible(ControlMode == ControlTypes::KeyboardAndMouse);
#ifdef __3DS__
// Keyboard blocks until input is finished
@ -1087,7 +1074,7 @@ bool UiItemMouseEvents(SDL_Event *event, const std::vector<std::unique_ptr<UiIte
void DrawMouse()
{
if (IsHardwareCursor() || sgbControllerActive || sgbTouchActive)
if (ControlMode != ControlTypes::KeyboardAndMouse || IsHardwareCursor())
return;
DrawArt(MousePosition, &ArtCursor);

3
Source/DiabloUI/selhero.cpp

@ -13,6 +13,7 @@
#include "DiabloUI/selok.h"
#include "DiabloUI/selyesno.h"
#include "control.h"
#include "controls/plrctrls.h"
#include "options.h"
#include "pfile.h"
#include "utils/language.h"
@ -217,7 +218,7 @@ bool ShouldPrefillHeroName()
#if defined(PREFILL_PLAYER_NAME)
return true;
#else
return sgbControllerActive;
return ControlMode != ControlTypes::KeyboardAndMouse;
#endif
}

66
Source/control.cpp

@ -14,6 +14,7 @@
#include "DiabloUI/art.h"
#include "DiabloUI/art_draw.h"
#include "automap.h"
#include "controls/plrctrls.h"
#include "cursor.h"
#include "engine/cel_sprite.hpp"
#include "engine/load_cel.hpp"
@ -47,6 +48,7 @@
#endif
namespace devilution {
/**
* @brief Set if the life flask needs to be redrawn during next frame
*/
@ -160,38 +162,6 @@ const char *const PanBtnStr[8] = {
"" // Player attack
};
void CalculatePanelAreas()
{
MainPanel = {
{ (gnScreenWidth - PANEL_WIDTH) / 2, gnScreenHeight - PANEL_HEIGHT },
{ PANEL_WIDTH, PANEL_HEIGHT }
};
LeftPanel = {
{ 0, 0 },
{ SPANEL_WIDTH, SPANEL_HEIGHT }
};
RightPanel = {
{ 0, 0 },
{ SPANEL_WIDTH, SPANEL_HEIGHT }
};
#ifdef VIRTUAL_GAMEPAD
LeftPanel.position.x = gnScreenWidth / 2 - LeftPanel.size.width;
#else
if (gnScreenWidth - LeftPanel.size.width - RightPanel.size.width > PANEL_WIDTH) {
LeftPanel.position.x = (gnScreenWidth - LeftPanel.size.width - RightPanel.size.width - PANEL_WIDTH) / 2;
}
#endif
LeftPanel.position.y = (gnScreenHeight - LeftPanel.size.height - PANEL_HEIGHT) / 2;
#ifdef VIRTUAL_GAMEPAD
RightPanel.position.x = gnScreenWidth / 2;
#else
RightPanel.position.x = gnScreenWidth - RightPanel.size.width - LeftPanel.position.x;
#endif
RightPanel.position.y = LeftPanel.position.y;
}
/**
* Draws a section of the empty flask cel on top of the panel to create the illusion
* of the flask getting empty. This function takes a cel and draws a
@ -413,6 +383,38 @@ void RemoveGold(Player &player, int goldIndex)
} // namespace
void CalculatePanelAreas()
{
MainPanel = {
{ (gnScreenWidth - PANEL_WIDTH) / 2, gnScreenHeight - PANEL_HEIGHT },
{ PANEL_WIDTH, PANEL_HEIGHT }
};
LeftPanel = {
{ 0, 0 },
{ SPANEL_WIDTH, SPANEL_HEIGHT }
};
RightPanel = {
{ 0, 0 },
{ SPANEL_WIDTH, SPANEL_HEIGHT }
};
if (ControlMode == ControlTypes::VirtualGamepad) {
LeftPanel.position.x = gnScreenWidth / 2 - LeftPanel.size.width;
} else {
if (gnScreenWidth - LeftPanel.size.width - RightPanel.size.width > PANEL_WIDTH) {
LeftPanel.position.x = (gnScreenWidth - LeftPanel.size.width - RightPanel.size.width - PANEL_WIDTH) / 2;
}
}
LeftPanel.position.y = (gnScreenHeight - LeftPanel.size.height - PANEL_HEIGHT) / 2;
if (ControlMode == ControlTypes::VirtualGamepad) {
RightPanel.position.x = gnScreenWidth / 2;
} else {
RightPanel.position.x = gnScreenWidth - RightPanel.size.width - LeftPanel.position.x;
}
RightPanel.position.y = LeftPanel.position.y;
}
bool IsChatAvailable()
{
#ifdef _DEBUG

1
Source/control.h

@ -59,6 +59,7 @@ const Rectangle &GetRightPanel();
extern std::optional<OwnedSurface> pBtmBuff;
extern SDL_Rect PanBtnPos[8];
void CalculatePanelAreas();
bool IsChatAvailable();
/**
* @brief Check if the UI can cover the game area entierly

2
Source/controls/controller.cpp

@ -2,7 +2,9 @@
#include <cmath>
#ifndef USE_SDL1
#include "controls/devices/game_controller.h"
#endif
#include "controls/devices/joystick.h"
#include "controls/devices/kbcontroller.h"

15
Source/controls/controller_motion.cpp

@ -3,10 +3,13 @@
#include <cmath>
#include "controls/controller.h"
#ifndef USE_SDL1
#include "controls/devices/game_controller.h"
#endif
#include "controls/devices/joystick.h"
#include "controls/devices/kbcontroller.h"
#include "controls/game_controls.h"
#include "controls/plrctrls.h"
#include "controls/touch/gamepad.h"
#include "options.h"
@ -160,11 +163,13 @@ AxisDirection GetLeftStickOrDpadDirection(bool allowDpad)
bool isLeftPressed = stickX <= -0.5 || (allowDpad && IsControllerButtonPressed(ControllerButton_BUTTON_DPAD_LEFT));
bool isRightPressed = stickX >= 0.5 || (allowDpad && IsControllerButtonPressed(ControllerButton_BUTTON_DPAD_RIGHT));
#ifdef VIRTUAL_GAMEPAD
isUpPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isUpPressed;
isDownPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isDownPressed;
isLeftPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isLeftPressed;
isRightPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isRightPressed;
#ifndef USE_SDL1
if (ControlMode == ControlTypes::VirtualGamepad) {
isUpPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isUpPressed;
isDownPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isDownPressed;
isLeftPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isLeftPressed;
isRightPressed |= VirtualGamepadState.isActive && VirtualGamepadState.directionPad.isRightPressed;
}
#endif
if (isUpPressed) {

7
Source/controls/devices/game_controller.cpp

@ -1,7 +1,5 @@
#include "controls/devices/game_controller.h"
#ifndef USE_SDL1
#include <cstddef>
#include "controls/controller_motion.h"
@ -13,9 +11,6 @@
namespace devilution {
// Defined in SourceX/controls/plctrls.cpp
extern bool sgbControllerActive;
std::vector<GameController> GameController::controllers_;
void GameController::UnlockTriggerState()
@ -189,7 +184,6 @@ void GameController::Remove(SDL_JoystickID instanceId)
if (controller.instance_id_ != instanceId)
continue;
controllers_.erase(controllers_.begin() + i);
sgbControllerActive = !controllers_.empty();
return;
}
Log("Game controller not found with instance id: {}", instanceId);
@ -231,4 +225,3 @@ bool GameController::IsPressedOnAnyController(ControllerButton button)
}
} // namespace devilution
#endif

3
Source/controls/devices/game_controller.h

@ -1,4 +1,3 @@
#pragma once
#include <vector>
@ -7,7 +6,6 @@
#include "controls/controller_buttons.h"
#ifndef USE_SDL1
namespace devilution {
class GameController {
@ -42,4 +40,3 @@ private:
};
} // namespace devilution
#endif

5
Source/controls/devices/joystick.cpp

@ -8,9 +8,6 @@
namespace devilution {
// Defined in SourceX/controls/plctrls.cpp
extern bool sgbControllerActive;
std::vector<Joystick> Joystick::joysticks_;
ControllerButton Joystick::ToControllerButton(const SDL_Event &event)
@ -267,7 +264,6 @@ void Joystick::Add(int deviceIndex)
result.instance_id_ = SDL_JoystickInstanceID(result.sdl_joystick_);
#endif
joysticks_.push_back(result);
sgbControllerActive = true;
}
void Joystick::Remove(SDL_JoystickID instanceId)
@ -279,7 +275,6 @@ void Joystick::Remove(SDL_JoystickID instanceId)
if (joystick.instance_id_ != instanceId)
continue;
joysticks_.erase(joysticks_.begin() + i);
sgbControllerActive = !joysticks_.empty();
return;
}
Log("Joystick not found with instance id: {}", instanceId);

120
Source/controls/game_controls.cpp

@ -4,7 +4,9 @@
#include "controls/controller.h"
#include "controls/controller_motion.h"
#ifndef USE_SDL1
#include "controls/devices/game_controller.h"
#endif
#include "controls/devices/joystick.h"
#include "controls/menu_controls.h"
#include "controls/modifier_hints.h"
@ -98,65 +100,67 @@ bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrlEvent, Game
{
const bool inGameMenu = InGameMenu();
#ifdef VIRTUAL_GAMEPAD
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 { DVL_VK_TAB, false };
return true;
}
if (VirtualGamepadState.primaryActionButton.isHeld && VirtualGamepadState.primaryActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag)
*action = GameAction(GameActionType_PRIMARY_ACTION);
else if (sgpCurrentMenu != nullptr || stextflag != STORE_NONE || QuestLogIsOpen)
*action = GameActionSendKey { DVL_VK_RETURN, false };
else
*action = GameActionSendKey { DVL_VK_SPACE, false };
return true;
}
if (VirtualGamepadState.secondaryActionButton.isHeld && VirtualGamepadState.secondaryActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag)
*action = GameAction(GameActionType_SECONDARY_ACTION);
return true;
}
if (VirtualGamepadState.spellActionButton.isHeld && VirtualGamepadState.spellActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag)
*action = GameAction(GameActionType_CAST_SPELL);
return true;
}
if (VirtualGamepadState.cancelButton.isHeld && VirtualGamepadState.cancelButton.didStateChange) {
if (inGameMenu || DoomFlag || spselflag)
*action = GameActionSendKey { DVL_VK_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)
#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.healthButton.isHeld && VirtualGamepadState.healthButton.didStateChange) {
if (!QuestLogIsOpen && !sbookflag && stextflag == STORE_NONE)
*action = GameAction(GameActionType_USE_HEALTH_POTION);
return true;
}
if (VirtualGamepadState.manaButton.isHeld && VirtualGamepadState.manaButton.didStateChange) {
if (!QuestLogIsOpen && !sbookflag && stextflag == STORE_NONE)
*action = GameAction(GameActionType_USE_MANA_POTION);
return true;
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 { DVL_VK_TAB, false };
return true;
}
if (VirtualGamepadState.primaryActionButton.isHeld && VirtualGamepadState.primaryActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag)
*action = GameAction(GameActionType_PRIMARY_ACTION);
else if (sgpCurrentMenu != nullptr || stextflag != STORE_NONE || QuestLogIsOpen)
*action = GameActionSendKey { DVL_VK_RETURN, false };
else
*action = GameActionSendKey { DVL_VK_SPACE, false };
return true;
}
if (VirtualGamepadState.secondaryActionButton.isHeld && VirtualGamepadState.secondaryActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag)
*action = GameAction(GameActionType_SECONDARY_ACTION);
return true;
}
if (VirtualGamepadState.spellActionButton.isHeld && VirtualGamepadState.spellActionButton.didStateChange) {
if (!inGameMenu && !QuestLogIsOpen && !sbookflag)
*action = GameAction(GameActionType_CAST_SPELL);
return true;
}
if (VirtualGamepadState.cancelButton.isHeld && VirtualGamepadState.cancelButton.didStateChange) {
if (inGameMenu || DoomFlag || spselflag)
*action = GameActionSendKey { DVL_VK_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 == STORE_NONE)
*action = GameAction(GameActionType_USE_HEALTH_POTION);
return true;
}
if (VirtualGamepadState.manaButton.isHeld && VirtualGamepadState.manaButton.didStateChange) {
if (!QuestLogIsOpen && !sbookflag && stextflag == STORE_NONE)
*action = GameAction(GameActionType_USE_MANA_POTION);
return true;
}
}
}
#endif

9
Source/controls/menu_controls.cpp

@ -28,13 +28,9 @@ MenuAction GetMenuAction(const SDL_Event &event)
const ControllerButtonEvent ctrlEvent = ToControllerButtonEvent(event);
if (ProcessControllerMotion(event, ctrlEvent)) {
sgbControllerActive = true;
return GetMenuHeldUpDownAction();
}
if (ctrlEvent.button != ControllerButton_NONE)
sgbControllerActive = true;
if (!ctrlEvent.up) {
switch (ctrlEvent.button) {
case ControllerButton_IGNORE:
@ -64,8 +60,6 @@ MenuAction GetMenuAction(const SDL_Event &event)
}
if (event.type == SDL_MOUSEBUTTONDOWN) {
sgbControllerActive = false;
switch (event.button.button) {
case SDL_BUTTON_X1:
#if !SDL_VERSION_ATLEAST(2, 0, 0)
@ -76,9 +70,6 @@ MenuAction GetMenuAction(const SDL_Event &event)
}
#if HAS_KBCTRL == 0
if (event.type >= SDL_KEYDOWN && event.type < SDL_JOYAXISMOTION)
sgbControllerActive = false;
if (event.type == SDL_KEYDOWN) {
auto sym = event.key.keysym.sym;
remap_keyboard_key(&sym);

177
Source/controls/plrctrls.cpp

@ -8,6 +8,9 @@
#include "control.h"
#include "controls/controller.h"
#include "controls/controller_motion.h"
#ifndef USE_SDL1
#include "controls/devices/game_controller.h"
#endif
#include "controls/game_controls.h"
#include "controls/touch/gamepad.h"
#include "cursor.h"
@ -29,8 +32,7 @@
namespace devilution {
bool sgbTouchActive = false;
bool sgbControllerActive = false;
ControlTypes ControlMode = ControlTypes::None;
int pcurstrig = -1;
int pcursmissile = -1;
quest_id pcursquest = Q_INVALID;
@ -456,8 +458,10 @@ void Interact()
}
bool stand = false;
#ifdef VIRTUAL_GAMEPAD
stand = VirtualGamepadState.standButton.isHeld;
#ifndef USE_SDL1
if (ControlMode == ControlTypes::VirtualGamepad) {
stand = VirtualGamepadState.standButton.isHeld;
}
#endif
if (leveltype != DTYPE_TOWN && stand) {
@ -1117,7 +1121,7 @@ void WalkInDir(int playerId, AxisDirection dir)
auto &player = Players[playerId];
if (dir.x == AxisDirectionX_NONE && dir.y == AxisDirectionY_NONE) {
if (sgbControllerActive && player.walkpath[0] != WALK_NONE && player.destAction == ACTION_NONE)
if (ControlMode != ControlTypes::KeyboardAndMouse && player.walkpath[0] != WALK_NONE && player.destAction == ACTION_NONE)
NetSendCmdLoc(playerId, true, CMD_WALKXY, player.position.future); // Stop walking
return;
}
@ -1128,11 +1132,13 @@ void WalkInDir(int playerId, AxisDirection dir)
if (!player.IsWalking() && player.CanChangeAction())
player._pdir = pdir;
#ifdef VIRTUAL_GAMEPAD
if (VirtualGamepadState.standButton.isHeld) {
if (player._pmode == PM_STAND)
StartStand(playerId, pdir);
return;
#ifndef USE_SDL1
if (ControlMode == ControlTypes::VirtualGamepad) {
if (VirtualGamepadState.standButton.isHeld) {
if (player._pmode == PM_STAND)
StartStand(playerId, pdir);
return;
}
}
#endif
@ -1204,13 +1210,8 @@ void Movement(int playerId)
|| IsControllerButtonPressed(ControllerButton_BUTTON_BACK))
return;
AxisDirection moveDir = GetMoveDirection();
if (moveDir.x != AxisDirectionX_NONE || moveDir.y != AxisDirectionY_NONE) {
sgbControllerActive = true;
}
if (GetLeftStickOrDPadGameUIHandler() == nullptr) {
WalkInDir(playerId, moveDir);
WalkInDir(playerId, GetMoveDirection());
}
}
@ -1249,16 +1250,103 @@ struct RightStickAccumulator {
float hiresDY;
};
ControlTypes GetInputTypeFromEvent(SDL_Event &event)
{
if (IsAnyOf(event.type, SDL_KEYDOWN, SDL_KEYUP))
return ControlTypes::KeyboardAndMouse;
#ifdef USE_SDL1
if (IsAnyOf(event.type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEMOTION))
return ControlTypes::KeyboardAndMouse;
#else
if (IsAnyOf(event.type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP))
return event.button.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse;
if (event.type == SDL_MOUSEMOTION)
return event.motion.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse;
if (event.type == SDL_MOUSEWHEEL)
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 && event.type <= SDL_CONTROLLERDEVICEREMAPPED)
return ControlTypes::Gamepad;
if (IsAnyOf(event.type, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED))
return ControlTypes::Gamepad;
#endif
if (event.type >= SDL_JOYAXISMOTION && event.type <= SDL_JOYBUTTONUP)
return ControlTypes::Gamepad;
return ControlTypes::None;
}
bool ContinueSimulatingMouse(SDL_Event &event)
{
if (IsAutomapActive())
return false;
if (event.type == SDL_JOYAXISMOTION) {
#if defined(JOY_AXIS_RIGHTX)
if (event.jaxis.axis == JOY_AXIS_RIGHTX)
return true;
#endif
#if defined(JOY_AXIS_RIGHTY)
if (event.jaxis.axis == JOY_AXIS_RIGHTY)
return true;
#endif
#ifndef USE_SDL1
#if !defined(JOY_AXIS_RIGHTX) && !defined(JOY_AXIS_RIGHTY)
if (!GameController::All().empty())
return true;
#endif
} else if (event.type == SDL_CONTROLLERAXISMOTION && IsAnyOf(event.caxis.axis, SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY)) {
return true;
#endif
#ifdef USE_SDL1
} else if (IsAnyOf(event.type, SDL_JOYBUTTONUP, SDL_JOYBUTTONDOWN, SDL_KEYUP, SDL_KEYDOWN)) {
#else
} else if (IsAnyOf(event.type, SDL_JOYBUTTONUP, SDL_JOYBUTTONDOWN, SDL_KEYUP, SDL_KEYDOWN, SDL_CONTROLLERBUTTONUP, SDL_CONTROLLERBUTTONDOWN)) {
#endif
const ControllerButtonEvent ctrlEvent = ToControllerButtonEvent(event);
if (IsAnyOf(ctrlEvent.button, ControllerButton_BUTTON_RIGHTSTICK, ControllerButton_BUTTON_BACK, ControllerButton_NONE, ControllerButton_IGNORE)) {
return true;
}
}
return false;
}
} // namespace
bool IsAutomapActive()
void DetectInputMethod(SDL_Event &event)
{
return AutomapActive && leveltype != DTYPE_TOWN;
ControlTypes inputType = GetInputTypeFromEvent(event);
#ifdef __vita__
if (inputType == ControlTypes::VirtualGamepad) {
inputType = ControlTypes::Gamepad;
}
#endif
#if HAS_KBCTRL == 1
if (inputType == ControlTypes::KeyboardAndMouse) {
const ControllerButtonEvent ctrlEvent = ToControllerButtonEvent(event);
if (!IsAnyOf(ctrlEvent.button, ControllerButton_NONE, ControllerButton_IGNORE)) {
inputType = ControlTypes::Gamepad;
}
}
#endif
if (ControlMode == ControlTypes::KeyboardAndMouse && inputType == ControlTypes::Gamepad && ContinueSimulatingMouse(event)) {
return;
}
if (inputType != ControlTypes::None && inputType != ControlMode) {
ControlMode = inputType;
CalculatePanelAreas();
}
}
bool IsMovingMouseCursorWithController()
bool IsAutomapActive()
{
return rightStickX != 0 || rightStickY != 0;
return AutomapActive && leveltype != DTYPE_TOWN;
}
void HandleRightStickMotion()
@ -1280,7 +1368,6 @@ void HandleRightStickMotion()
}
{ // move cursor
sgbControllerActive = false;
InvalidateInventorySlot();
int x = MousePosition.x;
int y = MousePosition.y;
@ -1317,29 +1404,31 @@ void FocusOnInventory()
void plrctrls_after_check_curs_move()
{
// check for monsters first, then items, then towners.
if (sgbControllerActive) {
// Clear focuse set by cursor
pcursplr = -1;
pcursmonst = -1;
pcursitem = -1;
pcursobj = -1;
pcursmissile = -1;
pcurstrig = -1;
pcursquest = Q_INVALID;
cursPosition = { -1, -1 };
if (Players[MyPlayerId]._pInvincible) {
return;
}
if (DoomFlag) {
return;
}
if (!invflag) {
*infostr = '\0';
ClearPanel();
FindActor();
FindItemOrObject();
FindTrigger();
}
if (ControlMode == ControlTypes::KeyboardAndMouse) {
return;
}
// Clear focuse set by cursor
pcursplr = -1;
pcursmonst = -1;
pcursitem = -1;
pcursobj = -1;
pcursmissile = -1;
pcurstrig = -1;
pcursquest = Q_INVALID;
cursPosition = { -1, -1 };
if (Players[MyPlayerId]._pInvincible) {
return;
}
if (DoomFlag) {
return;
}
if (!invflag) {
*infostr = '\0';
ClearPanel();
FindActor();
FindItemOrObject();
FindTrigger();
}
}

14
Source/controls/plrctrls.h

@ -12,6 +12,15 @@ typedef enum belt_item_type : uint8_t {
BLT_MANA,
} belt_item_type;
enum class ControlTypes : uint8_t {
None,
KeyboardAndMouse,
Gamepad,
VirtualGamepad,
};
extern ControlTypes ControlMode;
// Runs every frame.
// Handles menu movement.
void plrctrls_every_frame();
@ -30,12 +39,11 @@ void HandleRightStickMotion();
// Whether we're in a dialog menu that the game handles natively with keyboard controls.
bool InGameMenu();
void DetectInputMethod(SDL_Event &event);
// Whether the automap is being displayed.
bool IsAutomapActive();
// Whether the mouse cursor is being moved with the controller.
bool IsMovingMouseCursorWithController();
void UseBeltItem(int type);
// Talk to towners, click on inv items, attack, etc.

11
Source/controls/touch/event_handlers.cpp

@ -1,5 +1,3 @@
#ifndef USE_SDL1
#include "controls/touch/event_handlers.h"
#include "control.h"
@ -15,8 +13,6 @@
namespace devilution {
extern bool sgbTouchActive;
namespace {
VirtualGamepadEventHandler Handler(&VirtualGamepadState);
@ -38,7 +34,6 @@ void SimulateMouseMovement(const SDL_Event &event)
MousePosition = position;
sgbControllerActive = false;
InvalidateInventorySlot();
}
@ -93,16 +88,12 @@ void HandleBottomPanelInteraction(const SDL_Event &event)
void HandleTouchEvent(const SDL_Event &event)
{
sgbTouchActive = false;
if (Handler.Handle(event))
return;
if (!IsAnyOf(event.type, SDL_FINGERDOWN, SDL_FINGERUP, SDL_FINGERMOTION))
return;
sgbTouchActive = true;
SimulateMouseMovement(event);
if (HandleGameMenuInteraction(event))
@ -308,5 +299,3 @@ bool VirtualButtonEventHandler::HandleFingerMotion(const SDL_TouchFingerEvent &e
}
} // namespace devilution
#endif

4
Source/controls/touch/event_handlers.h

@ -1,7 +1,5 @@
#pragma once
#ifdef VIRTUAL_GAMEPAD
#include <SDL.h>
#include "controls/touch/gamepad.h"
@ -93,5 +91,3 @@ private:
void HandleTouchEvent(const SDL_Event &event);
} // namespace devilution
#endif

4
Source/controls/touch/gamepad.h

@ -1,7 +1,5 @@
#pragma once
#ifdef VIRTUAL_GAMEPAD
#include <functional>
#include "controls/controller_buttons.h"
@ -121,5 +119,3 @@ void DeactivateVirtualGamepad();
extern VirtualGamepad VirtualGamepadState;
} // namespace devilution
#endif

1
Source/controls/touch/renderers.cpp

@ -1,4 +1,5 @@
#include "controls/touch/renderers.h"
#include "control.h"
#include "cursor.h"
#include "diablo.h"

4
Source/controls/touch/renderers.h

@ -1,7 +1,5 @@
#pragma once
#ifdef VIRTUAL_GAMEPAD
#include <SDL.h>
#include "DiabloUI/art.h"
@ -224,5 +222,3 @@ void RenderVirtualGamepad(SDL_Surface *surface);
void FreeVirtualGamepadGFX();
} // namespace devilution
#endif

16
Source/diablo.cpp

@ -198,7 +198,7 @@ bool ProcessInput()
if (!gmenu_is_active() && sgnTimeoutCurs == CURSOR_NONE) {
#ifdef __vita__
finish_simulated_mouse_clicks(MousePosition.x, MousePosition.y);
FinishSimulatedMouseClicks(MousePosition);
#endif
CheckCursMove();
plrctrls_after_check_curs_move();
@ -909,7 +909,7 @@ void DiabloParseFlags(int argc, char **argv)
void DiabloInitScreen()
{
MousePosition = { gnScreenWidth / 2, gnScreenHeight / 2 };
if (!sgbControllerActive)
if (ControlMode == ControlTypes::KeyboardAndMouse)
SetCursorPos(MousePosition);
ScrollInfo.tile = { 0, 0 };
ScrollInfo.offset = { 0, 0 };
@ -953,7 +953,7 @@ void DiabloInit()
messages.emplace_back(_(QuickMessages[i].message));
}
#ifdef VIRTUAL_GAMEPAD
#ifndef USE_SDL1
InitializeVirtualGamepad();
#endif
@ -1090,7 +1090,7 @@ void LoadLvlGFX()
void LoadAllGFX()
{
IncProgress();
#ifdef VIRTUAL_GAMEPAD
#if !defined(USE_SDL1) && !defined(__vita__)
InitVirtualGamepadGFX(renderer);
#endif
IncProgress();
@ -1563,7 +1563,7 @@ void FreeGameMem()
FreeObjectGFX();
FreeMonsterSnd();
FreeTownerGFX();
#ifdef VIRTUAL_GAMEPAD
#ifndef USE_SDL1
DeactivateVirtualGamepad();
FreeVirtualGamepadGFX();
#endif
@ -1908,7 +1908,7 @@ void LoadGameLevel(bool firstflag, lvl_entry lvldir)
LoadAllGFX();
} else {
IncProgress();
#ifdef VIRTUAL_GAMEPAD
#if !defined(USE_SDL1) && !defined(__vita__)
InitVirtualGamepadGFX(renderer);
#endif
IncProgress();
@ -2014,7 +2014,7 @@ void LoadGameLevel(bool firstflag, lvl_entry lvldir)
InitGolems();
InitMonsters();
IncProgress();
#ifdef VIRTUAL_GAMEPAD
#if !defined(USE_SDL1) && !defined(__vita__)
InitVirtualGamepadGFX(renderer);
#endif
InitMissileGFX(gbIsHellfire);
@ -2093,7 +2093,7 @@ void LoadGameLevel(bool firstflag, lvl_entry lvldir)
}
}
#ifdef VIRTUAL_GAMEPAD
#ifndef USE_SDL1
ActivateVirtualGamepad();
#endif

13
Source/dx.cpp

@ -7,6 +7,7 @@
#include <SDL.h>
#include "controls/plrctrls.h"
#include "controls/touch/renderers.h"
#include "engine.h"
#include "options.h"
@ -283,18 +284,18 @@ void RenderPresent()
if (SDL_RenderCopy(renderer, texture.get(), nullptr, nullptr) <= -1) {
ErrSdl();
}
#ifdef VIRTUAL_GAMEPAD
RenderVirtualGamepad(renderer);
#endif
if (ControlMode == ControlTypes::VirtualGamepad) {
RenderVirtualGamepad(renderer);
}
SDL_RenderPresent(renderer);
if (!*sgOptions.Graphics.vSync) {
LimitFrameRate();
}
} else {
#ifdef VIRTUAL_GAMEPAD
RenderVirtualGamepad(surface);
#endif
if (ControlMode == ControlTypes::VirtualGamepad) {
RenderVirtualGamepad(surface);
}
if (SDL_UpdateWindowSurface(ghMainWnd) <= -1) {
ErrSdl();
}

2
Source/inv.cpp

@ -1345,7 +1345,7 @@ void DrawInvBelt(const Surface &out)
const int celFrame = GetInvItemFrame(frame);
if (pcursinvitem == i + INVITEM_BELT_FIRST) {
if (!sgbControllerActive || invflag) {
if (ControlMode == ControlTypes::KeyboardAndMouse || invflag) {
CelBlitOutlineTo(out, GetOutlineColor(myPlayer.SpdList[i], true), position, cel, celFrame, false);
}
}

3
Source/miniwin/miniwin.h

@ -1,6 +1,6 @@
#pragma once
#include <SDL_keyboard.h>
#include <SDL.h>
#include <cctype>
#include <cmath>
#include <cstdint>
@ -47,6 +47,7 @@ int TranslateSdlKey(SDL_Keysym key);
bool GetAsyncKeyState(int vKey);
void SetMouseButtonEvent(SDL_Event &event, uint32_t type, uint8_t button, Point position);
bool FetchMessage(tagMSG *lpMsg);
bool TranslateMessage(const tagMSG *lpMsg);

68
Source/miniwin/misc_msg.cpp

@ -16,7 +16,9 @@
#include "controls/input.h"
#include "controls/plrctrls.h"
#include "controls/remap_keyboard.h"
#ifndef USE_SDL1
#include "controls/touch/event_handlers.h"
#endif
#include "cursor.h"
#include "engine/demomode.h"
#include "engine/rectangle.hpp"
@ -53,6 +55,19 @@ static std::deque<tagMSG> message_queue;
bool mouseWarping = false;
Point mousePositionWarping;
void SetMouseButtonEvent(SDL_Event &event, uint32_t type, uint8_t button, Point position)
{
event.type = type;
event.button.button = button;
if (type == SDL_MOUSEBUTTONDOWN) {
event.button.state = SDL_PRESSED;
} else {
event.button.state = SDL_RELEASED;
}
event.button.x = position.x;
event.button.y = position.y;
}
void SetCursorPos(Point position)
{
mousePositionWarping = position;
@ -319,11 +334,24 @@ bool FetchMessage_Real(tagMSG *lpMsg)
lpMsg->lParam = 0;
lpMsg->wParam = 0;
#ifdef __vita__
HandleTouchEvent(&e, MousePosition);
#elif !defined(USE_SDL1)
HandleTouchEvent(e);
#endif
if (e.type == SDL_QUIT) {
lpMsg->message = DVL_WM_QUIT;
return true;
}
if ((e.type == SDL_KEYUP || e.type == SDL_KEYDOWN) && e.key.keysym.sym == SDLK_UNKNOWN) {
// Erroneous events generated by RG350 kernel.
return true;
}
DetectInputMethod(e);
#if !defined(USE_SDL1) && !defined(__vita__)
if (!movie_playing) {
// SDL generates mouse events from touch-based inputs to provide basic
@ -337,27 +365,14 @@ bool FetchMessage_Real(tagMSG *lpMsg)
}
#endif
#ifdef VIRTUAL_GAMEPAD
HandleTouchEvent(e);
#endif
#ifdef __vita__
handle_touch(&e, MousePosition.x, MousePosition.y);
#endif
#ifdef USE_SDL1
if (e.type == SDL_MOUSEMOTION) {
OutputToLogical(&e.motion.x, &e.motion.y);
} else if (e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP) {
} else if (IsAnyOf(e.type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP)) {
OutputToLogical(&e.button.x, &e.button.y);
}
#endif
if ((e.type == SDL_KEYUP || e.type == SDL_KEYDOWN) && e.key.keysym.sym == SDLK_UNKNOWN) {
// Erroneous events generated by RG350 kernel.
return true;
}
if (HandleControllerAddedOrRemovedEvent(e))
return true;
@ -368,8 +383,6 @@ bool FetchMessage_Real(tagMSG *lpMsg)
GameAction action;
if (GetGameAction(e, ctrlEvent, &action)) {
if (action.type != GameActionType_NONE) {
sgbControllerActive = true;
if (movie_playing) {
lpMsg->message = DVL_WM_KEYDOWN;
if (action.type == GameActionType_SEND_KEY)
@ -450,27 +463,20 @@ bool FetchMessage_Real(tagMSG *lpMsg)
lpMsg->wParam = action.send_key.vk_code;
return true;
case GameActionType_SEND_MOUSE_CLICK:
sgbControllerActive = false;
switch (action.send_mouse_click.button) {
case GameActionSendMouseClick::LEFT:
lpMsg->message = action.send_mouse_click.up ? DVL_WM_LBUTTONUP : DVL_WM_LBUTTONDOWN;
break;
case GameActionSendMouseClick::RIGHT:
lpMsg->message = action.send_mouse_click.up ? DVL_WM_RBUTTONUP : DVL_WM_RBUTTONDOWN;
break;
}
lpMsg->lParam = PositionForMouse(MousePosition.x, MousePosition.y);
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);
SDL_PushEvent(&clickEvent);
break;
}
return true;
#ifdef __vita__
}
#ifdef __vita__
if (e.type < SDL_JOYAXISMOTION || (e.type >= SDL_FINGERDOWN && e.type < SDL_DOLLARGESTURE)) {
#else
} else if (e.type < SDL_JOYAXISMOTION) {
if (e.type < SDL_JOYAXISMOTION) {
#endif
if (!mouseWarping || e.type != SDL_MOUSEMOTION)
sgbControllerActive = false;
if (mouseWarping && e.type == SDL_MOUSEMOTION)
mouseWarping = false;
}
@ -506,7 +512,7 @@ bool FetchMessage_Real(tagMSG *lpMsg)
lpMsg->message = DVL_WM_MOUSEMOVE;
lpMsg->lParam = PositionForMouse(e.motion.x, e.motion.y);
lpMsg->wParam = KeystateForMouse(0);
if (!sgbControllerActive && invflag)
if (ControlMode == ControlTypes::KeyboardAndMouse && invflag)
InvalidateInventorySlot();
break;
case SDL_MOUSEBUTTONDOWN: {

13
Source/missiles.cpp

@ -8,6 +8,7 @@
#include <climits>
#include "control.h"
#include "controls/plrctrls.h"
#include "cursor.h"
#include "dead.h"
#ifdef _DEBUG
@ -2444,7 +2445,7 @@ void AddHealOther(Missile &missile, Point /*dst*/, Direction /*midir*/)
UseMana(missile._misource, SPL_HEALOTHER);
if (missile._misource == MyPlayerId) {
NewCursor(CURSOR_HEALOTHER);
if (sgbControllerActive)
if (ControlMode != ControlTypes::KeyboardAndMouse)
TryIconCurs();
}
}
@ -2480,7 +2481,7 @@ void AddIdentify(Missile &missile, Point /*dst*/, Direction /*midir*/)
sbookflag = false;
if (!invflag) {
invflag = true;
if (sgbControllerActive)
if (ControlMode != ControlTypes::KeyboardAndMouse)
FocusOnInventory();
}
NewCursor(CURSOR_IDENTIFY);
@ -2577,7 +2578,7 @@ void AddRepair(Missile &missile, Point /*dst*/, Direction /*midir*/)
sbookflag = false;
if (!invflag) {
invflag = true;
if (sgbControllerActive)
if (ControlMode != ControlTypes::KeyboardAndMouse)
FocusOnInventory();
}
NewCursor(CURSOR_REPAIR);
@ -2593,7 +2594,7 @@ void AddRecharge(Missile &missile, Point /*dst*/, Direction /*midir*/)
sbookflag = false;
if (!invflag) {
invflag = true;
if (sgbControllerActive)
if (ControlMode != ControlTypes::KeyboardAndMouse)
FocusOnInventory();
}
NewCursor(CURSOR_RECHARGE);
@ -2606,7 +2607,7 @@ void AddDisarm(Missile &missile, Point /*dst*/, Direction /*midir*/)
UseMana(missile._misource, SPL_DISARM);
if (missile._misource == MyPlayerId) {
NewCursor(CURSOR_DISARM);
if (sgbControllerActive) {
if (ControlMode != ControlTypes::KeyboardAndMouse) {
if (pcursobj != -1)
NetSendCmdLocParam1(true, CMD_DISARMXY, cursPosition, pcursobj);
else
@ -2703,7 +2704,7 @@ void AddResurrect(Missile &missile, Point /*dst*/, Direction /*midir*/)
UseMana(missile._misource, SPL_RESURRECT);
if (missile._misource == MyPlayerId) {
NewCursor(CURSOR_RESURRECT);
if (sgbControllerActive)
if (ControlMode != ControlTypes::KeyboardAndMouse)
TryIconCurs();
}
missile._miDelFlag = true;

221
Source/platform/vita/touch.cpp

@ -1,14 +1,23 @@
#include "platform/vita/touch.h"
#include <cmath>
#include "miniwin/miniwin.h"
#include "options.h"
#include "touch.h"
#include "utils/display.h"
#include "utils/ui_fwd.h"
static int visible_width;
static int visible_height;
static int x_borderwidth;
static int y_borderwidth;
namespace devilution {
namespace {
#define TOUCH_PORT_MAX_NUM 1
#define NO_TOUCH (-1) // finger id setting if finger is not touching the screen
int visible_width;
int visible_height;
int x_borderwidth;
int y_borderwidth;
template <typename T>
inline T clip(T v, T amin, T amax)
@ -21,24 +30,20 @@ inline T clip(T v, T amin, T amax)
return v;
}
#define TOUCH_PORT_MAX_NUM 1
#define NO_TOUCH (-1) // finger id setting if finger is not touching the screen
void SetMouseMotionEvent(SDL_Event *event, int32_t x, int32_t y, int32_t xrel, int32_t yrel)
{
event->type = SDL_MOUSEMOTION;
event->motion.x = x;
event->motion.y = y;
event->motion.xrel = xrel;
event->motion.yrel = yrel;
event->motion.which = SDL_TOUCH_MOUSEID;
}
static void InitTouch();
static void PreprocessEvents(SDL_Event *event);
static void PreprocessFingerDown(SDL_Event *event);
static void PreprocessFingerUp(SDL_Event *event);
static void preprocess_back_finger_down(SDL_Event *event);
static void preprocess_back_finger_up(SDL_Event *event);
static void PreprocessFingerMotion(SDL_Event *event);
static void SetMouseButtonEvent(SDL_Event *event, uint32_t type, uint8_t button, int32_t x, int32_t y);
static void SetMouseMotionEvent(SDL_Event *event, int32_t x, int32_t y, int32_t xrel, int32_t yrel);
static bool touch_initialized = false;
static unsigned int simulated_click_start_time[TOUCH_PORT_MAX_NUM][2]; // initiation time of last simulated left or right click (zero if no click)
static bool direct_touch = true; // pointer jumps to finger
static int mouse_x = 0; // always reflects current mouse position
static int mouse_y = 0;
bool touch_initialized = false;
unsigned int simulated_click_start_time[TOUCH_PORT_MAX_NUM][2]; // initiation time of last simulated left or right click (zero if no click)
bool direct_touch = true; // pointer jumps to finger
Point Mouse; // always reflects current mouse position
enum {
// clang-format off
@ -58,7 +63,7 @@ struct Touch {
float lastDownY; // SDL touch coordinates when last pressed down
};
static Touch finger[TOUCH_PORT_MAX_NUM][MaxNumFingers]; // keep track of finger status
Touch finger[TOUCH_PORT_MAX_NUM][MaxNumFingers]; // keep track of finger status
enum DraggingType {
DragNone,
@ -66,9 +71,9 @@ enum DraggingType {
DragThreeFinger,
};
static DraggingType multi_finger_dragging[TOUCH_PORT_MAX_NUM]; // keep track whether we are currently drag-and-dropping
DraggingType multi_finger_dragging[TOUCH_PORT_MAX_NUM]; // keep track whether we are currently drag-and-dropping
static void InitTouch()
void InitTouch()
{
for (int port = 0; port < TOUCH_PORT_MAX_NUM; port++) {
for (int i = 0; i < MaxNumFingers; i++) {
@ -91,56 +96,15 @@ static void InitTouch()
y_borderwidth = (current.h - visible_height) / 2;
}
static void PreprocessEvents(SDL_Event *event)
{
// Supported touch gestures:
// left mouse click: single finger short tap
// right mouse click: second finger short tap while first finger is still down
// pointer motion: single finger drag
// left button drag and drop: dual finger drag
// right button drag and drop: triple finger drag
if (event->type != SDL_FINGERDOWN && event->type != SDL_FINGERUP && event->type != SDL_FINGERMOTION) {
return;
}
// front (0) or back (1) panel
SDL_TouchID port = event->tfinger.touchId;
if (port != 0) {
if (devilution::sgOptions.Controller.bRearTouch) {
switch (event->type) {
case SDL_FINGERDOWN:
preprocess_back_finger_down(event);
break;
case SDL_FINGERUP:
preprocess_back_finger_up(event);
break;
}
}
return;
}
switch (event->type) {
case SDL_FINGERDOWN:
PreprocessFingerDown(event);
break;
case SDL_FINGERUP:
PreprocessFingerUp(event);
break;
case SDL_FINGERMOTION:
PreprocessFingerMotion(event);
break;
}
}
static void PreprocessFingerDown(SDL_Event *event)
void PreprocessFingerDown(SDL_Event *event)
{
// front (0) or back (1) panel
SDL_TouchID port = event->tfinger.touchId;
// id (for multitouch)
SDL_FingerID id = event->tfinger.fingerId;
int x = mouse_x;
int y = mouse_y;
int x = Mouse.x;
int y = Mouse.y;
if (direct_touch) {
x = static_cast<int>(event->tfinger.x * visible_width) + x_borderwidth;
@ -173,7 +137,7 @@ static void PreprocessFingerDown(SDL_Event *event)
}
}
static void preprocess_back_finger_down(SDL_Event *event)
void PreprocessBackFingerDown(SDL_Event *event)
{
// front (0) or back (1) panel
SDL_TouchID port = event->tfinger.touchId;
@ -192,7 +156,7 @@ static void preprocess_back_finger_down(SDL_Event *event)
}
}
static void preprocess_back_finger_up(SDL_Event *event)
void PreprocessBackFingerUp(SDL_Event *event)
{
// front (0) or back (1) panel
SDL_TouchID port = event->tfinger.touchId;
@ -204,14 +168,13 @@ static void preprocess_back_finger_up(SDL_Event *event)
event->caxis.value = 0;
event->caxis.which = 0;
if (event->tfinger.x <= 0.5) {
;
event->caxis.axis = SDL_CONTROLLER_AXIS_TRIGGERLEFT;
} else {
event->caxis.axis = SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
}
}
static void PreprocessFingerUp(SDL_Event *event)
void PreprocessFingerUp(SDL_Event *event)
{
// front (0) or back (1) panel
SDL_TouchID port = event->tfinger.touchId;
@ -226,8 +189,8 @@ static void PreprocessFingerUp(SDL_Event *event)
}
}
int x = mouse_x;
int y = mouse_y;
int x = Mouse.x;
int y = Mouse.y;
for (int i = 0; i < MaxNumFingers; i++) {
if (finger[port][i].id != id) {
@ -268,7 +231,8 @@ static void PreprocessFingerUp(SDL_Event *event)
devilution::OutputToLogical(&x, &y);
}
}
SetMouseButtonEvent(event, SDL_MOUSEBUTTONDOWN, simulatedButton, x, y);
SetMouseButtonEvent(*event, SDL_MOUSEBUTTONDOWN, simulatedButton, { x, y });
event->button.which = SDL_TOUCH_MOUSEID;
} else if (numFingersDown == 1) {
// when dragging, and the last finger is lifted, the drag is over
Uint8 simulatedButton = 0;
@ -277,13 +241,14 @@ static void PreprocessFingerUp(SDL_Event *event)
} else {
simulatedButton = SDL_BUTTON_LEFT;
}
SetMouseButtonEvent(event, SDL_MOUSEBUTTONUP, simulatedButton, x, y);
SetMouseButtonEvent(*event, SDL_MOUSEBUTTONUP, simulatedButton, { x, y });
event->button.which = SDL_TOUCH_MOUSEID;
multi_finger_dragging[port] = DragNone;
}
}
}
static void PreprocessFingerMotion(SDL_Event *event)
void PreprocessFingerMotion(SDL_Event *event)
{
// front (0) or back (1) panel
SDL_TouchID port = event->tfinger.touchId;
@ -303,8 +268,8 @@ static void PreprocessFingerMotion(SDL_Event *event)
}
if (numFingersDown >= 1) {
int x = mouse_x;
int y = mouse_y;
int x = Mouse.x;
int y = Mouse.y;
if (direct_touch) {
x = static_cast<int>(event->tfinger.x * visible_width) + x_borderwidth;
@ -316,14 +281,14 @@ static void PreprocessFingerMotion(SDL_Event *event)
// convert touch events to relative mouse pointer events
// Whenever an SDL_event involving the mouse is processed,
x = static_cast<int>(mouse_x + (event->tfinger.dx * SpeedFactor * devilution::GetOutputSurface()->w));
y = static_cast<int>(mouse_y + (event->tfinger.dy * SpeedFactor * devilution::GetOutputSurface()->h));
x = static_cast<int>(Mouse.x + (event->tfinger.dx * SpeedFactor * devilution::GetOutputSurface()->w));
y = static_cast<int>(Mouse.y + (event->tfinger.dy * SpeedFactor * devilution::GetOutputSurface()->h));
}
x = clip(x, 0, devilution::GetOutputSurface()->w);
y = clip(y, 0, devilution::GetOutputSurface()->h);
int xrel = x - mouse_x;
int yrel = y - mouse_y;
int xrel = x - Mouse.x;
int yrel = y - Mouse.y;
// update the current finger's coordinates so we can track it later
for (int i = 0; i < MaxNumFingers; i++) {
@ -346,8 +311,7 @@ static void PreprocessFingerMotion(SDL_Event *event)
}
}
if (numFingersDownlong >= 2) {
int mouseDownX = mouse_x;
int mouseDownY = mouse_y;
Point mouseDown = Mouse;
if (direct_touch) {
for (int i = 0; i < MaxNumFingers; i++) {
if (finger[port][i].id == id) {
@ -355,8 +319,8 @@ static void PreprocessFingerMotion(SDL_Event *event)
for (int j = 0; j < MaxNumFingers; j++) {
if (finger[port][j].id >= 0 && (i != j)) {
if (finger[port][j].timeLastDown < earliestTime) {
mouseDownX = finger[port][j].lastX;
mouseDownY = finger[port][j].lastY;
mouseDown.x = finger[port][j].lastX;
mouseDown.y = finger[port][j].lastY;
earliestTime = finger[port][j].timeLastDown;
}
}
@ -375,7 +339,8 @@ static void PreprocessFingerMotion(SDL_Event *event)
multi_finger_dragging[port] = DragThreeFinger;
}
SDL_Event ev;
SetMouseButtonEvent(&ev, SDL_MOUSEBUTTONDOWN, simulatedButton, mouseDownX, mouseDownY);
SetMouseButtonEvent(ev, SDL_MOUSEBUTTONDOWN, simulatedButton, mouseDown);
ev.button.which = SDL_TOUCH_MOUSEID;
SDL_PushEvent(&ev);
}
}
@ -409,12 +374,52 @@ static void PreprocessFingerMotion(SDL_Event *event)
}
}
namespace devilution {
void PreprocessEvents(SDL_Event *event)
{
// Supported touch gestures:
// left mouse click: single finger short tap
// right mouse click: second finger short tap while first finger is still down
// pointer motion: single finger drag
// left button drag and drop: dual finger drag
// right button drag and drop: triple finger drag
if (event->type != SDL_FINGERDOWN && event->type != SDL_FINGERUP && event->type != SDL_FINGERMOTION) {
return;
}
void handle_touch(SDL_Event *event, int currentMouseX, int currentMouseY)
// front (0) or back (1) panel
SDL_TouchID port = event->tfinger.touchId;
if (port != 0) {
if (devilution::sgOptions.Controller.bRearTouch) {
switch (event->type) {
case SDL_FINGERDOWN:
PreprocessBackFingerDown(event);
break;
case SDL_FINGERUP:
PreprocessBackFingerUp(event);
break;
}
}
return;
}
switch (event->type) {
case SDL_FINGERDOWN:
PreprocessFingerDown(event);
break;
case SDL_FINGERUP:
PreprocessFingerUp(event);
break;
case SDL_FINGERMOTION:
PreprocessFingerMotion(event);
break;
}
}
} // namespace
void HandleTouchEvent(SDL_Event *event, Point mousePosition)
{
mouse_x = currentMouseX;
mouse_y = currentMouseY;
Mouse = mousePosition;
if (!touch_initialized) {
InitTouch();
@ -427,10 +432,9 @@ void handle_touch(SDL_Event *event, int currentMouseX, int currentMouseY)
}
}
void finish_simulated_mouse_clicks(int currentMouseX, int currentMouseY)
void FinishSimulatedMouseClicks(Point mousePosition)
{
mouse_x = currentMouseX;
mouse_y = currentMouseY;
Mouse = mousePosition;
for (auto &port : simulated_click_start_time) {
for (int i = 0; i < 2; i++) {
@ -450,7 +454,8 @@ void finish_simulated_mouse_clicks(int currentMouseX, int currentMouseY)
simulatedButton = SDL_BUTTON_RIGHT;
}
SDL_Event ev;
SetMouseButtonEvent(&ev, SDL_MOUSEBUTTONUP, simulatedButton, mouse_x, mouse_y);
SetMouseButtonEvent(ev, SDL_MOUSEBUTTONUP, simulatedButton, Mouse);
ev.button.which = SDL_TOUCH_MOUSEID;
SDL_PushEvent(&ev);
port[i] = 0;
@ -459,25 +464,3 @@ void finish_simulated_mouse_clicks(int currentMouseX, int currentMouseY)
}
} // namespace devilution
static void SetMouseButtonEvent(SDL_Event *event, uint32_t type, uint8_t button, int32_t x, int32_t y)
{
event->type = type;
event->button.button = button;
if (type == SDL_MOUSEBUTTONDOWN) {
event->button.state = SDL_PRESSED;
} else {
event->button.state = SDL_RELEASED;
}
event->button.x = x;
event->button.y = y;
}
static void SetMouseMotionEvent(SDL_Event *event, int32_t x, int32_t y, int32_t xrel, int32_t yrel)
{
event->type = SDL_MOUSEMOTION;
event->motion.x = x;
event->motion.y = y;
event->motion.xrel = xrel;
event->motion.yrel = yrel;
}

6
Source/platform/vita/touch.h

@ -4,10 +4,12 @@
#include <SDL.h>
#include "engine/point.hpp"
namespace devilution {
void handle_touch(SDL_Event *event, int currentMouseX, int currentMouseY);
void finish_simulated_mouse_clicks(int currentMouseX, int currentMouseY);
void HandleTouchEvent(SDL_Event *event, Point mousePosition);
void FinishSimulatedMouseClicks(Point mousePosition);
} // namespace devilution

5
Source/player.cpp

@ -7,6 +7,7 @@
#include <cstdint>
#include "control.h"
#include "controls/plrctrls.h"
#include "cursor.h"
#include "dead.h"
#ifdef _DEBUG
@ -2559,7 +2560,7 @@ void NextPlrLevel(int pnum)
drawmanaflag = true;
}
if (sgbControllerActive)
if (ControlMode != ControlTypes::KeyboardAndMouse)
FocusOnCharInfo();
CalcPlrInv(player, true);
@ -3393,7 +3394,7 @@ void CheckPlrSpell(bool isShiftHeld, spell_id spellID, spell_type spellType)
return;
}
if (!sgbControllerActive) {
if (ControlMode == ControlTypes::KeyboardAndMouse) {
if (pcurs != CURSOR_HAND)
return;

9
Source/scrollrt.cpp

@ -6,6 +6,7 @@
#include "DiabloUI/ui_flags.hpp"
#include "automap.h"
#include "controls/plrctrls.h"
#include "controls/touch/renderers.h"
#include "cursor.h"
#include "dead.h"
@ -246,9 +247,7 @@ void UndrawCursor(const Surface &out)
bool ShouldShowCursor()
{
if (!sgbControllerActive && !sgbTouchActive)
return true;
if (IsMovingMouseCursorWithController())
if (ControlMode == ControlTypes::KeyboardAndMouse)
return true;
if (pcurs == CURSOR_TELEPORT)
return true;
@ -1274,12 +1273,10 @@ void DrawView(const Surface &out, Point startPosition)
} else if (QuestLogIsOpen) {
DrawQuestLog(out);
}
#ifndef VIRTUAL_GAMEPAD
if (!chrflag && Players[MyPlayerId]._pStatPts != 0 && !spselflag
if (ControlMode != ControlTypes::VirtualGamepad && !chrflag && Players[MyPlayerId]._pStatPts != 0 && !spselflag
&& (!QuestLogIsOpen || !GetLeftPanel().Contains(GetMainPanel().position + Displacement { 0, -74 }))) {
DrawLevelUpIcon(out);
}
#endif
if (ShowUniqueItemInfoBox) {
DrawUniqueInfo(out);
}

5
Source/scrollrt.h

@ -25,11 +25,6 @@ enum class ScrollDirection : uint8_t {
NorthWest,
};
// Defined in SourceX/controls/plctrls.cpp
extern bool sgbControllerActive;
extern bool sgbTouchActive;
extern bool IsMovingMouseCursorWithController();
extern int LightTableIndex;
extern uint32_t level_cel_block;
extern char arch_draw_type;

3
Source/trigs.cpp

@ -8,6 +8,7 @@
#include <fmt/format.h>
#include "control.h"
#include "controls/plrctrls.h"
#include "cursor.h"
#include "error.h"
#include "init.h"
@ -749,7 +750,7 @@ void CheckTrigForce()
{
trigflag = false;
if (!sgbControllerActive && GetMainPanel().Contains(MousePosition)) {
if (ControlMode == ControlTypes::KeyboardAndMouse && GetMainPanel().Contains(MousePosition)) {
return;
}

10
Source/utils/display.cpp

@ -13,7 +13,9 @@
#include "DiabloUI/diabloui.h"
#include "control.h"
#include "controls/controller.h"
#ifndef USE_SDL1
#include "controls/devices/game_controller.h"
#endif
#include "controls/devices/joystick.h"
#include "controls/devices/kbcontroller.h"
#include "controls/game_controls.h"
@ -186,6 +188,9 @@ bool SpawnWindow(const char *lpWindowName)
#if SDL_VERSION_ATLEAST(2, 0, 10)
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
#endif
#if SDL_VERSION_ATLEAST(2, 0, 2)
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
#endif
#if defined(_WIN32) && !defined(USE_SDL1)
// The default WASAPI backend causes distortions
@ -405,14 +410,11 @@ void ResizeWindow()
#ifndef USE_SDL1
SDL_SetWindowResizable(ghMainWnd, renderer != nullptr ? SDL_TRUE : SDL_FALSE);
InitializeVirtualGamepad();
#endif
CreateBackBuffer();
force_redraw = 255;
#ifdef VIRTUAL_GAMEPAD
InitializeVirtualGamepad();
#endif
}
SDL_Surface *GetOutputSurface()

Loading…
Cancel
Save