Stop unworn input when SteamVR overlay stays hidden

This commit is contained in:
SAPHID committed 2026-10-26 02:06:34 +00:00
1 parent bc72c41be5
commit db079eec9f
4 files changed
+96 -2

No files matched your search

@@ -45,5 +45,58 @@
"controllerHardwareVerified": false,
"wornVisualComfortVerified": false,
"vrKeyboardVerified": false
}
},
"combinedHeadChecks": [
{
"timeUtc": "2026-10-26T02:01:05.938830+00:00",
"head": "bc72c41be5aa4bc80192145afefb1c6fe31a47fc",
"passed": false,
"overlayVisible": false,
"inputPassed": false,
"reason": "Timed out waiting for live UI: 0",
"retaggedTestWindow": true,
"batteryBefore": [
100
],
"batteryAfter": [
99
],
"powerRestored": true,
"lockReleased": true
},
{
"timeUtc": "2026-10-26T02:02:44.600755+00:00",
"head": "bc72c41be5aa4bc80192145afefb1c6fe31a47fc",
"passed": false,
"overlayVisible": false,
"inputPassed": false,
"reason": "Timed out waiting for live UI: 0",
"retaggedTestWindow": true,
"batteryBefore": [
99
],
"batteryAfter": [
99
],
"powerRestored": true,
"lockReleased": true
},
{
"timeUtc": "2026-10-26T02:05:00.560460+00:00",
"head": "bc72c41be5aa4bc80192145afefb1c6fe31a47fc",
"passed": true,
"overlayVisible": true,
"inputPassed": true,
"reason": null,
"retaggedTestWindow": false,
"batteryBefore": [
99
],
"batteryAfter": [
99
],
"powerRestored": true,
"lockReleased": true
}
]
}
@@ -25,3 +25,20 @@ power change.
Synthetic pointer events and captures do not prove physical controller use,
wearer-visible readability, optical comfort or VR keyboard behavior. Those
remain unverified.
## Combined v0.4.39 candidate reruns
After #278 and #279 joined main, the combined `bc72c41` branch ran the same
locked exercise three times. The first two runs (02:01 and 02:02 UTC) loaded
the sample UI in Chromium, but SteamVR kept its overlay hidden even after the
existing test-window focus retry. Synthetic input reached no panel control;
both runs failed. The third run (02:05 UTC) showed the overlay without that
retry and passed the sample setting, input, stereo and mirror checks. Every run
restored the original power settings, removed its recovery timer and released
its own lock with no cleanup errors. The [numeric summary](framey-vr-standby-gate-2026-10-26.json)
records all three outcomes.
The intermittent hidden-overlay condition remains a reliability limit. The
runner now records a small read-only diagnostic and refuses to send synthetic
input if the overlay stays hidden after its focus retry. A successful Chromium
panel alone is not treated as VR visibility.
+3 -1
View File
@@ -62,7 +62,9 @@ not proof of a physical controller or the SteamVR virtual keyboard.
SteamVR can leave a recreated panel hidden with a stale focus request. The
exercise retries once by removing and reapplying `STEAM_GAME` on its own test
browser window, then requests focus again. It never retags another application.
The report records whether this recovery was needed. Registration, dashboard
If the overlay stays hidden, it records a small read-only registration/service
diagnostic and stops before synthetic input. The report records whether this
recovery was needed. Registration, dashboard
visibility, actual panel visibility, and pixel capture are separate checks.
A visible docked panel can report `IsDashboardVisible=false` and
`IsActiveDashboardOverlay=false`. A zero-sized main texture or failed image
+22
View File
@@ -99,6 +99,22 @@ finally: vr.close()
'''
HIDDEN_OVERLAY_DIAGNOSTIC = '''
import json,pathlib,subprocess
key='valve.steam.desktopgame.2001947813'
p=subprocess.run(['/opt/steamvr/bin/linuxarm64/vrcmd','--overlays'],
capture_output=True,text=True,timeout=8)
lines=[line.strip() for line in p.stdout.splitlines() if "'"+key+"'" in line]
service=subprocess.run(['systemctl','--user','is-active','frame-control-headset.service'],
capture_output=True,text=True,timeout=8)
state=pathlib.Path.home()/'.local/share/frame-control/headset/state.json'
try: window=json.loads(state.read_text()).get('window')
except (OSError,ValueError): window=None
print(json.dumps({'overlayLines':lines[:2], 'overlayCommandExit':p.returncode,
'serviceActive':service.stdout.strip()=='active', 'windowRegistered':bool(window)}))
'''
def debug_bundle(original, profile):
"""Only the test-owned browser gets CDP and a disposable profile."""
out = io.BytesIO()
@@ -227,6 +243,12 @@ time.sleep(2)
print('{}')
''')
report['overlay'] = remote.python(diagnostic_source())
if args.exercise and not report['overlay']['state']['visible']:
try:
report['hiddenOverlay'] = remote.python(HIDDEN_OVERLAY_DIAGNOSTIC)
except Exception as exc:
report['hiddenOverlayError'] = str(exc)
raise RuntimeError('Frame Control overlay stayed hidden after focus retry; no input sent')
if args.wake or args.exercise:
shot = remote.python((ROOT/'ui/frame_vrshot.py').read_text(), timeout=20)['path']
try: