Files
DeeJanuz--frametop/input/steamui.py
T
DeeJanuzandClaude Opus 5.5 2d985573c0 Gaze first: abandoned; keep the controller experiment for reference
The last state of the experiment, kept on this branch only:
- input/gazefirst.py, input/steamui.py: the relay reading the controllers from
  vrserver's web socket, switching the compositor binding, and driving the Steam
  UI filter (whose block now expires unless renewed).
- The helper's trigger and bumper holds (steered by the controller's position),
  the laser keeper, and the click gate that waits for the laser.
- pointer/probe/focustest (overlay flag 1 << 4, as an input client too),
  vrsetting (SteamVR settings through vrserver), lasertest --reclaim.

Every press and release Steam sees takes SteamVR out of laser mode, and taking
the laser back breaks clicks and drags. See docs/gaze-controllers.md on
experimental.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 21:11:40 -06:00

41 lines
1.7 KiB
Python

"""steamui: run JavaScript in Steam's UI (its SharedJSContext) through Steam's CEF debugger on
127.0.0.1:8080, with nothing but the standard library (input/vrws.py's web socket client).
evaluate(expression) the expression's value (JSON-able), or an OSError when Steam or its
UI isn't there, or a RuntimeError when the script threw
"""
import json
import time
import urllib.request
from vrws import VrSocket
DEBUGGER = "http://127.0.0.1:8080"
def evaluate(expression, target="SharedJSContext", timeout=2.0):
with urllib.request.urlopen(f"{DEBUGGER}/json", timeout=timeout) as resp:
pages = json.load(resp)
url = next((p.get("webSocketDebuggerUrl") for p in pages if p.get("title") == target), None)
if not url:
raise OSError(f"Steam's {target} isn't open")
ws = VrSocket(timeout=timeout, url=url)
try:
ws.send(json.dumps({"id": 1, "method": "Runtime.evaluate",
"params": {"expression": expression, "returnByValue": True}}))
deadline = time.monotonic() + timeout
while True:
left = deadline - time.monotonic()
msg = ws.recv(timeout=max(left, 0)) if left > 0 else None
if msg is None:
raise OSError("Steam's UI didn't answer")
if isinstance(msg, dict) and msg.get("id") == 1:
break
finally:
ws.close()
result = msg.get("result") or {}
if "exceptionDetails" in result:
details = result["exceptionDetails"]
raise RuntimeError((details.get("exception") or {}).get("description") or details.get("text", "error"))
return (result.get("result") or {}).get("value")