fix(client-linux): Deck Gaming Mode — auto pad type, real chrome-less fullscreen, leave-to-Gaming-Mode, colour bisect
- "Automatic" gamepad type resolves to the virtual Steam Deck pad on Deck
hardware (env SteamDeck / DMI Jupiter|Galileo): the built-in 28DE:1205
identity is invisible at Hello time — the Valve HIDAPI drivers run
in-session only and Steam Input shadows the pad with its virtual X360 —
so auto always fell through to Xbox 360. "steamdeck" is now also
selectable in Settings.
- Chrome-less launches flatten the window CSS (border-radius/box-shadow)
and fullscreen at startup: gamescope never ACKs the xdg fullscreen
state, so adwaita kept the floating-CSD rounded corners + shadow
visible over the stream.
- Gaming-Mode --connect launches quit on session end, so Steam ends the
"game" and the Deck returns to Gaming Mode — previously the app popped
to its own hosts page, stranding the user fullscreen and making the
escape chord read as broken.
- The capture hint is controller-aware; the chromeless hint teaches the
hold-chord ("hold L1+R1+Start+Select to leave") and a quick chord press
re-flashes it.
- Colour bisect for the reported off-colours on the VAAPI dmabuf path:
graphics offload defaults OFF under gamescope (a subsurface hands the
NV12 CSC to the compositor), PUNKTFUNK_OFFLOAD=1|0 overrides, and each
colour-signaling change logs whether GDK accepted the BT.709-narrow
color state (fallback = GDK's BT.601 dmabuf default).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,21 @@ fn pref_for_type(t: sdl3::gamepad::GamepadType) -> GamepadPref {
|
||||
}
|
||||
}
|
||||
|
||||
/// Best-effort "this machine is a Steam Deck". The Gaming-Mode env short-circuits; desktop
|
||||
/// mode falls back to DMI (Valve board, Jupiter = LCD / Galileo = OLED — readable inside the
|
||||
/// flatpak sandbox). Cached: the answer can't change while we run.
|
||||
pub fn is_steam_deck() -> bool {
|
||||
static DECK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
*DECK.get_or_init(|| {
|
||||
if std::env::var_os("SteamDeck").is_some() {
|
||||
return true;
|
||||
}
|
||||
let dmi = |f: &str| std::fs::read_to_string(format!("/sys/class/dmi/id/{f}"));
|
||||
dmi("board_vendor").is_ok_and(|v| v.trim() == "Valve")
|
||||
&& dmi("product_name").is_ok_and(|p| matches!(p.trim(), "Jupiter" | "Galileo"))
|
||||
})
|
||||
}
|
||||
|
||||
enum Ctl {
|
||||
Attach(Arc<NativeClient>),
|
||||
Detach,
|
||||
@@ -197,8 +212,19 @@ impl GamepadService {
|
||||
|
||||
/// What "Automatic" resolves to right now — the virtual pad matching the physical one
|
||||
/// (Swift parity); no pad connected leaves the host's own default.
|
||||
///
|
||||
/// **Steam Deck special case:** this is read at session start, *before* attach — but the
|
||||
/// Deck's built-in controller is only enumerable with its real 28DE:1205 identity while
|
||||
/// the Valve HIDAPI drivers run, and those are enabled on attach only (see
|
||||
/// [`set_valve_hidapi`]); with Steam Input on, SDL sees nothing but Steam's virtual
|
||||
/// X360 pad anyway. Both cases used to fall through to Xbox 360. On a Deck, a virtual
|
||||
/// pad (or no pad at all) means the physical controller behind it IS the built-in one —
|
||||
/// resolve to the Steam Deck virtual pad so the paddles/trackpads/gyro have somewhere
|
||||
/// to land. A real external controller still wins (it's the one that gets forwarded).
|
||||
pub fn auto_pref(&self) -> GamepadPref {
|
||||
match self.active() {
|
||||
Some(p) if !p.steam_virtual => p.pref,
|
||||
_ if is_steam_deck() => GamepadPref::SteamDeck,
|
||||
Some(p) => p.pref,
|
||||
None => GamepadPref::Auto,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user