wolf: grant /dev/uinput to the Steam container for Steam Input's virtual controller

Confirmed live: Steam's own controller detection and test screen worked
fine (device listed, buttons fired correctly, Gamepad template applied)
but every actual game — a real Steam title or a non-Steam emulator
shortcut alike — saw no controller at all.

Root cause: Steam Input never hands a game the raw controller device.
It exclusively grabs the raw device for itself and creates its own
synthetic virtual controller via /dev/uinput, then hands that synthetic
device to the game. Reading/testing the raw device (what Steam's own
controller page does) doesn't need uinput; creating the virtual output
device it hands to games does. The 'steam' CATALOG entry only granted
/dev/input/*, /dev/dri/*, /dev/nvidia* via GOW_REQUIRED_DEVICES and had
no devices= list at all — so Steam Input could read the controller but
could never create the virtual device games actually see.

This is the exact same requirement the 'esde' entry already has for
AntiMicroX (also a uinput-based synthetic input tool), including the
same two-part fix noted in its own comment: GOW_REQUIRED_DEVICES alone
only gets the base image's entrypoint script to bind-mount the node —
the container also needs Wolf's own create-time devices= grant to
actually open it. Added /dev/uinput to GOW_REQUIRED_DEVICES and a
devices=['/dev/uinput:/dev/uinput'] entry to both copies of the
'steam' CATALOG dict, matching esde's existing pattern exactly.

update_field() already refreshes an existing app's 'devices' field on
rerun (added specifically for this same esde/AntiMicroX case per its
own comment), so reselecting Steam via 'sudo ./setup.sh wolf' or
'./manage.sh apps' picks this up without a fresh reinstall.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BWYKEERLA1a7gv86Z4W23
This commit is contained in:
Claude
2026-09-10 18:49:59 +00:00
parent 52c7609050
commit 9524c79557
+32 -2
View File
@@ -2384,12 +2384,27 @@ CATALOG = {
f'{games}/retroarch:/home/retro/.config/retroarch:rw',
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw',
f'{games}/esde-settings:/home/retro/ES-DE/settings:rw'],
# Steam Input needs /dev/uinput for the SAME reason the esde entry
# below needs it for AntiMicroX: it does not hand a game the raw
# controller device at all — it grabs the raw device exclusively for
# itself and creates its OWN synthetic virtual controller via uinput,
# then hands that synthetic device to the game. Confirmed live:
# without this, Steam's own controller test screen reads the raw
# device fine (it does not need uinput for that) and shows a correct
# Gamepad template, but every actual game — Steam title or non-Steam
# shortcut alike — sees no controller at all, since Steam Input can
# never create the virtual device it is supposed to hand off. Same
# devices= grant pattern as esde below: GOW_REQUIRED_DEVICES alone
# only gets the base image's entrypoint script to bind-mount the
# node; the container also needs Wolf's own create-time device grant
# to actually open it.
env=['PROTON_LOG=1', 'RUN_SWAY=true',
'GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*'],
'GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/* /dev/dri/* /dev/nvidia*'],
cap_add=['SYS_ADMIN', 'SYS_NICE', 'SYS_PTRACE', 'NET_RAW', 'MKNOD', 'NET_ADMIN'],
security_opt=['seccomp=unconfined', 'apparmor=unconfined'],
ipc_mode='host', ulimits=[{'Name': 'nofile', 'Hard': 10240, 'Soft': 10240}],
privileged=False,
devices=['/dev/uinput:/dev/uinput'],
),
'esde': dict(
name='WolfES-DE', title='EmulationStation',
@@ -4813,13 +4828,28 @@ CATALOG = {
f'{games}/retroarch:/home/retro/.config/retroarch:rw',
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw',
f'{games}/esde-settings:/home/retro/ES-DE/settings:rw'],
# Steam Input needs /dev/uinput for the SAME reason the esde entry
# below needs it for AntiMicroX: it does not hand a game the raw
# controller device at all — it grabs the raw device exclusively for
# itself and creates its OWN synthetic virtual controller via uinput,
# then hands that synthetic device to the game. Confirmed live:
# without this, Steam's own controller test screen reads the raw
# device fine (it does not need uinput for that) and shows a correct
# Gamepad template, but every actual game — Steam title or non-Steam
# shortcut alike — sees no controller at all, since Steam Input can
# never create the virtual device it is supposed to hand off. Same
# devices= grant pattern as esde below: GOW_REQUIRED_DEVICES alone
# only gets the base image's entrypoint script to bind-mount the
# node; the container also needs Wolf's own create-time device grant
# to actually open it.
env=['PROTON_LOG=1', 'RUN_SWAY=true',
'GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*'],
'GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/* /dev/dri/* /dev/nvidia*'],
cap_add=['SYS_ADMIN', 'SYS_NICE', 'SYS_PTRACE', 'NET_RAW', 'MKNOD', 'NET_ADMIN'],
security_opt=['seccomp=unconfined', 'apparmor=unconfined'],
ipc_mode='host',
ulimits=[{'Name': 'nofile', 'Hard': 10240, 'Soft': 10240}],
privileged=False,
devices=['/dev/uinput:/dev/uinput'],
),
'esde': dict(
name='WolfES-DE', title='EmulationStation',