mirror of
https://github.com/Andalu30/frame-unboundedMouse-vibed.git
synced 2026-10-06 01:00:03 +02:00
4.5 KiB
4.5 KiB
Steam Frame background: why the mouse is trapped, and why a driver fixes it
These are findings from read-only exploration of a Steam Frame on 2026-10-01 (SteamOS 0.4.2 VR, build 20260928.6175029). Paths and versions may change with updates.
The display chain
The KDE desktop doesn't run on the hardware. It is nested several layers deep:
DSI-1 panel (2× 2160x2160 @ 108/120/144 Hz)
└─ vrcompositor (SteamVR) owns the panel
└─ gamescope --backend openvr draws each app as a VR overlay (--virtual-connector-strategy PerAppId)
│ --output-width 1920 --output-height 1080, --vr-overlay-physical-width 2.67
└─ Xwayland :0
└─ kwin_wayland (X11 *windowed* backend), started by /usr/bin/steamos-nested-desktop with --width 1280 --height 800
└─ Plasma + apps
- Steam's "Desktop" entry is
/usr/share/applications/deckard-nested-desktop.desktop. "Deckard" is the Frame's internal codename. - Gamescope's arguments are hardcoded in
/usr/lib/steamos/gamescope-sessionand run from the user unitgamescope-session.service. That unit isPartOf=steamvr.service, which is why restarting SteamVR kills the desktop. - Gamescope resizes KWin's window to its own 1920×1080 output, whatever size KWin asks for.
The input path
/dev/input/eventX (mouse) → gamescope (libinput) → focused overlay's Xwayland → KWin (as X11 events)
- KWin on the X11 windowed backend never uses libinput, so KDE's mouse and keyboard settings pages are empty.
/org/kde/KWin/InputDevicedoesn't exist. - Gamescope delivers the mouse only to its focused overlay, clamped to that surface. This is the "bounded" mouse the project is named after.
The laser pointer
- The laser belongs to vrcompositor. It casts a ray from a pose and sends the overlay it hits
VREvent_MouseMove/ButtonDown/ButtonUp/.... Gamescope turns those into pointer input for its clients. - The actions are in
/opt/steamvr/resources/config/vrcompositor_actions.json. The important one is/actions/lasermouse/in/Pointer(type pose, mandatory), plus LeftClick, RightClick, MiddleClick, scroll and others. - Frame controller bindings (
/opt/steamvr/drivers/frame_controller/resources/input/vrcompositor_bindings_frame_controller.json):- Pointer ←
/user/hand/*/pose/tip - LeftClick ← trigger
- "Quick mouse" (
/actions/quickmouse/in/ActivateQuickMouse) ← squeeze the grip. This just brings the laser up while you're in gamepad mode.
- Pointer ←
- The Frame HMD also has a binding (
drivers/frame_hmd/.../vrcompositor_bindings_frame_hmd.json): Pointer ←/user/head/pose/raw, which is a head-gaze laser. - Key insight: the compositor accepts any pose source for the laser. A virtual device with a mouse-aimed pose is therefore enough, and no compositor hacking is needed. This driver is built on that.
Alternatives that were considered
| idea | why not (yet) |
|---|---|
| Quick mouse | Only an "activate" shortcut. The ray still needs a pose. |
lasermouse mailbox (ws://127.0.0.1:27062, messages dump_laser_overlays, remote_laser_mouse_events, force_activate_laser_mouse) |
The remote-event payload is an undocumented protobuf (VRLink_LaserMouseEvent, from vr_vrlink.proto, built with protobuf-lite so there's no schema in the binary). It seems to be meant for VRLink PC streaming. |
Gamescope flags (--mouse-sensitivity, --force-grab-cursor, overlay size) |
They only change behaviour inside one overlay. |
| Running KWin on DRM/libinput | SteamVR owns the panel. |
Mailbox wire protocol, for reference
This is what the dashboard JS does (/opt/steamvr/resources/webinterface/dashboard/chunk~*.js):
connect ws://127.0.0.1:27062[?secret=...]
send "mailbox_open <name>"
send "mailbox_send <target> <json>" json: {"type": "...", "returnAddress": "<name>", "message_id": N, ...}
recv JSON; replies mirror message_id
Useful locations
| what | where |
|---|---|
| SteamVR runtime | /opt/steamvr (bin/linuxarm64, drivers/, resources/) |
| Driver registration | ~/.config/openvr/openvrpaths.vrpath (vrpathreg show/adddriver/removedriver) |
| User SteamVR settings | ~/.config/openvr/config/steamvr.vrsettings |
| Logs | ~/.local/share/Steam/logs/vrserver.txt, vrcompositor.txt. They're also forwarded to the journal by /usr/share/deckard/steamvr_logs_to_journald.py. |
| OpenVR driver header | /opt/steamvr/tools/hellovr_vulkan_linux/src/openvr/headers/openvr_driver.h (SteamVR 2.1 API: IServerTrackedDeviceProvider_004, ITrackedDeviceServerDriver_005) |