Skip to content

Commit

Permalink
BACKENDS: Do not send mouse events to games occurring outside the gam…
Browse files Browse the repository at this point in the history
…e draw rect
  • Loading branch information
csnover committed Oct 15, 2017
1 parent 319ab07 commit cd538ff
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 27 deletions.
36 changes: 19 additions & 17 deletions backends/events/sdl/sdl-events.cpp
Expand Up @@ -169,13 +169,15 @@ int SdlEventSource::mapKey(SDLKey sdlKey, SDLMod mod, Uint16 unicode) {
}
}

void SdlEventSource::processMouseEvent(Common::Event &event, int x, int y) {
bool SdlEventSource::processMouseEvent(Common::Event &event, int x, int y) {
event.mouse.x = x;
event.mouse.y = y;

if (_graphicsManager) {
_graphicsManager->notifyMousePosition(event.mouse);
return _graphicsManager->notifyMousePosition(event.mouse);
}

return true;
}

bool SdlEventSource::handleKbdMouse(Common::Event &event) {
Expand Down Expand Up @@ -307,8 +309,7 @@ bool SdlEventSource::handleKbdMouse(Common::Event &event) {

if (_km.x != oldKmX || _km.y != oldKmY) {
event.type = Common::EVENT_MOUSEMOVE;
processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
return true;
return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
}
}
}
Expand Down Expand Up @@ -548,7 +549,9 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
// with a mouse wheel event. However, SDL2 does not supply
// these, thus we use whatever we got last time. It seems
// these are always stored in _km.x, _km.y.
processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
if (!processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER)) {
return false;
}
if (yDir < 0) {
event.type = Common::EVENT_WHEELDOWN;
return true;
Expand Down Expand Up @@ -739,12 +742,12 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {

bool SdlEventSource::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
event.type = Common::EVENT_MOUSEMOVE;
processMouseEvent(event, ev.motion.x, ev.motion.y);

// update KbdMouse
_km.x = ev.motion.x * MULTIPLIER;
_km.y = ev.motion.y * MULTIPLIER;

return true;
return processMouseEvent(event, ev.motion.x, ev.motion.y);
}

bool SdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
Expand All @@ -765,12 +768,11 @@ bool SdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event)
else
return false;

processMouseEvent(event, ev.button.x, ev.button.y);
// update KbdMouse
_km.x = ev.button.x * MULTIPLIER;
_km.y = ev.button.y * MULTIPLIER;

return true;
return processMouseEvent(event, ev.button.x, ev.button.y);
}

bool SdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
Expand All @@ -784,21 +786,21 @@ bool SdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
#endif
else
return false;
processMouseEvent(event, ev.button.x, ev.button.y);

// update KbdMouse
_km.x = ev.button.x * MULTIPLIER;
_km.y = ev.button.y * MULTIPLIER;

return true;
return processMouseEvent(event, ev.button.x, ev.button.y);
}

bool SdlEventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
if (ev.jbutton.button == JOY_BUT_LMOUSE) {
event.type = Common::EVENT_LBUTTONDOWN;
processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
} else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
event.type = Common::EVENT_RBUTTONDOWN;
processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
} else {
event.type = Common::EVENT_KEYDOWN;
switch (ev.jbutton.button) {
Expand All @@ -819,17 +821,17 @@ bool SdlEventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
event.kbd.ascii = mapKey(SDLK_F5, (SDLMod)ev.key.keysym.mod, 0);
break;
}
return true;
}
return true;
}

bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
if (ev.jbutton.button == JOY_BUT_LMOUSE) {
event.type = Common::EVENT_LBUTTONUP;
processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
} else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
event.type = Common::EVENT_RBUTTONUP;
processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
} else {
event.type = Common::EVENT_KEYUP;
switch (ev.jbutton.button) {
Expand All @@ -850,8 +852,8 @@ bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
event.kbd.ascii = mapKey(SDLK_F5, (SDLMod)ev.key.keysym.mod, 0);
break;
}
return true;
}
return true;
}

bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
Expand Down
2 changes: 1 addition & 1 deletion backends/events/sdl/sdl-events.h
Expand Up @@ -117,7 +117,7 @@ class SdlEventSource : public Common::EventSource {
* Assigns the mouse coords to the mouse event. Furthermore notify the
* graphics manager about the position change.
*/
virtual void processMouseEvent(Common::Event &event, int x, int y);
virtual bool processMouseEvent(Common::Event &event, int x, int y);

/**
* Remaps key events. This allows platforms to configure
Expand Down
39 changes: 32 additions & 7 deletions backends/graphics/sdl/sdl-graphics.cpp
Expand Up @@ -169,22 +169,47 @@ bool SdlGraphicsManager::showMouse(const bool visible) {
return WindowedGraphicsManager::showMouse(visible);
}

void SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) {
bool SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) {
int showCursor = SDL_DISABLE;
if (!_activeArea.drawRect.contains(mouse)) {
bool valid = true;
if (_activeArea.drawRect.contains(mouse)) {
_cursorLastInActiveArea = true;
} else {
mouse.x = CLIP<int>(mouse.x, _activeArea.drawRect.left, _activeArea.drawRect.right - 1);
mouse.y = CLIP<int>(mouse.y, _activeArea.drawRect.top, _activeArea.drawRect.bottom - 1);

if (_window->mouseIsGrabbed()) {
if (_window->mouseIsGrabbed() ||
// Keep the mouse inside the game area during dragging to prevent an
// event mismatch where the mouseup event gets lost because it is
// performed outside of the game area
(_cursorLastInActiveArea && SDL_GetMouseState(nullptr, nullptr) != 0)) {
setSystemMousePosition(mouse.x, mouse.y);
} else if (_cursorVisible) {
showCursor = SDL_ENABLE;
} else {
// Allow the in-game mouse to get a final movement event to the edge
// of the window if the mouse was moved out of the game area
if (_cursorLastInActiveArea) {
_cursorLastInActiveArea = false;
} else if (_cursorVisible) {
// Keep sending events to the game if the cursor is invisible,
// since otherwise if a game lets you skip a cutscene by
// clicking and the user moved the mouse outside the active
// area, the clicks wouldn't do anything, which would be
// confusing
valid = false;
}

if (_cursorVisible) {
showCursor = SDL_ENABLE;
}
}
}

SDL_ShowCursor(showCursor);
setMousePosition(mouse.x, mouse.y);
mouse = convertWindowToVirtual(mouse.x, mouse.y);
if (valid) {
setMousePosition(mouse.x, mouse.y);
mouse = convertWindowToVirtual(mouse.x, mouse.y);
}
return valid;
}

void SdlGraphicsManager::handleResizeImpl(const int width, const int height) {
Expand Down
4 changes: 3 additions & 1 deletion backends/graphics/sdl/sdl-graphics.h
Expand Up @@ -84,8 +84,10 @@ class SdlGraphicsManager : virtual public WindowedGraphicsManager {
*
* @param mouse The mouse position in window coordinates, which must be
* converted synchronously to virtual coordinates.
* @returns true if the mouse was in a valid position for the game and
* should cause the event to be sent to the game.
*/
virtual void notifyMousePosition(Common::Point &mouse);
virtual bool notifyMousePosition(Common::Point &mouse);

virtual bool showMouse(const bool visible) override;

Expand Down
9 changes: 8 additions & 1 deletion backends/graphics/windowed.h
Expand Up @@ -39,7 +39,8 @@ class WindowedGraphicsManager : virtual public GraphicsManager {
_cursorVisible(false),
_cursorX(0),
_cursorY(0),
_cursorNeedsRedraw(false) {}
_cursorNeedsRedraw(false),
_cursorLastInActiveArea(true) {}

virtual void showOverlay() override {
if (_overlayVisible)
Expand Down Expand Up @@ -303,6 +304,12 @@ class WindowedGraphicsManager : virtual public GraphicsManager {
*/
bool _cursorNeedsRedraw;

/**
* Whether the last position of the system cursor was within the active area
* of the window.
*/
bool _cursorLastInActiveArea;

/**
* The position of the mouse cursor, in window coordinates.
*/
Expand Down

0 comments on commit cd538ff

Please sign in to comment.