feat(clients/input): system buttons route around local overlays #47

Merged
enricobuehler merged 1 commits from worktree-system-buttons-routing into main 2026-08-04 20:02:24 +00:00
Owner

Pressing guide/Steam/QAM collided with the client device's own shell: iOS 26 opens its Game Overlay for the Home press (no app opt-out — iOS 27 makes it a user setting via GCControllerHomeButtonSettingsManager), and a Gaming-Mode client opened BOTH Steam overlays for one press, the local one covering the stream.

Two cross-client tier-P settings, zero wire changes:

  • system_buttons (auto|forward|local) — raw guide+misc1 passthrough. Auto forwards everywhere EXCEPT under gamescope, where SteamOS reacts to the same physical press no matter what.
  • guide_gesture (auto|on|off) — hold Select ALONE ≈350 ms sends the HOST's guide, down until release; held on, that's the host's long-press, which opens a Gaming-Mode host's QAM for regular pads. A Select tap is delivered on release with its up 50 ms behind (per-transition sends fold into seq'd GamepadState snapshots — a back-to-back pair can coalesce into no press at all). Select inside a combo (the escape chord) passes through untouched. Auto arms it only where the raw press can't reach the host cleanly: gamescope, iOS/iPadOS, tvOS.

Same SelectGesture rules in pf-client-core (pure state machine + unit tests), the Apple client (mask-diff adaptation), and Android's GamepadRouter. Settings rows on every surface (GTK, WinUI, console UI, Decky, Apple ×2, Android ×2) with profile plumbing throughout.

punktfunk-session grows a control socket ($XDG_RUNTIME_DIR[/app/$FLATPAK_ID]/punktfunk-session-ctl.sock — the one runtime path a flatpak and the host see identically): guide/qam verbs inject synthetic taps. The Decky panel gains a Host menus section (visible while the client runs) whose buttons press the host's Steam/QAM and close the local menu so the host's shows through — this also covers QAM on Deck-shaped virtual pads, where long-press Steam isn't the QAM.

Docs: input, client-settings, steam-deck. Design: punktfunk-planning design/system-buttons-routing.md.

Gates: docker clippy --all-targets --locked -D warnings (pf-client-core, session, console-ui, GTK) + tests (88 incl. 6 new gesture tests / 47), cargo fmt --all --check, swift build (macOS), gradle kit+app compile, decky tsc --noEmit + py_compile.

Owed: on-glass Deck→gamescope (double overlay gone, both panel buttons, hold-Select), iPhone under iOS 26, desktop raw-guide regression. ⚠ clients/windows not compiled (no reachable box — settings rows only). iOS 27 deep-link is a TODO pending the Xcode 27 SDK.

Pressing guide/Steam/QAM collided with the client device's own shell: iOS 26 opens its Game Overlay for the Home press (no app opt-out — iOS 27 makes it a *user* setting via `GCControllerHomeButtonSettingsManager`), and a Gaming-Mode client opened BOTH Steam overlays for one press, the local one covering the stream. Two cross-client tier-P settings, zero wire changes: - **`system_buttons`** (`auto|forward|local`) — raw guide+misc1 passthrough. Auto forwards everywhere EXCEPT under gamescope, where SteamOS reacts to the same physical press no matter what. - **`guide_gesture`** (`auto|on|off`) — hold Select ALONE ≈350 ms sends the HOST's guide, down until release; held on, that's the host's long-press, which opens a Gaming-Mode host's QAM for regular pads. A Select tap is delivered on release with its up 50 ms behind (per-transition sends fold into seq'd `GamepadState` snapshots — a back-to-back pair can coalesce into no press at all). Select inside a combo (the escape chord) passes through untouched. Auto arms it only where the raw press can't reach the host cleanly: gamescope, iOS/iPadOS, tvOS. Same `SelectGesture` rules in pf-client-core (pure state machine + unit tests), the Apple client (mask-diff adaptation), and Android's `GamepadRouter`. Settings rows on every surface (GTK, WinUI, console UI, Decky, Apple ×2, Android ×2) with profile plumbing throughout. `punktfunk-session` grows a control socket (`$XDG_RUNTIME_DIR[/app/$FLATPAK_ID]/punktfunk-session-ctl.sock` — the one runtime path a flatpak and the host see identically): `guide`/`qam` verbs inject synthetic taps. The Decky panel gains a **Host menus** section (visible while the client runs) whose buttons press the host's Steam/QAM and close the local menu so the host's shows through — this also covers QAM on Deck-shaped virtual pads, where long-press Steam isn't the QAM. Docs: input, client-settings, steam-deck. Design: punktfunk-planning `design/system-buttons-routing.md`. **Gates:** docker clippy `--all-targets --locked -D warnings` (pf-client-core, session, console-ui, GTK) + tests (88 incl. 6 new gesture tests / 47), `cargo fmt --all --check`, swift build (macOS), gradle kit+app compile, decky `tsc --noEmit` + `py_compile`. **Owed:** on-glass Deck→gamescope (double overlay gone, both panel buttons, hold-Select), iPhone under iOS 26, desktop raw-guide regression. ⚠ `clients/windows` not compiled (no reachable box — settings rows only). iOS 27 deep-link is a TODO pending the Xcode 27 SDK.
enricobuehler added 1 commit 2026-08-04 19:51:59 +00:00
feat(clients/input): system buttons route around local overlays
apple / swift (pull_request) Successful in 1m30s
apple / screenshots (pull_request) Skipped
android / android (pull_request) Successful in 4m16s
ci / rust-arm64 (pull_request) Successful in 3m20s
windows / build (aarch64-pc-windows-msvc) (pull_request) Successful in 59s
ci / web (pull_request) Successful in 1m36s
ci / docs-site (pull_request) Successful in 2m7s
windows / build (x86_64-pc-windows-msvc) (pull_request) Successful in 1m55s
ci / rust (pull_request) Successful in 10m36s
1db7058a5d
Pressing guide/Steam/QAM collided with the client device's own shell: iOS 26
opens its Game Overlay for the Home press (no app opt-out until iOS 27 makes
it a user setting), and a Gaming-Mode client opened BOTH Steam overlays for
one press — the local one covering the stream.

