1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-03 13:01:33 +02:00

Minor refactoring of mouse input handling

This commit is contained in:
Ivan Savenko 2023-05-26 15:55:31 +03:00
parent 526ce1b546
commit 34123c7f07
9 changed files with 86 additions and 93 deletions

View File

@ -37,8 +37,6 @@ InputHandler::InputHandler()
, fingerHandler(std::make_unique<InputSourceTouch>()) , fingerHandler(std::make_unique<InputSourceTouch>())
, textHandler(std::make_unique<InputSourceText>()) , textHandler(std::make_unique<InputSourceText>())
, userHandler(std::make_unique<UserEventHandler>()) , userHandler(std::make_unique<UserEventHandler>())
, mouseButtonsMask(0)
, pointerSpeedMultiplier(settings["general"]["relativePointerSpeedMultiplier"].Float())
{ {
} }
@ -77,14 +75,8 @@ void InputHandler::processEvents()
{ {
boost::unique_lock<boost::mutex> lock(eventsMutex); boost::unique_lock<boost::mutex> lock(eventsMutex);
for (auto const & currentEvent : eventsQueue) for (auto const & currentEvent : eventsQueue)
{
if (currentEvent.type == SDL_MOUSEMOTION)
{
cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
mouseButtonsMask = currentEvent.motion.state;
}
handleCurrentEvent(currentEvent); handleCurrentEvent(currentEvent);
}
eventsQueue.clear(); eventsQueue.clear();
} }
@ -211,25 +203,15 @@ bool InputHandler::isKeyboardShiftDown() const
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT]; return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
} }
void InputHandler::moveCursorPosition(const Point & distance)
void InputHandler::fakeMoveCursor(float dx, float dy)
{ {
int x, y, w, h; setCursorPosition(getCursorPosition() + distance);
}
SDL_Event event; void InputHandler::setCursorPosition(const Point & position)
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0}; {
cursorPosition = position;
sme.state = SDL_GetMouseState(&x, &y); GH.events().dispatchMouseMoved(position);
SDL_GetWindowSize(mainWindow, &w, &h);
sme.x = GH.getCursorPosition().x + (int)(pointerSpeedMultiplier * w * dx);
sme.y = GH.getCursorPosition().y + (int)(pointerSpeedMultiplier * h * dy);
vstd::abetween(sme.x, 0, w);
vstd::abetween(sme.y, 0, h);
event.motion = sme;
SDL_PushEvent(&event);
} }
void InputHandler::startTextInput(const Rect & where) void InputHandler::startTextInput(const Rect & where)
@ -244,14 +226,7 @@ void InputHandler::stopTextInput()
bool InputHandler::isMouseButtonPressed(MouseButton button) const bool InputHandler::isMouseButtonPressed(MouseButton button) const
{ {
static_assert(static_cast<uint32_t>(MouseButton::LEFT) == SDL_BUTTON_LEFT, "mismatch between VCMI and SDL enum!"); return mouseHandler->isMouseButtonPressed(button) || fingerHandler->isMouseButtonPressed(button);
static_assert(static_cast<uint32_t>(MouseButton::MIDDLE) == SDL_BUTTON_MIDDLE, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::RIGHT) == SDL_BUTTON_RIGHT, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::EXTRA1) == SDL_BUTTON_X1, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::EXTRA2) == SDL_BUTTON_X2, "mismatch between VCMI and SDL enum!");
uint32_t index = static_cast<uint32_t>(button);
return mouseButtonsMask & SDL_BUTTON(index);
} }
void InputHandler::pushUserEvent(EUserEvent usercode, void * userdata) void InputHandler::pushUserEvent(EUserEvent usercode, void * userdata)

View File

