diff --git a/app/streaming/input/gamepad.cpp b/app/streaming/input/gamepad.cpp index 94625f6c..d5171f22 100644 --- a/app/streaming/input/gamepad.cpp +++ b/app/streaming/input/gamepad.cpp @@ -443,19 +443,6 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve return; } - if (state->buttons == (BACK_FLAG | LB_FLAG | RB_FLAG | B_FLAG)) { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, - "Detected control panel toggle gamepad combo"); - - Session::get()->toggleControlPanelVisibility(); - - if (isGamepadInputAllowed()) { - LiSendMultiControllerEvent(state->index, m_GamepadMask, - 0, 0, 0, 0, 0, 0, 0); - } - return; - } - if (state->buttons == (BACK_FLAG | LB_FLAG | RB_FLAG | Y_FLAG)) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Detected keyboard/mouse input toggle gamepad combo"); diff --git a/app/streaming/input/input.cpp b/app/streaming/input/input.cpp index 819519a0..a2a109e7 100644 --- a/app/streaming/input/input.cpp +++ b/app/streaming/input/input.cpp @@ -86,11 +86,6 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i m_SpecialKeyCombos[KeyComboToggleStatsOverlay].scanCode = SDL_SCANCODE_S; m_SpecialKeyCombos[KeyComboToggleStatsOverlay].enabled = true; - m_SpecialKeyCombos[KeyComboToggleControlPanel].keyCombo = KeyComboToggleControlPanel; - m_SpecialKeyCombos[KeyComboToggleControlPanel].keyCode = SDLK_p; - m_SpecialKeyCombos[KeyComboToggleControlPanel].scanCode = SDL_SCANCODE_P; - m_SpecialKeyCombos[KeyComboToggleControlPanel].enabled = true; - m_SpecialKeyCombos[KeyComboToggleMouseMode].keyCombo = KeyComboToggleMouseMode; m_SpecialKeyCombos[KeyComboToggleMouseMode].keyCode = SDLK_m; m_SpecialKeyCombos[KeyComboToggleMouseMode].scanCode = SDL_SCANCODE_M; diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 780e0383..753ff275 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -163,7 +163,6 @@ private: KeyComboUngrabInput, KeyComboToggleFullScreen, KeyComboToggleStatsOverlay, - KeyComboToggleControlPanel, KeyComboToggleMouseMode, KeyComboToggleCursorHide, KeyComboToggleMinimize, diff --git a/app/streaming/input/keyboard.cpp b/app/streaming/input/keyboard.cpp index 7d5a03c4..1f8a8214 100644 --- a/app/streaming/input/keyboard.cpp +++ b/app/streaming/input/keyboard.cpp @@ -64,14 +64,6 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo) !Session::get()->getOverlayManager().isOverlayEnabled(Overlay::OverlayDebug)); break; - case KeyComboToggleControlPanel: - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, - "Detected control panel toggle combo"); - if (auto session = Session::get(); session != nullptr) { - session->toggleControlPanelVisibility(); - } - break; - case KeyComboToggleMouseMode: SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Detected mouse mode toggle combo"); diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 57ba29b1..69bf4d02 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -178,8 +178,29 @@ void Session::clConnectionStatusUpdate(int connectionStatus) "Connection status update: %d", connectionStatus); - s_ActiveSession->m_ConnectionStatus.store(connectionStatus, std::memory_order_relaxed); - s_ActiveSession->refreshControlPanelOverlay(); + if (!s_ActiveSession->m_Preferences->connectionWarnings) { + return; + } + + if (s_ActiveSession->m_MouseEmulationRefCount > 0) { + // Don't display the overlay if mouse emulation is already using it + return; + } + + switch (connectionStatus) + { + case CONN_STATUS_POOR: + s_ActiveSession->m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed); + s_ActiveSession->m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, + s_ActiveSession->m_StreamConfig.bitrate > 5000 ? + "Slow connection to PC\nReduce your bitrate" : "Poor connection to PC"); + s_ActiveSession->m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true); + break; + case CONN_STATUS_OKAY: + s_ActiveSession->m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed); + s_ActiveSession->m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, false); + break; + } } void Session::clSetHdrMode(bool enabled) @@ -558,8 +579,6 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere m_AudioVolumeScalar(1.0f), m_AllowGamepadInput(true), m_AllowKeyboardMouseInput(false), - m_ControlPanelVisible(true), - m_ConnectionStatus(CONN_STATUS_OKAY), m_StatusOverlayGeneration(0), m_QtWindow(nullptr), m_UnexpectedTermination(true), // Failure prior to streaming is unexpected @@ -574,7 +593,6 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere m_AudioSampleCount(0), m_DropAudioEndTime(0) { - m_TemporaryStatusOverlayText[0] = '\0'; } void Session::setGamepadInputAllowed(bool allowed) @@ -643,13 +661,6 @@ void Session::toggleKeyboardMouseInputAllowed() setKeyboardMouseInputAllowed(!isKeyboardMouseInputAllowed()); } -void Session::toggleControlPanelVisibility() -{ - const bool visible = !m_ControlPanelVisible.load(std::memory_order_relaxed); - m_ControlPanelVisible.store(visible, std::memory_order_relaxed); - showTemporaryStatusOverlay(visible ? "Control panel shown" : "Control panel hidden"); -} - void Session::notifyInputPermissionState() { char buffer[96]; @@ -689,80 +700,14 @@ Uint32 Session::statusOverlayTimeoutCallback(Uint32, void* param) return 0; } -void Session::refreshControlPanelOverlay() -{ - if (!m_ControlPanelVisible.load(std::memory_order_relaxed)) { - if (m_TemporaryStatusOverlayText[0] != '\0') { - m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, m_TemporaryStatusOverlayText); - m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true); - } - else { - m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, false); - } - return; - } - - char volumeState[24]; - if (m_ManualAudioMuted.load(std::memory_order_relaxed)) { - SDL_snprintf(volumeState, sizeof(volumeState), "MUTED"); - } - else { - const int percent = (int)SDL_roundf(getAudioVolumeScalar() * 100.0f); - SDL_snprintf(volumeState, sizeof(volumeState), "%d%%", percent); - } - - char panelText[640]; - SDL_snprintf(panelText, - sizeof(panelText), - "Stream Controls\n" - "KB/M (Ctrl+Alt+Shift+K): %s\n" - "Pad (Ctrl+Alt+Shift+G): %s\n" - "Vol (U/J, mute N): %s\n" - "UI (Ctrl+Alt+Shift+P / Select+L1+R1+B): ON", - isKeyboardMouseInputAllowed() ? "ON" : "OFF", - isGamepadInputAllowed() ? "ON" : "OFF", - volumeState); - - size_t used = SDL_strlen(panelText); - if (used < sizeof(panelText) && m_MouseEmulationRefCount > 0) { - SDL_snprintf(panelText + used, - sizeof(panelText) - used, - "\nMouse mode: ACTIVE (hold Start to disable)"); - used = SDL_strlen(panelText); - } - - if (used < sizeof(panelText) && - m_Preferences->connectionWarnings && - m_ConnectionStatus.load(std::memory_order_relaxed) == CONN_STATUS_POOR) { - SDL_snprintf(panelText + used, - sizeof(panelText) - used, - "\nNetwork: %s", - m_StreamConfig.bitrate > 5000 ? "Slow (reduce bitrate)" : "Poor"); - used = SDL_strlen(panelText); - } - - if (used < sizeof(panelText) && m_TemporaryStatusOverlayText[0] != '\0') { - SDL_snprintf(panelText + used, - sizeof(panelText) - used, - "\nStatus: %s", - m_TemporaryStatusOverlayText); - } - - m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, panelText); - m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true); -} - void Session::showTemporaryStatusOverlay(const char* text, Uint32 timeoutMs) { - if (text == nullptr || text[0] == '\0') { + if (m_MouseEmulationRefCount > 0) { return; } - SDL_snprintf(m_TemporaryStatusOverlayText, - sizeof(m_TemporaryStatusOverlayText), - "%s", - text); - refreshControlPanelOverlay(); + m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, text); + m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true); const uint32_t generation = m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed) + 1; SDL_AddTimer(timeoutMs, statusOverlayTimeoutCallback, (void*)(uintptr_t)generation); @@ -782,9 +727,6 @@ void Session::applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool all if (reason != LI_SESSION_INPUT_POLICY_REASON_STREAM_START) { notifyInputPermissionState(); } - else { - refreshControlPanelOverlay(); - } } void Session::updateEffectiveAudioMuteState() @@ -1767,8 +1709,16 @@ void Session::notifyMouseEmulationMode(bool enabled) m_MouseEmulationRefCount += enabled ? 1 : -1; SDL_assert(m_MouseEmulationRefCount >= 0); - showTemporaryStatusOverlay(enabled ? "Gamepad mouse mode enabled" : "Gamepad mouse mode disabled"); - refreshControlPanelOverlay(); + // We re-use the status update overlay for mouse mode notification + if (m_MouseEmulationRefCount > 0) { + m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed); + m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, "Gamepad mouse mode active\nLong press Start to deactivate"); + m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true); + } + else { + m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed); + m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, false); + } } class AsyncConnectionStartThread : public QThread @@ -1974,10 +1924,7 @@ void Session::start() m_ManualAudioMuted.store(false, std::memory_order_relaxed); m_AudioMuted.store(false, std::memory_order_relaxed); m_AudioVolumeScalar.store(1.0f, std::memory_order_relaxed); - m_ControlPanelVisible.store(true, std::memory_order_relaxed); - m_ConnectionStatus.store(CONN_STATUS_OKAY, std::memory_order_relaxed); m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed); - m_TemporaryStatusOverlayText[0] = '\0'; // Initialize the gamepad code with our preferences // NB: m_InputHandler must be initialize before starting the connection. @@ -2181,7 +2128,6 @@ void Session::exec() // Toggle the stats overlay if requested by the user m_OverlayManager.setOverlayState(Overlay::OverlayDebug, m_Preferences->showPerformanceOverlay); - refreshControlPanelOverlay(); // Switch to async logging mode when we enter the SDL loop StreamUtils::enterAsyncLoggingMode(); @@ -2277,9 +2223,9 @@ void Session::exec() break; } case SDL_CODE_HIDE_STATUS_OVERLAY: - if ((uint32_t)(uintptr_t)event.user.data1 == m_StatusOverlayGeneration.load(std::memory_order_relaxed)) { - m_TemporaryStatusOverlayText[0] = '\0'; - refreshControlPanelOverlay(); + if ((uint32_t)(uintptr_t)event.user.data1 == m_StatusOverlayGeneration.load(std::memory_order_relaxed) && + m_MouseEmulationRefCount == 0) { + m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, false); } break; default: diff --git a/app/streaming/session.h b/app/streaming/session.h index 13eca494..8e5bd35f 100644 --- a/app/streaming/session.h +++ b/app/streaming/session.h @@ -140,7 +140,6 @@ public: void setKeyboardMouseInputAllowed(bool allowed); void toggleGamepadInputAllowed(); void toggleKeyboardMouseInputAllowed(); - void toggleControlPanelVisibility(); void notifyInputPermissionState(); float getAudioVolumeScalar() const @@ -276,7 +275,6 @@ private: static Uint32 statusOverlayTimeoutCallback(Uint32 interval, void* param); - void refreshControlPanelOverlay(); void showTemporaryStatusOverlay(const char* text, Uint32 timeoutMs = 1500); void applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool allowGamepad, uint8_t reason); void sendInputPermissionStateToHost(uint8_t reason); @@ -299,8 +297,6 @@ private: std::atomic m_AudioVolumeScalar; std::atomic m_AllowGamepadInput; std::atomic m_AllowKeyboardMouseInput; - std::atomic m_ControlPanelVisible; - std::atomic m_ConnectionStatus; std::atomic m_StatusOverlayGeneration; Uint32 m_FullScreenFlag; QQuickWindow* m_QtWindow; @@ -325,7 +321,6 @@ private: OPUS_MULTISTREAM_CONFIGURATION m_OriginalAudioConfig; int m_AudioSampleCount; Uint32 m_DropAudioEndTime; - char m_TemporaryStatusOverlayText[160]; Overlay::OverlayManager m_OverlayManager; diff --git a/app/streaming/video/overlaymanager.cpp b/app/streaming/video/overlaymanager.cpp index 77150cc9..17e5e5c5 100644 --- a/app/streaming/video/overlaymanager.cpp +++ b/app/streaming/video/overlaymanager.cpp @@ -12,8 +12,8 @@ OverlayManager::OverlayManager() : m_Overlays[OverlayType::OverlayDebug].color = {0xD0, 0xD0, 0x00, 0xFF}; m_Overlays[OverlayType::OverlayDebug].fontSize = 20; - m_Overlays[OverlayType::OverlayStatusUpdate].color = {0xF0, 0xF0, 0xF0, 0xFF}; - m_Overlays[OverlayType::OverlayStatusUpdate].fontSize = 24; + m_Overlays[OverlayType::OverlayStatusUpdate].color = {0xCC, 0x00, 0x00, 0xFF}; + m_Overlays[OverlayType::OverlayStatusUpdate].fontSize = 36; // While TTF will usually not be initialized here, it is valid for that not to // be the case, since Session destruction is deferred and could overlap with @@ -146,45 +146,16 @@ void OverlayManager::notifyOverlayUpdated(OverlayType type) } } - SDL_Surface* newSurface = nullptr; - if (m_Overlays[type].enabled) { - // The _Wrapped variant is required for line breaks to work - SDL_Surface* textSurface = TTF_RenderText_Blended_Wrapped(m_Overlays[type].font, - m_Overlays[type].text, - m_Overlays[type].color, - 1024); - if (textSurface != nullptr && type == OverlayStatusUpdate) { - constexpr int kHorizontalPadding = 18; - constexpr int kVerticalPadding = 12; - - SDL_Surface* panelSurface = SDL_CreateRGBSurfaceWithFormat(0, - textSurface->w + (kHorizontalPadding * 2), - textSurface->h + (kVerticalPadding * 2), - 32, - SDL_PIXELFORMAT_ARGB8888); - if (panelSurface != nullptr) { - SDL_FillRect(panelSurface, - nullptr, - SDL_MapRGBA(panelSurface->format, 0x00, 0x00, 0x00, 0xA0)); - - SDL_Rect destination = {kHorizontalPadding, kVerticalPadding, textSurface->w, textSurface->h}; - SDL_SetSurfaceBlendMode(textSurface, SDL_BLENDMODE_BLEND); - SDL_BlitSurface(textSurface, nullptr, panelSurface, &destination); - SDL_FreeSurface(textSurface); - newSurface = panelSurface; - } - else { - newSurface = textSurface; - } - } - else { - newSurface = textSurface; - } - } - // Exchange the old surface with the new one - SDL_Surface* oldSurface = (SDL_Surface*)SDL_AtomicSetPtr((void**)&m_Overlays[type].surface, - newSurface); + SDL_Surface* oldSurface = (SDL_Surface*)SDL_AtomicSetPtr( + (void**)&m_Overlays[type].surface, + m_Overlays[type].enabled ? + // The _Wrapped variant is required for line breaks to work + TTF_RenderText_Blended_Wrapped(m_Overlays[type].font, + m_Overlays[type].text, + m_Overlays[type].color, + 1024) + : nullptr); // Notify the renderer m_Renderer->notifyOverlayUpdated(type);