diff --git a/tools/gamescope/PATCHES.md b/tools/gamescope/PATCHES.md index ad4fc4b34..6d0c1a119 100644 --- a/tools/gamescope/PATCHES.md +++ b/tools/gamescope/PATCHES.md @@ -39,5 +39,12 @@ library list, before anything is published. then focus is handed over again. `GAMESCOPE_RESTORE_FOCUS_WINDOW` on the root window asks for the same restore from outside (the session script's resume watcher). +- `0113-steam-overlay-keeps-game-keyboard-focus.patch` - this app: the Steam client opens the Quick + Access Menu and Steam menu over a game with `STEAM_INPUT_FOCUS` 1, which moves X keyboard focus to + its overlay; wine then deactivates the game and a fullscreen game minimizes itself, freezing + behind the menu instead of running on as on a Steam Deck. Steam's own overlay taking input now + keeps keyboard focus on the game, as mode 2 does; its input comes from the controller through + Steam Input, not the X keyboard. + Sixteen more of Armada's patches are DRM/lease/HDR-on-KMS work for a native display, which this app's Wayland-hosted gamescope never reaches, or need a newer gamescope than the runtime has. diff --git a/tools/gamescope/patches/0113-steam-overlay-keeps-game-keyboard-focus.patch b/tools/gamescope/patches/0113-steam-overlay-keeps-game-keyboard-focus.patch new file mode 100644 index 000000000..9a09e26c8 --- /dev/null +++ b/tools/gamescope/patches/0113-steam-overlay-keeps-game-keyboard-focus.patch @@ -0,0 +1,70 @@ +From: DroidDeck +Subject: [PATCH] steamcompmgr: keep the game's keyboard focus under Steam's overlay + +The Steam client opens its Quick Access Menu and Steam menu over a game by setting +STEAM_OVERLAY 1 and STEAM_INPUT_FOCUS 1 on its window. Mode 1 moves X keyboard focus to the +overlay, so the game's window gets FocusOut: wine moves the foreground to the desktop, a fullscreen +game deactivates and minimizes itself (WM_CHANGE_STATE IconicState), and it stops rendering behind +the menu - frozen, all threads asleep, until the menu closes (Alan Wake's American Nightmare, +Proton Experimental ARM64). On a Steam Deck the game runs on behind the menu. + +Mode 2 already means "input to the overlay, keyboard focus stays on the focus window". Treat +Steam's own overlay taking input in mode 1 the same way at the three places mode 2 is honoured. +The overlay's input does not need X keyboard focus: the controller drives it through Steam Input. +Measured by rewriting the property to 2 by hand: the game kept running behind the menu and the +controller still moved only the menu. + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 372a82c..f870974 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -1321,6 +1321,22 @@ window_is_steam( steamcompmgr_win_t *w ) + return w && ( w->isSteamLegacyBigPicture || w->appID == 769 ); + } + ++// Whether keyboard focus stays on the focus window while this window has input focus. ++// STEAM_INPUT_FOCUS 2 asks for that. The Steam client also opens its Quick Access Menu and Steam ++// menu over a game with 1, which moves X keyboard focus to the overlay: wine then deactivates the ++// game, a fullscreen game minimizes itself, and it froze behind the menu instead of running on as ++// on a Steam Deck. The overlay's own input does not need X keyboard focus (the controller drives ++// it through Steam Input), so Steam's overlay keeps the game's keyboard focus too. ++static bool ++window_keeps_game_keyboard_focus( steamcompmgr_win_t *w ) ++{ ++ if ( !w ) ++ return false; ++ if ( w->inputFocusMode == 2 ) ++ return true; ++ return w->inputFocusMode == 1 && w->isOverlay && window_is_steam( w ); ++} ++ + static bool + window_is_vr_scene_app( steamcompmgr_win_t *w ) + { +@@ -4728,7 +4744,7 @@ void xwayland_ctx_t::DetermineAndApplyFocus( const std::vector< steamcompmgr_win + + if ( gamescope::VirtualConnectorIsSingleOutput() ) + { +- if ( inputFocus && inputFocus->inputFocusMode == 2 ) ++ if ( window_keeps_game_keyboard_focus( inputFocus ) ) + keyboardFocusWin = ctx->focus.focusWindow; + } + else +@@ -5340,7 +5356,7 @@ determine_and_apply_focus( global_focus_t *pFocus ) + pFocus->inputFocusMode = pFocus->inputFocusWindow->inputFocusMode; + + if ( gamescope::VirtualConnectorIsSingleOutput() && +- pFocus->inputFocusMode == 2 ) ++ window_keeps_game_keyboard_focus( pFocus->inputFocusWindow ) ) + { + pFocus->keyboardFocusWindow = pFocus->overrideWindow + ? pFocus->overrideWindow +@@ -6485,7 +6501,7 @@ handle_wl_surface_id(xwayland_ctx_t *ctx, steamcompmgr_win_t *w, uint32_t surfac + steamcompmgr_win_t *keyboardFocusWindow = pCurrentFocus->inputFocusWindow; + + if ( gamescope::VirtualConnectorIsSingleOutput() && +- keyboardFocusWindow && keyboardFocusWindow->inputFocusMode == 2 ) ++ window_keeps_game_keyboard_focus( keyboardFocusWindow ) ) + keyboardFocusWindow = pCurrentFocus->focusWindow; + + if ( w == keyboardFocusWindow ) diff --git a/tools/linuxfs/overlay/usr/local/bin/bannerlator-session b/tools/linuxfs/overlay/usr/local/bin/bannerlator-session index 1f55e3089..cb6595340 100755 --- a/tools/linuxfs/overlay/usr/local/bin/bannerlator-session +++ b/tools/linuxfs/overlay/usr/local/bin/bannerlator-session @@ -172,6 +172,8 @@ if [ -z "${BL_INSIDE:-}" ]; then # HDR10: the app opened its compositor's colour-management gate for this session (BL_HDR=1); # gamescope then offers HDR to its clients through the same wp_color_manager_v1 it binds on ours. [ "${BL_HDR:-0}" = 1 ] && args+=(--hdr-enabled) + # Extra gamescope arguments for an experiment (--debug-focus, say), from Download/droiddeck-env. + [ -n "${BL_GAMESCOPE_ARGS:-}" ] && read -r -a _bl_extra <<<"$BL_GAMESCOPE_ARGS" && args+=("${_bl_extra[@]}") # Deck mode's performance overlay (Quick Access Menu → Performance → Overlay Level) is drawn by # mangoapp, which gamescope starts beside the client; the client sets the level by rewriting # MANGOHUD_CONFIGFILE. The apk stages Valve's aarch64 build (tools/mangoapp) - without it the menu