@ -28,8 +28,6 @@ class InputHandler
boost::mutex eventsMutex; boost::mutex eventsMutex;
Point cursorPosition; Point cursorPosition;
float pointerSpeedMultiplier;
int mouseButtonsMask;
void preprocessEvent(const SDL_Event & event); void preprocessEvent(const SDL_Event & event);
void handleCurrentEvent(const SDL_Event & current); void handleCurrentEvent(const SDL_Event & current);
@ -53,7 +51,11 @@ public:
/// returns true if input event has been found /// returns true if input event has been found
bool ignoreEventsUntilInput(); bool ignoreEventsUntilInput();
void fakeMoveCursor(float dx, float dy); /// Moves cursor by specified distance
void moveCursorPosition(const Point & distance);
/// Moves cursor to a specified position
void setCursorPosition(const Point & position);
/// Initiates text input in selected area, potentially creating IME popup (mobile systems only at the moment) /// Initiates text input in selected area, potentially creating IME popup (mobile systems only at the moment)
void startTextInput(const Rect & where); void startTextInput(const Rect & where);

View File

@ -10,6 +10,7 @@
#include "StdInc.h" #include "StdInc.h"
#include "InputSourceMouse.h" #include "InputSourceMouse.h"
#include "InputHandler.h"
#include "../../lib/Point.h" #include "../../lib/Point.h"
#include "../gui/CGuiHandler.h" #include "../gui/CGuiHandler.h"
@ -20,7 +21,12 @@
void InputSourceMouse::handleEventMouseMotion(const SDL_MouseMotionEvent & motion) void InputSourceMouse::handleEventMouseMotion(const SDL_MouseMotionEvent & motion)
{ {
GH.events().dispatchMouseMoved(Point(motion.x, motion.y)); Point newPosition(motion.x, motion.y);
GH.input().setCursorPosition(newPosition);
mouseButtonsMask = motion.state;
} }
void InputSourceMouse::handleEventMouseButtonDown(const SDL_MouseButtonEvent & button) void InputSourceMouse::handleEventMouseButtonDown(const SDL_MouseButtonEvent & button)
@ -70,3 +76,15 @@ void InputSourceMouse::handleEventMouseButtonUp(const SDL_MouseButtonEvent & but
break; break;
} }
} }
bool InputSourceMouse::isMouseButtonPressed(MouseButton button) const
{
static_assert(static_cast<uint32_t>(MouseButton::LEFT) == SDL_BUTTON_LEFT, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::MIDDLE) == SDL_BUTTON_MIDDLE, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::RIGHT) == SDL_BUTTON_RIGHT, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::EXTRA1) == SDL_BUTTON_X1, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::EXTRA2) == SDL_BUTTON_X2, "mismatch between VCMI and SDL enum!");
uint32_t index = static_cast<uint32_t>(button);
return mouseButtonsMask & SDL_BUTTON(index);
}

View File

@ -14,12 +14,17 @@ struct SDL_MouseWheelEvent;
struct SDL_MouseMotionEvent; struct SDL_MouseMotionEvent;
struct SDL_MouseButtonEvent; struct SDL_MouseButtonEvent;
enum class MouseButton;
/// Class that handles mouse input from SDL events /// Class that handles mouse input from SDL events
class InputSourceMouse class InputSourceMouse
{ {
int mouseButtonsMask = 0;
public: public:
void handleEventMouseMotion(const SDL_MouseMotionEvent & current); void handleEventMouseMotion(const SDL_MouseMotionEvent & current);
void handleEventMouseButtonDown(const SDL_MouseButtonEvent & current); void handleEventMouseButtonDown(const SDL_MouseButtonEvent & current);
void handleEventMouseWheel(const SDL_MouseWheelEvent & current); void handleEventMouseWheel(const SDL_MouseWheelEvent & current);
void handleEventMouseButtonUp(const SDL_MouseButtonEvent & current); void handleEventMouseButtonUp(const SDL_MouseButtonEvent & current);
bool isMouseButtonPressed(MouseButton button) const;
}; };

View File