Two cross-client tier-P settings, zero wire changes:

- system_buttons (auto|forward|local): raw guide+misc1 passthrough. Auto
  forwards everywhere EXCEPT under gamescope, where SteamOS reacts to the
  same physical press no matter what.
- guide_gesture (auto|on|off): hold Select ALONE ~350ms sends the HOST's
  guide, down until release — held on, that's the host's long-press, which
  opens a Gaming-Mode host's QAM for regular pads. A Select tap is delivered
  on release with its up TAP_PRESS (50ms) behind, because per-transition
  sends fold into seq'd GamepadState snapshots and a back-to-back pair can
  coalesce into no press at all. A Select inside a combo (the escape chord)
  passes through untouched. Auto arms it only where the raw press can't
  reach the host cleanly: gamescope, iOS/iPadOS, tvOS.

The same SelectGesture rules live in pf-client-core (pure state machine +
unit tests), the Apple client (mask-diff adaptation in GamepadCapture), and
Android's GamepadRouter. Settings rows on every surface (GTK, WinUI,
console UI, Decky, Apple x2, Android x2) with profile plumbing throughout.

punktfunk-session grows a control socket
($XDG_RUNTIME_DIR[/app/$FLATPAK_ID]/punktfunk-session-ctl.sock — the one
runtime path a flatpak and the host see identically): 'guide'/'qam' verbs
inject synthetic taps. The Decky panel gains a Host menus section (visible
while the client runs) whose buttons press the host's Steam/QAM and close
the local menu so the host's shows through.

iOS 27's GCControllerHomeButtonSettingsManager deep-link is a TODO (the
class needs the Xcode 27 SDK to compile). Docs: input, client-settings,
steam-deck. Design: punktfunk-planning design/system-buttons-routing.md.

Gates: docker clippy --all-targets --locked -D warnings + tests
(pf-client-core 88 incl. 6 new gesture tests, pf-console-ui 47),
cargo fmt --all --check, swift build (macOS), gradle kit+app compile,
decky tsc --noEmit + py_compile. clients/windows not compiled (no box).
enricobuehler force-pushed worktree-system-buttons-routing from ac395bbfa9 to 1db7058a5d 2026-08-04 19:51:59 +00:00 Compare
enricobuehler merged commit c1231fa2e6 into main 2026-08-04 20:02:24 +00:00
enricobuehler deleted branch worktree-system-buttons-routing 2026-08-04 20:02:25 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#47