wolf: add fullscreen wrapper for Steam-launched emulators, document controller/crash troubleshooting
Addresses reported symptoms after adding Cemu/Azahar/PCSX2/Dolphin/ES-DE as non-Steam games in Wolf's Steam app: a launched emulator opens at roughly half the screen, and the controller doesn't respond. Half-screen: a non-Steam game launched from Steam is a second top-level window inside Wolf's single-app Steam Sway session (RUN_SWAY=true) — Sway's own kiosk config only auto-fullscreens the ONE window it expects (Steam's own), so anything launched from inside Steam opens at whatever default size it requests instead. steam-add-nonsteam-game and steam-setup-frontends now route the launch through a small generated wrapper (emulators/steam-fullscreen-wrap) that launches the real binary and repeatedly asks Sway to fullscreen whatever currently has focus for a few seconds after launch. NOT yet confirmed live against a real Wolf Steam session — if swaymsg isn't reachable from inside that container, the wrapper's loop just fails silently (2>/dev/null) and the launch is unaffected, so this is safe to try either way. Since every wrapped shortcut now shares the same Exe (the wrapper) with the real per-emulator target carried in LaunchOptions instead, the shortcuts.vdf dedupe/appid logic had to move from keying on Exe alone to the (Exe, LaunchOptions) pair — otherwise adding a second emulator would have silently overwritten the first one's entry. Also cleans up a legacy pre-wrapper entry (Exe pointing directly at the same real binary, no LaunchOptions) when re-adding something added before this existed, so re-running doesn't leave a stale duplicate tile behind. Verified with a synthetic shortcuts.vdf: two different emulators keep distinct entries, re-adding one updates in place, and a legacy direct-launch entry gets replaced rather than duplicated. Controller not responding turned out to most likely be Steam Input applying its own (unconfigured) controller mapping to the new shortcut rather than passing raw input through — documented the actual fix (Big Picture -> shortcut -> Controller Options -> Gamepad template or disable Steam Input) since this is a Steam-side per-shortcut setting this installer has no way to preconfigure via shortcuts.vdf. Also documented the third reported symptom (Cemu/Azahar/PCSX2 tiles appear but crash on launch, while Dolphin/ES-DE work) as a separate, not-yet-diagnosed issue, with the exact docker exec command to capture the real error directly (no wrapper, no Steam) since guessing at a fix without that output isn't reliable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BWYKEERLA1a7gv86Z4W23
This commit is contained in:
+120
-12
@@ -4071,9 +4071,50 @@ except Exception:
|
|||||||
ls "$_SANG_EMU_DIR" 2>/dev/null
|
ls "$_SANG_EMU_DIR" 2>/dev/null
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
_SANG_EXE="/home/retro/Applications/$(basename "$_SANG_HOST_FILE")"
|
_SANG_REAL_EXE="/home/retro/Applications/$(basename "$_SANG_HOST_FILE")"
|
||||||
[ -z "$_SANG_NAME" ] && _SANG_NAME=$(basename "$_SANG_HOST_FILE" | sed -E 's/\.(AppImage|sh|x86_64)$//I')
|
[ -z "$_SANG_NAME" ] && _SANG_NAME=$(basename "$_SANG_HOST_FILE" | sed -E 's/\.(AppImage|sh|x86_64)$//I')
|
||||||
|
|
||||||
|
# Route the actual launch through a small fullscreen-forcing wrapper
|
||||||
|
# instead of pointing Steam's Exe directly at the AppImage. Why: a
|
||||||
|
# non-Steam game launched from Steam is a SECOND top-level window in
|
||||||
|
# Wolf's single-app Steam Sway session (RUN_SWAY=true on the 'steam'
|
||||||
|
# CATALOG entry) — Sway's own kiosk config only auto-fullscreens the
|
||||||
|
# ONE window it expects (Steam's own), so anything launched from
|
||||||
|
# inside Steam opens at whatever default size it requests instead,
|
||||||
|
# which reads as roughly half the screen against a full
|
||||||
|
# Moonlight-resolution display. Reported live against ES-DE/Dolphin
|
||||||
|
# added this way. NOT yet confirmed live that swaymsg actually
|
||||||
|
# reaches Sway from inside this exact container/session — if it
|
||||||
|
# doesn't, the wrapper's fullscreen loop just fails silently
|
||||||
|
# (2>/dev/null below) and the app launches exactly as it did before
|
||||||
|
# this existed, so this is safe to try without risking the launch
|
||||||
|
# itself. Regenerated on every call (cheap, stateless — nothing to
|
||||||
|
# lose by overwriting it) so a fix to the wrapper reaches every
|
||||||
|
# existing shortcut the next time it's (re-)added, not just new ones.
|
||||||
|
_SANG_WRAP="$_SANG_EMU_DIR/steam-fullscreen-wrap"
|
||||||
|
cat > "$_SANG_WRAP" << 'WRAPEOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# steam-fullscreen-wrap <real-binary> [args...]
|
||||||
|
# Launches the real target, then repeatedly asks Sway to fullscreen whatever
|
||||||
|
# currently has input focus for a few seconds after launch — the newly
|
||||||
|
# launched window is expected to grab focus once it maps, same as any
|
||||||
|
# ordinary X11/Wayland client. 'fullscreen enable' (not 'toggle') is
|
||||||
|
# idempotent, so repeating it while the window is already fullscreen is a
|
||||||
|
# harmless no-op rather than flipping it back off.
|
||||||
|
REAL_BIN="$1"; shift
|
||||||
|
"$REAL_BIN" "$@" &
|
||||||
|
PID=$!
|
||||||
|
(
|
||||||
|
for _i in $(seq 1 20); do
|
||||||
|
sleep 0.5
|
||||||
|
swaymsg fullscreen enable 2>/dev/null
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
wait "$PID"
|
||||||
|
WRAPEOF
|
||||||
|
chmod +x "$_SANG_WRAP"
|
||||||
|
_SANG_EXE="/home/retro/Applications/steam-fullscreen-wrap"
|
||||||
|
|
||||||
STEAM_HOME=$(_steam_home)
|
STEAM_HOME=$(_steam_home)
|
||||||
if [ -z "$STEAM_HOME" ]; then
|
if [ -z "$STEAM_HOME" ]; then
|
||||||
echo "No Steam home found yet under ${WOLF_STATE_DIR:-/etc/wolf}."
|
echo "No Steam home found yet under ${WOLF_STATE_DIR:-/etc/wolf}."
|
||||||
@@ -4100,10 +4141,10 @@ except Exception:
|
|||||||
sleep 3
|
sleep 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sudo python3 - "$_SANG_VDF" "$_SANG_EXE" "$_SANG_NAME" "/home/retro/Applications" << 'VDFPY'
|
sudo python3 - "$_SANG_VDF" "$_SANG_EXE" "$_SANG_NAME" "/home/retro/Applications" "$_SANG_REAL_EXE" << 'VDFPY'
|
||||||
import sys, struct, os, zlib
|
import sys, struct, os, zlib
|
||||||
|
|
||||||
path, exe_path, app_name, start_dir = sys.argv[1:5]
|
path, exe_path, app_name, start_dir, real_exe = sys.argv[1:6]
|
||||||
|
|
||||||
TYPE_MAP, TYPE_STR, TYPE_INT, TYPE_END = 0x00, 0x01, 0x02, 0x08
|
TYPE_MAP, TYPE_STR, TYPE_INT, TYPE_END = 0x00, 0x01, 0x02, 0x08
|
||||||
|
|
||||||
@@ -4167,13 +4208,30 @@ if shortcuts_entry is None:
|
|||||||
|
|
||||||
entries_list = shortcuts_entry[2]
|
entries_list = shortcuts_entry[2]
|
||||||
|
|
||||||
|
# exe_path now points at the shared steam-fullscreen-wrap script (same Exe
|
||||||
|
# for every emulator added this way), with the real per-emulator target
|
||||||
|
# carried in LaunchOptions instead — so matching (for both idempotent
|
||||||
|
# re-adds and appid uniqueness) has to key on the (exe, LaunchOptions) PAIR,
|
||||||
|
# not exe alone, or adding a second emulator would silently overwrite the
|
||||||
|
# first one's shortcut entry. Also cleans up a legacy entry from before this
|
||||||
|
# wrapper existed, where Exe pointed directly at this same real binary with
|
||||||
|
# no LaunchOptions at all — re-adding an emulator added under the old
|
||||||
|
# scheme replaces that stale direct-launch entry instead of leaving a
|
||||||
|
# duplicate tile behind.
|
||||||
quoted_exe = f'"{exe_path}"'
|
quoted_exe = f'"{exe_path}"'
|
||||||
entries_list[:] = [e for e in entries_list if get_field(e[2], 'exe') != quoted_exe]
|
quoted_launch = f'"{real_exe}"'
|
||||||
|
entries_list[:] = [
|
||||||
|
e for e in entries_list
|
||||||
|
if not (
|
||||||
|
(get_field(e[2], 'exe') == quoted_exe and get_field(e[2], 'LaunchOptions') == quoted_launch)
|
||||||
|
or get_field(e[2], 'exe') == quoted_launch
|
||||||
|
)
|
||||||
|
]
|
||||||
for idx, e in enumerate(entries_list):
|
for idx, e in enumerate(entries_list):
|
||||||
e[0] = str(idx)
|
e[0] = str(idx)
|
||||||
|
|
||||||
new_index = str(len(entries_list))
|
new_index = str(len(entries_list))
|
||||||
crc_input = (exe_path + app_name).encode('utf-8')
|
crc_input = (exe_path + real_exe + app_name).encode('utf-8')
|
||||||
appid = (zlib.crc32(crc_input) | 0x80000000) & 0xFFFFFFFF
|
appid = (zlib.crc32(crc_input) | 0x80000000) & 0xFFFFFFFF
|
||||||
appid_signed = appid - 0x100000000 if appid >= 0x80000000 else appid
|
appid_signed = appid - 0x100000000 if appid >= 0x80000000 else appid
|
||||||
|
|
||||||
@@ -4184,7 +4242,7 @@ new_entry_fields = [
|
|||||||
['StartDir', TYPE_STR, f'"{start_dir}"'],
|
['StartDir', TYPE_STR, f'"{start_dir}"'],
|
||||||
['icon', TYPE_STR, ''],
|
['icon', TYPE_STR, ''],
|
||||||
['ShortcutPath', TYPE_STR, ''],
|
['ShortcutPath', TYPE_STR, ''],
|
||||||
['LaunchOptions', TYPE_STR, ''],
|
['LaunchOptions', TYPE_STR, quoted_launch],
|
||||||
['IsHidden', TYPE_INT, 0],
|
['IsHidden', TYPE_INT, 0],
|
||||||
['AllowDesktopConfig', TYPE_INT, 1],
|
['AllowDesktopConfig', TYPE_INT, 1],
|
||||||
['AllowOverlay', TYPE_INT, 1],
|
['AllowOverlay', TYPE_INT, 1],
|
||||||
@@ -4200,12 +4258,12 @@ entries_list.append([new_index, TYPE_MAP, new_entry_fields])
|
|||||||
|
|
||||||
with open(path, 'wb') as f:
|
with open(path, 'wb') as f:
|
||||||
f.write(serialize_map(root))
|
f.write(serialize_map(root))
|
||||||
print(f"Wrote shortcuts.vdf: {app_name} -> {exe_path} (appid {appid_signed})")
|
print(f"Wrote shortcuts.vdf: {app_name} -> {real_exe} (via {exe_path}, appid {appid_signed})")
|
||||||
VDFPY
|
VDFPY
|
||||||
sudo chown 1000:1000 "$_SANG_VDF"
|
sudo chown 1000:1000 "$_SANG_VDF"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Added '$_SANG_NAME' -> $_SANG_EXE to Steam's shortcuts.vdf."
|
echo "Added '$_SANG_NAME' -> $_SANG_REAL_EXE (via the fullscreen wrapper) to Steam's shortcuts.vdf."
|
||||||
echo "Open Steam in Moonlight (it will restart since it was stopped above) —"
|
echo "Open Steam in Moonlight (it will restart since it was stopped above) —"
|
||||||
echo "the new tile appears in your Library (may need the Library view, not just Home)."
|
echo "the new tile appears in your Library (may need the Library view, not just Home)."
|
||||||
echo "First launch: right-click it -> Properties -> Compatibility, and confirm"
|
echo "First launch: right-click it -> Properties -> Compatibility, and confirm"
|
||||||
@@ -5314,10 +5372,60 @@ controllers per player slot even when the physical controllers are
|
|||||||
identical models (the same case \`./manage.sh controllers\` exists to work
|
identical models (the same case \`./manage.sh controllers\` exists to work
|
||||||
around for ES-DE). Add Cemu here, then in Steam's own Big Picture
|
around for ES-DE). Add Cemu here, then in Steam's own Big Picture
|
||||||
Controller Settings you can see and assign each detected controller
|
Controller Settings you can see and assign each detected controller
|
||||||
individually. This hasn't been confirmed live yet against Wolf's
|
individually.
|
||||||
container-created virtual controllers specifically (real hardware behaves
|
|
||||||
this way; whether Steam Input sees Wolf's virtual joypads the same way is
|
**Controller doesn't respond at all once added to Steam?** Confirmed live:
|
||||||
still to be tested) — worth trying before assuming it works.
|
this is Steam Input, not the emulator — by default Steam applies its own
|
||||||
|
controller configuration to *every* shortcut, Steam or non-Steam alike,
|
||||||
|
and a freshly-added non-Steam game with no configuration picked yet can
|
||||||
|
end up with no usable mapping at all rather than passing raw input
|
||||||
|
through. Fix from Steam's own Big Picture UI: select the shortcut → the
|
||||||
|
controller icon / **Manage Game** → **Controller Options**, and either
|
||||||
|
pick a **Gamepad** template (closest to "pass it through as a normal
|
||||||
|
joystick", needed for ES-DE/RetroArch's own native SDL input handling to
|
||||||
|
see it at all) or turn **Steam Input** off for that one shortcut entirely
|
||||||
|
if you don't need the per-device assignment this section is about in the
|
||||||
|
first place. This is a one-time, per-shortcut setting Steam remembers —
|
||||||
|
not something this installer can preconfigure from the command line, since
|
||||||
|
it's stored in Steam's own (separate, Steam Cloud-synced) controller
|
||||||
|
config rather than \`shortcuts.vdf\`.
|
||||||
|
|
||||||
|
**Opens at roughly half the screen instead of fullscreen?** Also confirmed
|
||||||
|
live, and now worked around automatically as of the version of this repo
|
||||||
|
that added the point below — \`steam-add-nonsteam-game\`/
|
||||||
|
\`steam-setup-frontends\` route the launch through a small wrapper
|
||||||
|
(\`emulators/steam-fullscreen-wrap\`) instead of pointing Steam's \`Exe\`
|
||||||
|
directly at the AppImage. The underlying cause: a non-Steam game launched
|
||||||
|
from Steam is a *second* top-level window inside Wolf's single-app Steam
|
||||||
|
Sway session, and Sway's own kiosk config only auto-fullscreens the ONE
|
||||||
|
window it expects (Steam's own) — anything launched from inside Steam
|
||||||
|
opens at whatever default size it requests instead. The wrapper launches
|
||||||
|
the real binary, then repeatedly asks Sway to fullscreen whatever currently
|
||||||
|
has focus for a few seconds after launch (idempotent — harmless if it's
|
||||||
|
already fullscreen). **This has not been confirmed live against a real
|
||||||
|
Wolf Steam session yet** — if \`swaymsg\` isn't reachable from inside that
|
||||||
|
exact container, the wrapper's fullscreen loop just fails silently and the
|
||||||
|
window opens at its old default size, same as before this existed; it's
|
||||||
|
safe to try either way since the underlying launch itself is unaffected.
|
||||||
|
Re-run \`steam-add-nonsteam-game\`/\`steam-setup-frontends\` for anything
|
||||||
|
already added before this existed — it replaces the old direct-launch
|
||||||
|
shortcut with the wrapped one automatically, no duplicate tile left behind.
|
||||||
|
|
||||||
|
**An added emulator's tile appears in Steam but crashes on launch instead
|
||||||
|
of opening at all** (as opposed to the half-screen case above, where it
|
||||||
|
does open): that's a different problem — something about the AppImage
|
||||||
|
itself failing to run inside the Steam container specifically, since the
|
||||||
|
same binary launching fine through the \`esde\`/\`desktop\` Wolf apps rules out
|
||||||
|
the AppImage being broken outright. Worth checking before assuming it's
|
||||||
|
unfixable:
|
||||||
|
\`\`\`bash
|
||||||
|
CONTAINER=\$(docker ps --format '{{.Names}}' | grep -i WolfSteam | head -1)
|
||||||
|
docker exec "\$CONTAINER" /home/retro/Applications/<the-appimage-file> ; echo "exit: \$?"
|
||||||
|
\`\`\`
|
||||||
|
Run directly like this (no wrapper, no Steam involved) the real error
|
||||||
|
usually prints straight to the terminal — a missing shared library, a
|
||||||
|
FUSE/AppImage mount failure (\`dlopen(): error loading libfuse.so.2\`),
|
||||||
|
or similar. That output is what actually narrows down the fix.
|
||||||
|
|
||||||
## Running ES-DE and/or RetroArch through Steam instead of their own Wolf apps
|
## Running ES-DE and/or RetroArch through Steam instead of their own Wolf apps
|
||||||
The same Steam Input reasoning above applies beyond just Cemu: ES-DE and
|
The same Steam Input reasoning above applies beyond just Cemu: ES-DE and
|
||||||
|
|||||||
Reference in New Issue
Block a user