@ -26,6 +26,7 @@
InputSourceTouch::InputSourceTouch() InputSourceTouch::InputSourceTouch()
: multifinger(false) : multifinger(false)
, isPointerRelativeMode(settings["general"]["userRelativePointer"].Bool()) , isPointerRelativeMode(settings["general"]["userRelativePointer"].Bool())
, pointerSpeedMultiplier(settings["general"]["relativePointerSpeedMultiplier"].Float())
{ {
if(isPointerRelativeMode) if(isPointerRelativeMode)
{ {
@ -38,58 +39,73 @@ void InputSourceTouch::handleEventFingerMotion(const SDL_TouchFingerEvent & tfin
{ {
if(isPointerRelativeMode) if(isPointerRelativeMode)
{ {
GH.input().fakeMoveCursor(tfinger.dx, tfinger.dy); Point screenSize = GH.screenDimensions();
Point moveDistance {
static_cast<int>(screenSize.x * pointerSpeedMultiplier * tfinger.dx),
static_cast<int>(screenSize.y * pointerSpeedMultiplier * tfinger.dy)
};
GH.input().moveCursorPosition(moveDistance);
} }
} }
void InputSourceTouch::handleEventFingerDown(const SDL_TouchFingerEvent & tfinger) void InputSourceTouch::handleEventFingerDown(const SDL_TouchFingerEvent & tfinger)
{ {
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
multifinger = fingerCount > 1;
if(isPointerRelativeMode) if(isPointerRelativeMode)
{ {
if(tfinger.x > 0.5) if(tfinger.x > 0.5)
{ {
bool isRightClick = tfinger.y < 0.5; bool isRightClick = tfinger.y < 0.5;
fakeMouseButtonEventRelativeMode(true, isRightClick); if (isRightClick)
GH.events().dispatchMouseButtonPressed(MouseButton::RIGHT, GH.getCursorPosition());
else
GH.events().dispatchMouseButtonPressed(MouseButton::LEFT, GH.getCursorPosition());
} }
} }
#ifndef VCMI_IOS #ifndef VCMI_IOS
else if(fingerCount == 2) else
{ {
Point position = convertTouchToMouse(tfinger); auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
multifinger = fingerCount > 1;
GH.events().dispatchMouseMoved(position); if(fingerCount == 2)
GH.events().dispatchMouseButtonPressed(MouseButton::RIGHT, position); {
Point position = convertTouchToMouse(tfinger);
GH.input().setCursorPosition(position);
GH.events().dispatchMouseButtonPressed(MouseButton::RIGHT, position);
}
} }
#endif //VCMI_IOS #endif //VCMI_IOS
} }
void InputSourceTouch::handleEventFingerUp(const SDL_TouchFingerEvent & tfinger) void InputSourceTouch::handleEventFingerUp(const SDL_TouchFingerEvent & tfinger)
{ {
#ifndef VCMI_IOS
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
#endif //VCMI_IOS
if(isPointerRelativeMode) if(isPointerRelativeMode)
{ {
if(tfinger.x > 0.5) if(tfinger.x > 0.5)
{ {
bool isRightClick = tfinger.y < 0.5; bool isRightClick = tfinger.y < 0.5;
fakeMouseButtonEventRelativeMode(false, isRightClick); if (isRightClick)
GH.events().dispatchMouseButtonReleased(MouseButton::RIGHT, GH.getCursorPosition());
else
GH.events().dispatchMouseButtonReleased(MouseButton::LEFT, GH.getCursorPosition());
} }
} }
#ifndef VCMI_IOS #ifndef VCMI_IOS
else if(multifinger) else
{ {
Point position = convertTouchToMouse(tfinger); if(multifinger)
GH.events().dispatchMouseMoved(position); {
GH.events().dispatchMouseButtonReleased(MouseButton::RIGHT, position); auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
multifinger = fingerCount != 0; Point position = convertTouchToMouse(tfinger);
GH.input().setCursorPosition(position);
GH.events().dispatchMouseButtonReleased(MouseButton::RIGHT, position);
multifinger = fingerCount != 0;
}
} }
#endif //VCMI_IOS #endif //VCMI_IOS
} }
@ -99,37 +115,7 @@ Point InputSourceTouch::convertTouchToMouse(const SDL_TouchFingerEvent & tfinger
return Point(tfinger.x * GH.screenDimensions().x, tfinger.y * GH.screenDimensions().y); return Point(tfinger.x * GH.screenDimensions().x, tfinger.y * GH.screenDimensions().y);
} }
void InputSourceTouch::fakeMouseButtonEventRelativeMode(bool down, bool right) bool InputSourceTouch::isMouseButtonPressed(MouseButton button) const
{ {
SDL_Event event; return false;
SDL_MouseButtonEvent sme = {SDL_MOUSEBUTTONDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0};
if(!down)
{
sme.type = SDL_MOUSEBUTTONUP;
}
sme.button = right ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT;
sme.x = GH.getCursorPosition().x;
sme.y = GH.getCursorPosition().y;
float xScale, yScale;
int w, h, rLogicalWidth, rLogicalHeight;
SDL_GetWindowSize(mainWindow, &w, &h);
SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight);
SDL_RenderGetScale(mainRenderer, &xScale, &yScale);
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
moveCursorToPosition(Point((int)(sme.x * xScale) + (w - rLogicalWidth * xScale) / 2, (int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2)));
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
event.button = sme;
SDL_PushEvent(&event);
}
void InputSourceTouch::moveCursorToPosition(const Point & position)
{
SDL_WarpMouseInWindow(mainWindow, position.x, position.y);
} }

View File

@ -14,16 +14,16 @@ VCMI_LIB_NAMESPACE_BEGIN
class Point; class Point;
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END
enum class MouseButton;
struct SDL_TouchFingerEvent; struct SDL_TouchFingerEvent;
/// Class that handles touchscreen input from SDL events /// Class that handles touchscreen input from SDL events
class InputSourceTouch class InputSourceTouch
{ {
double pointerSpeedMultiplier;
bool multifinger; bool multifinger;
bool isPointerRelativeMode; bool isPointerRelativeMode;
/// moves mouse pointer into specified position inside vcmi window
void moveCursorToPosition(const Point & position);
Point convertTouchToMouse(const SDL_TouchFingerEvent & current); Point convertTouchToMouse(const SDL_TouchFingerEvent & current);
void fakeMouseButtonEventRelativeMode(bool down, bool right); void fakeMouseButtonEventRelativeMode(bool down, bool right);
@ -34,4 +34,6 @@ public:
void handleEventFingerMotion(const SDL_TouchFingerEvent & current); void handleEventFingerMotion(const SDL_TouchFingerEvent & current);
void handleEventFingerDown(const SDL_TouchFingerEvent & current); void handleEventFingerDown(const SDL_TouchFingerEvent & current);
void handleEventFingerUp(const SDL_TouchFingerEvent & current); void handleEventFingerUp(const SDL_TouchFingerEvent & current);
bool isMouseButtonPressed(MouseButton button) const;
}; };

View File

@ -18,6 +18,7 @@
#include "../gui/WindowHandler.h" #include "../gui/WindowHandler.h"
#include "../mainmenu/CMainMenu.h" #include "../mainmenu/CMainMenu.h"
#include "../mainmenu/CPrologEpilogVideo.h" #include "../mainmenu/CPrologEpilogVideo.h"
#include "../gui/EventDispatcher.h"
#include <SDL_events.h> #include <SDL_events.h>
@ -80,6 +81,9 @@ void UserEventHandler::handleUserEvent(const SDL_UserEvent & user)
GH.onScreenResize(); GH.onScreenResize();
break; break;
} }
case EUserEvent::FAKE_MOUSE_MOVE:
GH.events().dispatchMouseMoved(GH.getCursorPosition());
break;
default: default:
logGlobal->error("Unknown user event. Code %d", user.code); logGlobal->error("Unknown user event. Code %d", user.code);
break; break;

View File

@ -87,7 +87,7 @@ void CGuiHandler::handleEvents()
void CGuiHandler::fakeMouseMove() void CGuiHandler::fakeMouseMove()
{ {
input().fakeMoveCursor(0, 0); pushUserEvent(EUserEvent::FAKE_MOUSE_MOVE);
} }
void CGuiHandler::startTextInput(const Rect & whereInput) void CGuiHandler::startTextInput(const Rect & whereInput)

View File

@ -36,6 +36,7 @@ enum class EUserEvent
FULLSCREEN_TOGGLED, FULLSCREEN_TOGGLED,
CAMPAIGN_START_SCENARIO, CAMPAIGN_START_SCENARIO,
FORCE_QUIT, FORCE_QUIT,
FAKE_MOUSE_MOVE,
}; };
// Handles GUI logic and drawing // Handles GUI logic and drawing