BACKENDS: Fix missing mouse events when system cursor cannot be moved
Normally with SDL, a mouse motion event will be sent after the system mouse cursor has been moved by a call to SDL_WarpMouseInWindow, but if the system cursor cannot be moved (e.g. because the window does not have mouse focus), games still need to receive these mouse events so they can successfully update the mouse position internally. Otherwise, games continue to think the mouse is still in the original position and will continue to try to perform whatever action is associated with that mouse position. Refs Trac#9689.
This commit is contained in:
parent
cd538ffffa
commit
d1b77d4b68
10 changed files with 80 additions and 7 deletions
|
@ -254,4 +254,30 @@ void DefaultEventManager::pushEvent(const Common::Event &event) {
|
|||
_artificialEventSource.addEvent(event);
|
||||
}
|
||||
|
||||
void DefaultEventManager::purgeMouseEvents() {
|
||||
_dispatcher.dispatch();
|
||||
|
||||
Common::Queue<Common::Event> filteredQueue;
|
||||
while (!_eventQueue.empty()) {
|
||||
Common::Event event = _eventQueue.pop();
|
||||
switch (event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
case Common::EVENT_WHEELUP:
|
||||
case Common::EVENT_WHEELDOWN:
|
||||
case Common::EVENT_MBUTTONDOWN:
|
||||
case Common::EVENT_MBUTTONUP:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
filteredQueue.push(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_eventQueue = filteredQueue;
|
||||
}
|
||||
|
||||
#endif // !defined(DISABLE_DEFAULT_EVENTMANAGER)
|
||||
|
|
|
@ -80,6 +80,7 @@ public:
|
|||
virtual void init();
|
||||
virtual bool pollEvent(Common::Event &event);
|
||||
virtual void pushEvent(const Common::Event &event);
|
||||
virtual void purgeMouseEvents() override;
|
||||
|
||||
virtual Common::Point getMousePos() const { return _mousePos; }
|
||||
virtual int getButtonState() const { return _buttonState; }
|
||||
|
|
|
@ -75,7 +75,7 @@ static uint32 convUTF8ToUTF32(const char *src) {
|
|||
#endif
|
||||
|
||||
SdlEventSource::SdlEventSource()
|
||||
: EventSource(), _scrollLock(false), _joystick(0), _lastScreenID(0), _graphicsManager(0)
|
||||
: EventSource(), _scrollLock(false), _joystick(0), _lastScreenID(0), _graphicsManager(0), _queuedFakeMouseMove(false)
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
, _queuedFakeKeyUp(false), _fakeKeyUp()
|
||||
#endif
|
||||
|
@ -508,6 +508,12 @@ bool SdlEventSource::pollEvent(Common::Event &event) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_queuedFakeMouseMove) {
|
||||
event = _fakeMouseMove;
|
||||
_queuedFakeMouseMove = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_Event ev;
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
preprocessEvents(&ev);
|
||||
|
@ -1003,6 +1009,12 @@ void SdlEventSource::resetKeyboardEmulation(int16 x_max, int16 y_max) {
|
|||
_km.joy_y = 0;
|
||||
}
|
||||
|
||||
void SdlEventSource::fakeWarpMouse(const int x, const int y) {
|
||||
_queuedFakeMouseMove = true;
|
||||
_fakeMouseMove.type = Common::EVENT_MOUSEMOVE;
|
||||
_fakeMouseMove.mouse = Common::Point(x, y);
|
||||
}
|
||||
|
||||
bool SdlEventSource::handleResizeEvent(Common::Event &event, int w, int h) {
|
||||
if (_graphicsManager) {
|
||||
_graphicsManager->notifyResize(w, h);
|
||||
|
|
|
@ -51,6 +51,12 @@ public:
|
|||
*/
|
||||
virtual void resetKeyboardEmulation(int16 x_max, int16 y_max);
|
||||
|
||||
/**
|
||||
* Emulates a mouse movement that would normally be caused by a mouse warp
|
||||
* of the system mouse.
|
||||
*/
|
||||
void fakeWarpMouse(const int x, const int y);
|
||||
|
||||
protected:
|
||||
/** @name Keyboard mouse emulation
|
||||
* Disabled by fingolfin 2004-12-18.
|
||||
|
@ -156,6 +162,18 @@ protected:
|
|||
*/
|
||||
SDLKey obtainKeycode(const SDL_keysym keySym);
|
||||
|
||||
/**
|
||||
* Whether _fakeMouseMove contains an event we need to send.
|
||||
*/
|
||||
bool _queuedFakeMouseMove;
|
||||
|
||||
/**
|
||||
* A fake mouse motion event sent when the graphics manager is told to warp
|
||||
* the mouse but the system mouse is unable to be warped (e.g. because the
|
||||
* window is not focused).
|
||||
*/
|
||||
Common::Event _fakeMouseMove;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
/**
|
||||
* Whether _fakeKeyUp contains an event we need to send.
|
||||
|
|
|
@ -212,6 +212,13 @@ bool SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) {
|
|||
return valid;
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::setSystemMousePosition(const int x, const int y) {
|
||||
assert(_window);
|
||||
if (!_window->warpMouseInWindow(x, y)) {
|
||||
_eventSource->fakeWarpMouse(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::handleResizeImpl(const int width, const int height) {
|
||||
_eventSource->resetKeyboardEmulation(width - 1, height - 1);
|
||||
_forceRedraw = true;
|
||||
|
|
|
@ -150,10 +150,7 @@ protected:
|
|||
#endif
|
||||
}
|
||||
|
||||
virtual void setSystemMousePosition(const int x, const int y) override {
|
||||
assert(_window);
|
||||
_window->warpMouseInWindow(x, y);
|
||||
}
|
||||
virtual void setSystemMousePosition(const int x, const int y) override;
|
||||
|
||||
virtual void handleResizeImpl(const int width, const int height) override;
|
||||
|
||||
|
|
|
@ -217,6 +217,7 @@ bool ModularBackend::showMouse(bool visible) {
|
|||
}
|
||||
|
||||
void ModularBackend::warpMouse(int x, int y) {
|
||||
_eventManager->purgeMouseEvents();
|
||||
_graphicsManager->warpMouse(x, y);
|
||||
}
|
||||
|
||||
|
|
|
@ -155,16 +155,20 @@ bool SdlWindow::hasMouseFocus() const {
|
|||
#endif
|
||||
}
|
||||
|
||||
void SdlWindow::warpMouseInWindow(int x, int y) {
|
||||
bool SdlWindow::warpMouseInWindow(int x, int y) {
|
||||
if (hasMouseFocus()) {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
if (_window) {
|
||||
SDL_WarpMouseInWindow(_window, x, y);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
SDL_WarpMouse(x, y);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SdlWindow::iconifyWindow() {
|
||||
|
|
|
@ -58,8 +58,10 @@ public:
|
|||
/**
|
||||
* Warp the mouse to the specified position in window coordinates. The mouse
|
||||
* will only be warped if the window is focused in the window manager.
|
||||
*
|
||||
* @returns true if the system cursor was warped.
|
||||
*/
|
||||
void warpMouseInWindow(int x, int y);
|
||||
bool warpMouseInWindow(int x, int y);
|
||||
|
||||
/**
|
||||
* Iconifies the window.
|
||||
|
|
|
@ -395,6 +395,11 @@ public:
|
|||
*/
|
||||
virtual void pushEvent(const Event &event) = 0;
|
||||
|
||||
/**
|
||||
* Purges all unprocessed mouse events already in the event queue.
|
||||
*/
|
||||
virtual void purgeMouseEvents() = 0;
|
||||
|
||||
/** Return the current mouse position */
|
||||
virtual Point getMousePos() const = 0;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue