diff --git a/app/streaming/input/input.cpp b/app/streaming/input/input.cpp index 3871215f..0588f10e 100644 --- a/app/streaming/input/input.cpp +++ b/app/streaming/input/input.cpp @@ -21,6 +21,7 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s m_MousePositionLock(0), m_MouseWasInVideoRegion(false), m_PendingMouseButtonsAllUpOnVideoRegionLeave(false), + m_PointerRegionLockActive(false), m_FakeCaptureActive(false), m_CaptureSystemKeysMode(prefs.captureSysKeysMode), m_MouseCursorCapturedVisibilityState(SDL_DISABLE), @@ -115,6 +116,11 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s m_SpecialKeyCombos[KeyComboPasteText].scanCode = SDL_SCANCODE_V; m_SpecialKeyCombos[KeyComboPasteText].enabled = true; + m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].keyCombo = KeyComboTogglePointerRegionLock; + m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].keyCode = SDLK_l; + m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].scanCode = SDL_SCANCODE_L; + m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].enabled = true; + m_OldIgnoreDevices = SDL_GetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES); m_OldIgnoreDevicesExcept = SDL_GetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT); @@ -389,15 +395,6 @@ bool SdlInputHandler::isSystemKeyCaptureActive() void SdlInputHandler::setCaptureActive(bool active) { if (active) { - // If we're in full-screen exclusive mode, grab the cursor so it can't accidentally leave our window. - if ((SDL_GetWindowFlags(m_Window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) { -#if SDL_VERSION_ATLEAST(2, 0, 15) - SDL_SetWindowMouseGrab(m_Window, SDL_TRUE); -#else - SDL_SetWindowGrab(m_Window, SDL_TRUE); -#endif - } - // If we're in relative mode, try to activate SDL's relative mouse mode if (m_AbsoluteMouseMode || SDL_SetRelativeMouseMode(SDL_TRUE) < 0) { // Relative mouse mode didn't work or was disabled, so we'll just hide the cursor @@ -433,16 +430,11 @@ void SdlInputHandler::setCaptureActive(bool active) else { SDL_SetRelativeMouseMode(SDL_FALSE); } - -#if SDL_VERSION_ATLEAST(2, 0, 15) - // Allow the cursor to leave the bounds of our window again. - SDL_SetWindowMouseGrab(m_Window, SDL_FALSE); -#else - // Allow the cursor to leave the bounds of our window again. - SDL_SetWindowGrab(m_Window, SDL_FALSE); -#endif } + // Update mouse pointer region constraints + updatePointerRegionLock(); + // Now update the keyboard grab updateKeyboardGrabState(); } diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 90c92146..12b7512c 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -93,6 +93,8 @@ public: void updateKeyboardGrabState(); + void updatePointerRegionLock(); + static QString getUnmappedGamepads(); @@ -106,6 +108,7 @@ private: KeyComboToggleCursorHide, KeyComboToggleMinimize, KeyComboPasteText, + KeyComboTogglePointerRegionLock, KeyComboMax }; @@ -156,6 +159,7 @@ private: SDL_atomic_t m_MousePositionUpdated; bool m_MouseWasInVideoRegion; bool m_PendingMouseButtonsAllUpOnVideoRegionLeave; + bool m_PointerRegionLockActive; int m_GamepadMask; GamepadState m_GamepadState[MAX_GAMEPADS]; diff --git a/app/streaming/input/keyboard.cpp b/app/streaming/input/keyboard.cpp index 5343ef33..7f82e094 100644 --- a/app/streaming/input/keyboard.cpp +++ b/app/streaming/input/keyboard.cpp @@ -126,6 +126,13 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo) break; } + case KeyComboTogglePointerRegionLock: + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "Detected pointer region lock toggle combo"); + m_PointerRegionLockActive = !m_PointerRegionLockActive; + updatePointerRegionLock(); + break; + default: Q_UNREACHABLE(); } diff --git a/app/streaming/input/mouse.cpp b/app/streaming/input/mouse.cpp index 5921525d..07dc6abd 100644 --- a/app/streaming/input/mouse.cpp +++ b/app/streaming/input/mouse.cpp @@ -272,3 +272,48 @@ Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param) return interval; } + +void SdlInputHandler::updatePointerRegionLock() +{ + // Pointer region lock is irrelevant in relative mouse mode + if (SDL_GetRelativeMouseMode()) { + return; + } + + // If we're in full-screen exclusive mode or region lock is enabled, grab the cursor so it can't accidentally leave our window. + if (isCaptureActive() && + (m_PointerRegionLockActive || + (SDL_GetWindowFlags(m_Window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN)) { +#if SDL_VERSION_ATLEAST(2, 0, 18) + SDL_Rect src, dst; + + src.x = src.y = 0; + src.w = m_StreamWidth; + src.h = m_StreamHeight; + + dst.x = dst.y = 0; + SDL_GetWindowSize(m_Window, &dst.w, &dst.h); + + // Use the stream and window sizes to determine the video region + StreamUtils::scaleSourceToDestinationSurface(&src, &dst); + + // SDL 2.0.18 lets us lock the cursor to a specific region + SDL_SetWindowMouseRect(m_Window, &dst); +#elif SDL_VERSION_ATLEAST(2, 0, 15) + // SDL 2.0.15 only lets us lock the cursor to the whole window + SDL_SetWindowMouseGrab(m_Window, SDL_TRUE); +#else + SDL_SetWindowGrab(m_Window, SDL_TRUE); +#endif + } + else { + // Allow the cursor to leave the bounds of our video region or window +#if SDL_VERSION_ATLEAST(2, 0, 18) + SDL_SetWindowMouseRect(m_Window, nullptr); +#elif SDL_VERSION_ATLEAST(2, 0, 15) + SDL_SetWindowMouseGrab(m_Window, SDL_FALSE); +#else + SDL_SetWindowGrab(m_Window, SDL_FALSE); +#endif + } +} diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index b7312b60..1e883b0a 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -1708,6 +1708,9 @@ void Session::execInternal() // of recreating our decoder at the time the HDR transition happens. m_VideoDecoder->setHdrMode(LiGetCurrentHostDisplayHdrMode()); + // After a window resize, we need to reset the pointer lock region + m_InputHandler->updatePointerRegionLock(); + SDL_AtomicUnlock(&m_DecoderLock); break;