keyboard.vr.touchTyping (off by default): a key is pressed when a
controller's tip, where SteamVR's laser starts (/pose/tip: the device pose
times the render model's "tip" component), passes through it from the
front; released when pulled back 1 cm, re-armed 5 mm in front. Both hands,
also at once. Keys go through the keyboard's own HandleTouchStart /
HandleTouchEnd, like a laser press (Backspace repeats while held). Options
depth (cm) and haptics.
The geometry lives in a reusable controller bridge (vr-keyboard-controllers,
internal option): a systemui patch reads the keyboard's pose with SteamVR's
SGQueryService (an empty transform of ours in the keyboard's mount) and both
controllers' poses, and streams per hand the tip, the laser's hit on the
keyboard and the trigger (~90 Hz while relevant) through the
vr-keyboard-controllers-relay service to __sfuiControllers in Steam's
SharedJSContext. Tests: flake checks vr-keyboard-controllers and
vr-keyboard-touch.
On SIGTERM the periodic (and debounced) re-injection of injector.mjs and
helper.mjs could still run while or after the unpatch was evaluated, leaving
the page patched after the service was gone (e.g. a feature just turned off).
helper.mjs also gets a timeout on /json/list, like the injector.
The policy for the `state = true` files
(~/.local/state/steam-frame-nix/ui-patches/<name>.json), now stated in the
option, the injector and the README: they are user data, kept when a patch
is disabled or removed (the choices come back when it is enabled again),
and removed only by `steam-frame-nix-cleanup --all` / `install.sh
uninstall`; `--orphans` removes stale *.json.tmp only.
frame-controls v6 drops v5's one-time read of version 4's localStorage copy:
steamvr.service deletes ~/.cache/SteamVR (and with it that localStorage) on
every SteamVR start, so there is nothing left to migrate.
SteamOS's steamvr.service runs `rm -rf ~/.cache/SteamVR` on every SteamVR
start, which deletes vrwebhelper's browser profile and with it the
localStorage frame-controls kept its placements in, so they were lost on
every SteamVR restart and reboot.
steam-ui-patches: per-patch persistent state (`state = true`). The injector
keeps ~/.local/state/steam-frame-nix/ui-patches/<name>.json, seeds
window.__sfuiStore in a fresh page before the patch runs and writes the file
(atomically, on change, name-checked, max 64 KiB) when the page calls the
CDP binding __sfuiStoreSave.
frame-controls v5: placements saved there (v4 localStorage copy migrated
once, then removed). steam-close-button v8: "Steam hidden" saved there; a
restored hidden state hides Steam once if SteamVR already shows it when the
patch attaches (or first shows it before the patch sees Steam's frame).
README: "Changes outside Nix" lists the directory; install.sh uninstall
removes it.
steamFrame.uiPatches.patches registers JS patches that the
steam-ui-patches user service keeps injected into Steam's (or SteamVR's)
web UI over the local CEF DevTools ports and reverts when it stops.
steamFrame.launcherMenu uses it for the VR "+" menu: sort = true sorts
the programs by name; pinDesktop = "top" / "bottom" pins Desktop above or
below the scrolling list.