mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-15 21:22:40 +00:00
Ignore mouse events outside the video region
This commit is contained in:
@@ -14,6 +14,8 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s
|
|||||||
m_GamepadMouse(prefs.gamepadMouse),
|
m_GamepadMouse(prefs.gamepadMouse),
|
||||||
m_MouseMoveTimer(0),
|
m_MouseMoveTimer(0),
|
||||||
m_MousePositionLock(0),
|
m_MousePositionLock(0),
|
||||||
|
m_MouseWasInVideoRegion(false),
|
||||||
|
m_PendingMouseButtonsAllUpOnVideoRegionLeave(false),
|
||||||
m_FakeCaptureActive(false),
|
m_FakeCaptureActive(false),
|
||||||
m_LongPressTimer(0),
|
m_LongPressTimer(0),
|
||||||
m_StreamWidth(streamWidth),
|
m_StreamWidth(streamWidth),
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#define SDL_CODE_HIDE_CURSOR 1
|
||||||
|
#define SDL_CODE_SHOW_CURSOR 2
|
||||||
|
|
||||||
struct GamepadState {
|
struct GamepadState {
|
||||||
SDL_GameController* controller;
|
SDL_GameController* controller;
|
||||||
SDL_JoystickID jsId;
|
SDL_JoystickID jsId;
|
||||||
@@ -125,6 +128,8 @@ private:
|
|||||||
int windowWidth, windowHeight;
|
int windowWidth, windowHeight;
|
||||||
} m_MousePositionReport;
|
} m_MousePositionReport;
|
||||||
SDL_atomic_t m_MousePositionUpdated;
|
SDL_atomic_t m_MousePositionUpdated;
|
||||||
|
bool m_MouseWasInVideoRegion;
|
||||||
|
bool m_PendingMouseButtonsAllUpOnVideoRegionLeave;
|
||||||
|
|
||||||
int m_GamepadMask;
|
int m_GamepadMask;
|
||||||
GamepadState m_GamepadState[MAX_GAMEPADS];
|
GamepadState m_GamepadState[MAX_GAMEPADS];
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!isCaptureActive()) {
|
else if (!isCaptureActive()) {
|
||||||
if (event->button == SDL_BUTTON_LEFT && event->state == SDL_RELEASED) {
|
if (event->button == SDL_BUTTON_LEFT && event->state == SDL_RELEASED &&
|
||||||
|
isMouseInVideoRegion(event->x, event->y)) {
|
||||||
// Capture the mouse again if clicked when unbound.
|
// Capture the mouse again if clicked when unbound.
|
||||||
// We start capture on left button released instead of
|
// We start capture on left button released instead of
|
||||||
// pressed to avoid sending an errant mouse button released
|
// pressed to avoid sending an errant mouse button released
|
||||||
@@ -25,6 +26,10 @@ void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
|
|||||||
// Not capturing
|
// Not capturing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (m_AbsoluteMouseMode && !isMouseInVideoRegion(event->x, event->y) && event->state == SDL_PRESSED) {
|
||||||
|
// Ignore button presses outside the video region, but allow button releases
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event->button)
|
switch (event->button)
|
||||||
{
|
{
|
||||||
@@ -105,6 +110,15 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_AbsoluteMouseMode) {
|
||||||
|
int mouseX, mouseY;
|
||||||
|
SDL_GetMouseState(&mouseX, &mouseY);
|
||||||
|
if (!isMouseInVideoRegion(mouseX, mouseY)) {
|
||||||
|
// Ignore scroll events outside the video region
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (event->y != 0) {
|
if (event->y != 0) {
|
||||||
LiSendScrollEvent((signed char)event->y);
|
LiSendScrollEvent((signed char)event->y);
|
||||||
}
|
}
|
||||||
@@ -150,6 +164,7 @@ Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param)
|
|||||||
// the mouse position. We'll pick up the new position next time.
|
// the mouse position. We'll pick up the new position next time.
|
||||||
if (SDL_AtomicTryLock(&me->m_MousePositionLock)) {
|
if (SDL_AtomicTryLock(&me->m_MousePositionLock)) {
|
||||||
SDL_Rect src, dst;
|
SDL_Rect src, dst;
|
||||||
|
bool mouseInVideoRegion;
|
||||||
|
|
||||||
src.x = src.y = 0;
|
src.x = src.y = 0;
|
||||||
src.w = me->m_StreamWidth;
|
src.w = me->m_StreamWidth;
|
||||||
@@ -162,6 +177,11 @@ Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param)
|
|||||||
// Use the stream and window sizes to determine the video region
|
// Use the stream and window sizes to determine the video region
|
||||||
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
||||||
|
|
||||||
|
mouseInVideoRegion = me->isMouseInVideoRegion(me->m_MousePositionReport.x,
|
||||||
|
me->m_MousePositionReport.y,
|
||||||
|
me->m_MousePositionReport.windowWidth,
|
||||||
|
me->m_MousePositionReport.windowHeight);
|
||||||
|
|
||||||
// Clamp motion to the video region
|
// Clamp motion to the video region
|
||||||
short x = qMin(qMax(me->m_MousePositionReport.x - dst.x, 0), dst.w);
|
short x = qMin(qMax(me->m_MousePositionReport.x - dst.x, 0), dst.w);
|
||||||
short y = qMin(qMax(me->m_MousePositionReport.y - dst.y, 0), dst.h);
|
short y = qMin(qMax(me->m_MousePositionReport.y - dst.y, 0), dst.h);
|
||||||
@@ -169,8 +189,36 @@ Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param)
|
|||||||
// Release the spinlock to unblock the main thread
|
// Release the spinlock to unblock the main thread
|
||||||
SDL_AtomicUnlock(&me->m_MousePositionLock);
|
SDL_AtomicUnlock(&me->m_MousePositionLock);
|
||||||
|
|
||||||
// Send the mouse position update
|
// Send the mouse position update if one of the following is true:
|
||||||
LiSendMousePositionEvent(x, y, dst.w, dst.h);
|
// a) it is in the video region now
|
||||||
|
// b) it just left the video region (to ensure the mouse is clamped to the video boundary)
|
||||||
|
// c) a mouse button is still down from before the cursor left the video region (to allow smooth dragging)
|
||||||
|
Uint32 buttonState = SDL_GetMouseState(nullptr, nullptr);
|
||||||
|
if (buttonState == 0) {
|
||||||
|
me->m_PendingMouseButtonsAllUpOnVideoRegionLeave = false;
|
||||||
|
}
|
||||||
|
if (mouseInVideoRegion || me->m_MouseWasInVideoRegion || me->m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
|
||||||
|
LiSendMousePositionEvent(x, y, dst.w, dst.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust the cursor visibility if applicable
|
||||||
|
if (mouseInVideoRegion ^ me->m_MouseWasInVideoRegion) {
|
||||||
|
// We must push an event for the main thread to process, because it's not safe
|
||||||
|
// to directly can SDL_ShowCursor() on the arbitrary thread on which this timer
|
||||||
|
// executes.
|
||||||
|
SDL_Event event;
|
||||||
|
event.type = SDL_USEREVENT;
|
||||||
|
event.user.code = mouseInVideoRegion ? SDL_CODE_HIDE_CURSOR : SDL_CODE_SHOW_CURSOR;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
|
||||||
|
if (!mouseInVideoRegion && buttonState != 0) {
|
||||||
|
// If we still have a button pressed on leave, wait for that to come up
|
||||||
|
// before we stop sending mouse position events.
|
||||||
|
me->m_PendingMouseButtonsAllUpOnVideoRegionLeave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
me->m_MouseWasInVideoRegion = mouseInVideoRegion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1195,8 +1195,19 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||||||
goto DispatchDeferredCleanup;
|
goto DispatchDeferredCleanup;
|
||||||
|
|
||||||
case SDL_USEREVENT:
|
case SDL_USEREVENT:
|
||||||
SDL_assert(event.user.code == SDL_CODE_FRAME_READY);
|
switch (event.user.code) {
|
||||||
m_VideoDecoder->renderFrameOnMainThread();
|
case SDL_CODE_FRAME_READY:
|
||||||
|
m_VideoDecoder->renderFrameOnMainThread();
|
||||||
|
break;
|
||||||
|
case SDL_CODE_HIDE_CURSOR:
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
break;
|
||||||
|
case SDL_CODE_SHOW_CURSOR:
|
||||||
|
SDL_ShowCursor(SDL_ENABLE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SDL_assert(false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
|
|||||||
Reference in New Issue
Block a user