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>())
, textHandler(std::make_unique<InputSourceText>())
, 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);
for (auto const & currentEvent : eventsQueue)
{
if (currentEvent.type == SDL_MOUSEMOTION)
{
cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
mouseButtonsMask = currentEvent.motion.state;
}
handleCurrentEvent(currentEvent);
}
eventsQueue.clear();
}
@ -211,25 +203,15 @@ bool InputHandler::isKeyboardShiftDown() const
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
}
void InputHandler::fakeMoveCursor(float dx, float dy)
void InputHandler::moveCursorPosition(const Point & distance)
{
int x, y, w, h;
setCursorPosition(getCursorPosition() + distance);
}
SDL_Event event;
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
sme.state = SDL_GetMouseState(&x, &y);
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::setCursorPosition(const Point & position)
{
cursorPosition = position;
GH.events().dispatchMouseMoved(position);
}
void InputHandler::startTextInput(const Rect & where)
@ -244,14 +226,7 @@ void InputHandler::stopTextInput()
bool InputHandler::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);
return mouseHandler->isMouseButtonPressed(button) || fingerHandler->isMouseButtonPressed(button);
}
void InputHandler::pushUserEvent(EUserEvent usercode, void * userdata)

View File

@ -28,8 +28,6 @@ class InputHandler
boost::mutex eventsMutex;
Point cursorPosition;
float pointerSpeedMultiplier;
int mouseButtonsMask;
void preprocessEvent(const SDL_Event & event);
void handleCurrentEvent(const SDL_Event & current);
@ -53,7 +51,11 @@ public:
/// returns true if input event has been found
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)
void startTextInput(const Rect & where);

View File

@ -10,6 +10,7 @@
#include "StdInc.h"
#include "InputSourceMouse.h"
#include "InputHandler.h"
#include "../../lib/Point.h"
#include "../gui/CGuiHandler.h"
@ -20,7 +21,12 @@
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)
@ -70,3 +76,15 @@ void InputSourceMouse::handleEventMouseButtonUp(const SDL_MouseButtonEvent & but
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_MouseButtonEvent;
enum class MouseButton;
/// Class that handles mouse input from SDL events
class InputSourceMouse
{
int mouseButtonsMask = 0;
public:
void handleEventMouseMotion(const SDL_MouseMotionEvent & current);
void handleEventMouseButtonDown(const SDL_MouseButtonEvent & current);
void handleEventMouseWheel(const SDL_MouseWheelEvent & current);
void handleEventMouseButtonUp(const SDL_MouseButtonEvent & current);
bool isMouseButtonPressed(MouseButton button) const;
};

View File

@ -26,6 +26,7 @@
InputSourceTouch::InputSourceTouch()
: multifinger(false)
, isPointerRelativeMode(settings["general"]["userRelativePointer"].Bool())
, pointerSpeedMultiplier(settings["general"]["relativePointerSpeedMultiplier"].Float())
{
if(isPointerRelativeMode)
{
@ -38,58 +39,73 @@ void InputSourceTouch::handleEventFingerMotion(const SDL_TouchFingerEvent & tfin
{
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)
{
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
multifinger = fingerCount > 1;
if(isPointerRelativeMode)
{
if(tfinger.x > 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
else if(fingerCount == 2)
else
{
Point position = convertTouchToMouse(tfinger);
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
multifinger = fingerCount > 1;
GH.events().dispatchMouseMoved(position);
GH.events().dispatchMouseButtonPressed(MouseButton::RIGHT, position);
if(fingerCount == 2)
{
Point position = convertTouchToMouse(tfinger);
GH.input().setCursorPosition(position);
GH.events().dispatchMouseButtonPressed(MouseButton::RIGHT, position);
}
}
#endif //VCMI_IOS
}
void InputSourceTouch::handleEventFingerUp(const SDL_TouchFingerEvent & tfinger)
{
#ifndef VCMI_IOS
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
#endif //VCMI_IOS
if(isPointerRelativeMode)
{
if(tfinger.x > 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
else if(multifinger)
else
{
Point position = convertTouchToMouse(tfinger);
GH.events().dispatchMouseMoved(position);
GH.events().dispatchMouseButtonReleased(MouseButton::RIGHT, position);
multifinger = fingerCount != 0;
if(multifinger)
{
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
Point position = convertTouchToMouse(tfinger);
GH.input().setCursorPosition(position);
GH.events().dispatchMouseButtonReleased(MouseButton::RIGHT, position);
multifinger = fingerCount != 0;
}
}
#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);
}
void InputSourceTouch::fakeMouseButtonEventRelativeMode(bool down, bool right)
bool InputSourceTouch::isMouseButtonPressed(MouseButton button) const
{
SDL_Event event;
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);
return false;
}

View File

@ -14,16 +14,16 @@ VCMI_LIB_NAMESPACE_BEGIN
class Point;
VCMI_LIB_NAMESPACE_END
enum class MouseButton;
struct SDL_TouchFingerEvent;
/// Class that handles touchscreen input from SDL events
class InputSourceTouch
{
double pointerSpeedMultiplier;
bool multifinger;
bool isPointerRelativeMode;
/// moves mouse pointer into specified position inside vcmi window
void moveCursorToPosition(const Point & position);
Point convertTouchToMouse(const SDL_TouchFingerEvent & current);
void fakeMouseButtonEventRelativeMode(bool down, bool right);
@ -34,4 +34,6 @@ public:
void handleEventFingerMotion(const SDL_TouchFingerEvent & current);
void handleEventFingerDown(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 "../mainmenu/CMainMenu.h"
#include "../mainmenu/CPrologEpilogVideo.h"
#include "../gui/EventDispatcher.h"
#include <SDL_events.h>
@ -80,6 +81,9 @@ void UserEventHandler::handleUserEvent(const SDL_UserEvent & user)
GH.onScreenResize();
break;
}
case EUserEvent::FAKE_MOUSE_MOVE:
GH.events().dispatchMouseMoved(GH.getCursorPosition());
break;
default:
logGlobal->error("Unknown user event. Code %d", user.code);
break;

View File

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

View File

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