From 912e51d863589a0a82e31511cb142f0a56bedcfc Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 12 Jul 2020 15:03:08 -0700 Subject: [PATCH] Synchronize the client and host cursor when starting absolute mode capture --- app/streaming/input/input.cpp | 19 +++++++++++++ app/streaming/input/input.h | 4 +++ app/streaming/input/mouse.cpp | 52 +++++++++++++++++++++++++++-------- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/app/streaming/input/input.cpp b/app/streaming/input/input.cpp index 0679f9bb..f962eece 100644 --- a/app/streaming/input/input.cpp +++ b/app/streaming/input/input.cpp @@ -261,6 +261,25 @@ void SdlInputHandler::setCaptureActive(bool active) SDL_ShowCursor(SDL_DISABLE); m_FakeCaptureActive = true; } + + // Synchronize the client and host cursor when activating absolute capture + if (m_AbsoluteMouseMode) { + int mouseX, mouseY; + int windowX, windowY; + + // We have to use SDL_GetGlobalMouseState() because macOS may not reflect + // the new position of the mouse when outside the window. + SDL_GetGlobalMouseState(&mouseX, &mouseY); + + // Convert global mouse state to window-relative + SDL_GetWindowPosition(m_Window, &windowX, &windowY); + mouseX -= windowX; + mouseY -= windowY; + + if (isMouseInVideoRegion(mouseX, mouseY)) { + updateMousePositionReport(mouseX, mouseY); + } + } } else { if (m_FakeCaptureActive) { diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index f3d4432b..4cf55cf7 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -77,6 +77,10 @@ public: void setCaptureActive(bool active); + bool isMouseInVideoRegion(int mouseX, int mouseY, int windowWidth = -1, int windowHeight = -1); + + void updateMousePositionReport(int mouseX, int mouseY); + static QString getUnmappedGamepads(); diff --git a/app/streaming/input/mouse.cpp b/app/streaming/input/mouse.cpp index 3649ed3c..3adc4360 100644 --- a/app/streaming/input/mouse.cpp +++ b/app/streaming/input/mouse.cpp @@ -56,6 +56,22 @@ void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event) button); } +void SdlInputHandler::updateMousePositionReport(int mouseX, int mouseY) +{ + int windowWidth, windowHeight; + + // Call SDL_GetWindowSize() before entering the spinlock + SDL_GetWindowSize(m_Window, &windowWidth, &windowHeight); + + SDL_AtomicLock(&m_MousePositionLock); + m_MousePositionReport.x = mouseX; + m_MousePositionReport.y = mouseY; + m_MousePositionReport.windowWidth = windowWidth; + m_MousePositionReport.windowHeight = windowHeight; + SDL_AtomicUnlock(&m_MousePositionLock); + SDL_AtomicSet(&m_MousePositionUpdated, 1); +} + void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event) { if (!isCaptureActive()) { @@ -70,18 +86,7 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event) // Batch until the next mouse polling window or we'll get awful // input lag everything except GFE 3.14 and 3.15. if (m_AbsoluteMouseMode) { - int windowWidth, windowHeight; - - // Call SDL_GetWindowSize() before entering the spinlock - SDL_GetWindowSize(m_Window, &windowWidth, &windowHeight); - - SDL_AtomicLock(&m_MousePositionLock); - m_MousePositionReport.x = event->x; - m_MousePositionReport.y = event->y; - m_MousePositionReport.windowWidth = windowWidth; - m_MousePositionReport.windowHeight = windowHeight; - SDL_AtomicUnlock(&m_MousePositionLock); - SDL_AtomicSet(&m_MousePositionUpdated, 1); + updateMousePositionReport(event->x, event->y); } else { SDL_AtomicAdd(&m_MouseDeltaX, event->xrel); @@ -105,6 +110,29 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event) } } +bool SdlInputHandler::isMouseInVideoRegion(int mouseX, int mouseY, int windowWidth, int windowHeight) +{ + SDL_Rect src, dst; + + if (windowWidth < 0 || windowHeight < 0) { + SDL_GetWindowSize(m_Window, &windowWidth, &windowHeight); + } + + src.x = src.y = 0; + src.w = m_StreamWidth; + src.h = m_StreamHeight; + + dst.x = dst.y = 0; + dst.w = windowWidth; + dst.h = windowHeight; + + // Use the stream and window sizes to determine the video region + StreamUtils::scaleSourceToDestinationSurface(&src, &dst); + + return (mouseX >= dst.x && mouseX <= dst.x + dst.w) && + (mouseY >= dst.y && mouseY <= dst.y + dst.h); +} + Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param) { auto me = reinterpret_cast(param);