fix(steamdeck/install): set up controller passthrough + surface the required reboot
ci / docs-site (push) Successful in 1m12s
ci / web (push) Successful in 1m13s
apple / swift (push) Successful in 1m18s
decky / build-publish (push) Successful in 21s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 14s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 51s
ci / bench (push) Successful in 6m35s
apple / screenshots (push) Successful in 6m13s
deb / build-publish (push) Successful in 10m21s
docker / deploy-docs (push) Successful in 34s
deb / build-publish-host (push) Successful in 9m58s
android / android (push) Successful in 17m7s
arch / build-publish (push) Successful in 17m47s
ci / rust (push) Successful in 19m28s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 20m59s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 20m2s
ci / docs-site (push) Successful in 1m12s
ci / web (push) Successful in 1m13s
apple / swift (push) Successful in 1m18s
decky / build-publish (push) Successful in 21s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 14s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 51s
ci / bench (push) Successful in 6m35s
apple / screenshots (push) Successful in 6m13s
deb / build-publish (push) Successful in 10m21s
docker / deploy-docs (push) Successful in 34s
deb / build-publish-host (push) Successful in 9m58s
android / android (push) Successful in 17m7s
arch / build-publish (push) Successful in 17m47s
ci / rust (push) Successful in 19m28s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 20m59s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 20m2s
A fresh SteamOS host install failed on-glass two ways: KWin denied Desktop-mode capture (zkde_screencast_unstable_v1) so every session died in the pipeline build, and the native Steam Deck pad degraded to an Xbox 360 controller. Both stem from setup that only a fresh login applies — the host user-service keeps the pre-install group set and KWin reads its .desktop grant at session start — plus a missing vhci-hcd autoload the pad's USB/IP transport needs (the deb/rpm/arch packages ship it; the Deck installer did not). - install.sh: install punktfunk-modules.conf (+ modprobe vhci-hcd now) for the native Deck controller transport, seed the KDE RemoteDesktop grant (kde-authorized) for Desktop-mode input, and print a loud "reboot before streaming" notice when a relogin is actually required (input group added or the .desktop grant first installed). - update.sh: retrofit the udev rule, vhci-hcd autoload, input group, and grant so existing installs pick them up on the next update without a reinstall. - steamos-host.md: document the first-install reboot and the native controller passthrough requirements (input group + vhci-hcd + client-side Steam Input Off). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -58,8 +58,10 @@ It is idempotent — safe to re-run. In one pass it:
|
||||
1. creates the `pf2` Debian-trixie distrobox and installs the build toolchain,
|
||||
2. builds `punktfunk-host` (and the web console),
|
||||
3. writes config to `~/.config/punktfunk/` (a generated web-console login password),
|
||||
4. raises the UDP socket buffers to 32 MB and adds you to the `input` group (needs `sudo`; skipped
|
||||
with a warning if unavailable),
|
||||
4. raises the UDP socket buffers to 32 MB, installs the gamepad udev rule + the `vhci-hcd` autoload
|
||||
and adds you to the `input` group (virtual gamepads / **native Steam Deck controller passthrough**),
|
||||
and seeds the KDE RemoteDesktop grant for Desktop-mode input (needs `sudo`; skipped with a warning
|
||||
if unavailable),
|
||||
5. installs + starts the `punktfunk-host` and `punktfunk-web` **systemd user services** (with linger,
|
||||
so they run without a login session).
|
||||
|
||||
@@ -82,6 +84,14 @@ When it finishes it prints the web-console URL and how to pair.
|
||||
> If you only ever use native clients, install with `--no-gamestream` for a host with no GameStream
|
||||
> surface at all.
|
||||
|
||||
> **First install — reboot once before streaming.** KWin only authorizes Desktop-mode screen capture
|
||||
> on a fresh session, and the new `input` group (native Steam Deck controller passthrough) only takes
|
||||
> effect on a new login — so after the **first** install, **reboot the Deck** (a re-run that changes
|
||||
> nothing doesn't need it). Streaming **Game Mode** with a generic Xbox pad works right away; **Desktop
|
||||
> capture and the native Steam Deck controller need the reboot.** If a client connects and every
|
||||
> session ends with `KWin does not expose zkde_screencast_unstable_v1` or the pad shows up as an Xbox
|
||||
> 360 controller, you haven't rebooted yet.
|
||||
|
||||
## 3. Pair a device
|
||||
|
||||
By default the host **requires PIN pairing** (secure). Two ways to pair:
|
||||
@@ -128,6 +138,12 @@ bash ~/punktfunk/scripts/steamdeck/update.sh
|
||||
thrash the managed session. Pick one mode per session.
|
||||
- **Keep the device awake.** On handhelds, Game Mode auto-suspends on idle, which drops the host off
|
||||
the network mid stream — disable auto-suspend (Settings → Power) for a headless host.
|
||||
- **Native Steam Deck controller passthrough** presents the client's pad as a real Steam Deck
|
||||
controller (paddles, trackpads, gyro) via a virtual USB device — that needs the `input` group and the
|
||||
`vhci-hcd` module live, so it only works **after the first-install reboot** above; until then the pad
|
||||
degrades to a generic Xbox 360 controller (still fully playable). If you're streaming *to* another
|
||||
Steam Deck, also set Steam Input to **Off** for Punktfunk on that Deck — see
|
||||
[Stream to a Steam Deck](/docs/steam-deck).
|
||||
- **It survives OS updates**, but a major SteamOS bump can move library versions; if the host fails to
|
||||
start after an update, just re-run `update.sh` to rebuild against the new base.
|
||||
- Deeper reference (services, container, manual steps): [`scripts/steamdeck/README.md`](https://git.unom.io/unom/punktfunk/src/branch/main/scripts/steamdeck/README.md).
|
||||
|
||||
@@ -48,6 +48,9 @@ BIN="$TARGET_DIR/release/punktfunk-host"
|
||||
CONFIG="$HOME/.config/punktfunk"
|
||||
UNITS="$HOME/.config/systemd/user"
|
||||
XRD="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||
# Set when this run does something that only a fresh login picks up (input-group add, first-time
|
||||
# KWin .desktop grant). Drives the loud "reboot before streaming" note in the summary.
|
||||
NEED_RELOGIN=0
|
||||
|
||||
# --- 0. preflight ----------------------------------------------------------
|
||||
log "Preflight"
|
||||
@@ -148,11 +151,29 @@ fi
|
||||
# the restricted Wayland globals it lists (see packaging/linux/io.unom.Punktfunk.Host.desktop).
|
||||
# Exec must therefore be THIS install's binary path, not the packaged /usr/bin one. KWin reads
|
||||
# grants at session start — after first install, restart the Desktop session (Game Mode and back).
|
||||
DESKTOP_DST="$HOME/.local/share/applications/io.unom.Punktfunk.Host.desktop"
|
||||
# First-time install of the grant: KWin only reads it at session start, so a fresh login is required
|
||||
# before Desktop-mode capture works. A re-run that just rewrites it needs no relogin.
|
||||
[ -f "$DESKTOP_DST" ] || NEED_RELOGIN=1
|
||||
mkdir -p "$HOME/.local/share/applications"
|
||||
sed "s|^Exec=.*|Exec=$BIN|" "$SRC/packaging/linux/io.unom.Punktfunk.Host.desktop" \
|
||||
> "$HOME/.local/share/applications/io.unom.Punktfunk.Host.desktop"
|
||||
sed "s|^Exec=.*|Exec=$BIN|" "$SRC/packaging/linux/io.unom.Punktfunk.Host.desktop" > "$DESKTOP_DST"
|
||||
ok "KWin desktop-capture authorization (io.unom.Punktfunk.Host.desktop → $BIN)"
|
||||
|
||||
# KDE Desktop-mode INPUT: a normal Plasma login lacks the RemoteDesktop portal grant the host's libei
|
||||
# input path needs, so it would pop an "Allow remote control?" dialog a headless host can't answer.
|
||||
# Seed it once (per-user, no root) — mirrors packaging/bazzite/kde-desktop-setup.sh. Game Mode
|
||||
# (gamescope) needs none of this; the .desktop above already grants org_kde_kwin_fake_input.
|
||||
GRANT_SRC="$SRC/scripts/headless/kde-authorized"
|
||||
GRANT_DST="$HOME/.local/share/flatpak/db/kde-authorized"
|
||||
if [ -s "$GRANT_DST" ]; then
|
||||
ok "KDE RemoteDesktop grant already present"
|
||||
elif [ -s "$GRANT_SRC" ]; then
|
||||
mkdir -p "$(dirname "$GRANT_DST")"
|
||||
install -m644 "$GRANT_SRC" "$GRANT_DST"
|
||||
systemctl --user restart xdg-permission-store 2>/dev/null || true
|
||||
ok "seeded KDE RemoteDesktop grant (Desktop-mode input)"
|
||||
fi
|
||||
|
||||
if [ "$WITH_WEB" = 1 ] && [ ! -f "$CONFIG/web.env" ]; then
|
||||
# Random login password + session secret for the web console, generated once.
|
||||
# `|| true` swallows the SIGPIPE `tr` takes when `head` closes the pipe (pipefail would abort).
|
||||
@@ -169,7 +190,7 @@ else
|
||||
fi
|
||||
|
||||
# --- 4. system tuning (needs sudo; skipped gracefully if unavailable) ------
|
||||
log "System tuning (UDP buffers + input group) — needs sudo"
|
||||
log "System tuning (UDP buffers + gamepad rules + vhci-hcd + input group) — needs sudo"
|
||||
if sudo -n true 2>/dev/null; then
|
||||
printf 'net.core.wmem_max=33554432\nnet.core.rmem_max=33554432\n' \
|
||||
| sudo tee /etc/sysctl.d/99-punktfunk-net.conf >/dev/null
|
||||
@@ -178,9 +199,23 @@ if sudo -n true 2>/dev/null; then
|
||||
if [ -f "$SRC/scripts/60-punktfunk.rules" ]; then
|
||||
sudo install -m644 "$SRC/scripts/60-punktfunk.rules" /etc/udev/rules.d/60-punktfunk.rules
|
||||
sudo udevadm control --reload-rules && sudo udevadm trigger || true
|
||||
ok "installed udev rule (virtual gamepads)"
|
||||
ok "installed udev rule (virtual gamepads + native Steam Deck controller)"
|
||||
fi
|
||||
# vhci-hcd: the usbip transport that makes the virtual Steam Deck pad a *real* USB device so Steam
|
||||
# Input adopts it (else it degrades to plain UHID, which Steam ignores — "no controller appears").
|
||||
# Persist the autoload AND load it now so passthrough works without waiting for a reboot.
|
||||
if [ -f "$SRC/scripts/punktfunk-modules.conf" ]; then
|
||||
sudo install -m644 "$SRC/scripts/punktfunk-modules.conf" /etc/modules-load.d/punktfunk.conf
|
||||
sudo modprobe vhci-hcd 2>/dev/null || warn "could not load vhci-hcd now (loads on next boot) — needed for the native Steam Deck pad"
|
||||
ok "vhci-hcd autoload installed (native Steam Deck controller transport)"
|
||||
fi
|
||||
if id -nG "$USER" | grep -qw input; then
|
||||
ok "already in the 'input' group"
|
||||
else
|
||||
sudo usermod -aG input "$USER"
|
||||
NEED_RELOGIN=1
|
||||
warn "added $USER to the 'input' group (applies on next login)"
|
||||
fi
|
||||
id -nG "$USER" | grep -qw input || { sudo usermod -aG input "$USER"; warn "added $USER to 'input' group — log out/in (or reboot) for gamepad support"; }
|
||||
else
|
||||
warn "passwordless sudo unavailable — skipping UDP-buffer + udev tuning."
|
||||
warn "Without it, high-bitrate streaming drops packets. Apply manually later:"
|
||||
@@ -265,3 +300,10 @@ else
|
||||
echo " • Pairing required (secure default). From a client, pick this host and enter the PIN the host shows."
|
||||
fi
|
||||
echo " • Update later: bash $SRC/scripts/steamdeck/update.sh"
|
||||
if [ "$NEED_RELOGIN" = 1 ]; then
|
||||
echo
|
||||
warn "ONE MORE STEP before streaming — reboot the Deck (or fully log out and back in)."
|
||||
echo " KWin only authorizes Desktop-mode screen capture on a fresh session, and the new 'input'"
|
||||
echo " group (native Steam Deck controller passthrough) only applies to a new login. Streaming"
|
||||
echo " Game Mode with a generic Xbox pad works now; Desktop capture + the native Deck pad need the reboot."
|
||||
fi
|
||||
|
||||
@@ -44,6 +44,32 @@ sed "s|^Exec=.*|Exec=$TARGET_DIR/release/punktfunk-host|" "$SRC/packaging/linux/
|
||||
> "$HOME/.local/share/applications/io.unom.Punktfunk.Host.desktop"
|
||||
ok "KWin desktop-capture authorization refreshed"
|
||||
|
||||
# Retrofit the system bits install.sh now sets up but older installs predate (idempotent; the sudo
|
||||
# parts are skipped if passwordless sudo isn't available). vhci-hcd = usbip transport for the native
|
||||
# Steam Deck pad; 60-punktfunk.rules = /dev/uhid + vhci access; input group = uhid write; the
|
||||
# kde-authorized grant (per-user, no root) = Desktop-mode input. A newly-added input group still needs
|
||||
# a re-login to apply.
|
||||
if sudo -n true 2>/dev/null; then
|
||||
if [ -f "$SRC/scripts/60-punktfunk.rules" ]; then
|
||||
sudo install -m644 "$SRC/scripts/60-punktfunk.rules" /etc/udev/rules.d/60-punktfunk.rules
|
||||
sudo udevadm control --reload-rules >/dev/null 2>&1 || true
|
||||
sudo udevadm trigger >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [ -f "$SRC/scripts/punktfunk-modules.conf" ]; then
|
||||
sudo install -m644 "$SRC/scripts/punktfunk-modules.conf" /etc/modules-load.d/punktfunk.conf
|
||||
sudo modprobe vhci-hcd 2>/dev/null || true
|
||||
ok "vhci-hcd autoload ensured (native Steam Deck controller)"
|
||||
fi
|
||||
id -nG "$USER" | grep -qw input || { sudo usermod -aG input "$USER"; ok "added $USER to 'input' group — log out/in for it to apply"; }
|
||||
fi
|
||||
GRANT_SRC="$SRC/scripts/headless/kde-authorized"
|
||||
GRANT_DST="$HOME/.local/share/flatpak/db/kde-authorized"
|
||||
if [ ! -s "$GRANT_DST" ] && [ -s "$GRANT_SRC" ]; then
|
||||
mkdir -p "$(dirname "$GRANT_DST")"
|
||||
install -m644 "$GRANT_SRC" "$GRANT_DST"
|
||||
ok "seeded KDE RemoteDesktop grant (Desktop-mode input)"
|
||||
fi
|
||||
|
||||
log "Restarting services"
|
||||
systemctl --user restart punktfunk-host.service
|
||||
ok "punktfunk-host restarted"
|
||||
|
||||
Reference in New Issue
Block a user