VR keyboard: cleanup of the controller bridge, gesture input and docs

- gesture-input.js: drop the unused mode getter and release().
- relay.mjs: both sides have a binding; no condition.
- hub.js: the frame cadence is documented once (bridge-patch.js); errors
  listed.
- docs: the bridge's idle cost and "one word at a time" stated once;
  twoHanded's README row points to the docs; rewrapped lines.
This commit is contained in:
Pierre Kisters committed 2026-10-01 04:01:00 +02:00
1 parent 605e42ffa1
commit 2442527514
6 files changed
+16 -19

No files matched your search

+3 -4
View File
@@ -3,17 +3,16 @@
// extraArgs (like lib/hooks.js): installs window.__sfuiControllers unless an
// equal or newer VERSION is there (a newer one takes over the subscribers)
// and evaluates to it. relay.mjs calls frame(f) with bridge-patch.js's
// frames and lost() when the SteamVR side goes away.
// frames (cadence there) and lost() when the SteamVR side goes away.
// subscribe(fn) -> unsubscribe fn(frame) per frame, fn(null) when lost
// last the last frame (null: none / lost)
// demand(ms) full rate for the next ms (0: end), e.g.
// during a laser press; via the relay's
// CDP binding __sfuiCtlIn
// errors { count, last } of throwing subscribers
// Each frame's hand points (tip, ray) get the keyboard page's px: x, y
// (CSS px of the keyboard popup) and onKeyboard (inside the page), if the
// keyboard popup exists. Frames come at up to ~90 Hz while a hand's tip is
// within 10 cm of the keyboard or its trigger is pulled, else every 1 s, and
// only while SteamVR shows the keyboard (then one with keyboard null).
// keyboard popup exists.
(() => {
const VERSION = 2;
const G = globalThis;
+1 -1
View File
@@ -56,7 +56,7 @@ async function connect(side) {
const closed = new Promise((res) => { ws.onclose = res; });
// No Runtime.enable: bindings work without it, and it would stream the
// page's console and context events here.
if (cfg.binding) send('Runtime.addBinding', { name: cfg.binding });
send('Runtime.addBinding', { name: cfg.binding });
live[side] = (expression) => send('Runtime.evaluate', { expression });
console.log(`${side}: connected`);
await closed;
+1 -3
View File
@@ -30,7 +30,7 @@
// attribution. No fresh frames at the press: touch events only, as without
// the bridge.
(() => {
const VERSION = 2;
const VERSION = 3;
const STALE = 150, GAP = 60, TOL = 30, AGREE = 40, FAR = 60, WAIT = 250, LATE = 60;
function create({ now = () => performance.now() } = {}) {
@@ -89,7 +89,6 @@
VERSION,
get owner() { return owner; },
get hand() { return hand; },
get mode() { return mode; },
stats,
// { phase, id, x, y, target } if the event concerns the gesture (or may
// start one: phase 'down'), else null. An 'up' or 'cancel' ends the
@@ -148,7 +147,6 @@
if (!hand) { waitUntil = touchAt + WAIT; refs = [[c.x, c.y]]; }
return hand;
},
release() { reset(); },
// A bridge frame (null: bridge lost). Returns [x, y] to add to the path, or null.
frame(f) {
const t = now();
+4 -3
View File
@@ -10,9 +10,10 @@
// started on at release. With both lasers on the keyboard the pressing one
// may get no touchmoves; its path then comes from the controller bridge
// (gesture-input.js: the hand whose laser hit the press point; full rate
// asked for from the press to the release). Once a press leaves its first key we drop that
// key from Steam's pending touches (m_mapTouched) and cancel its long press
// (Steam's own touch-end cleanup, minus the typing), then decode the path.
// asked for from the press to the release). Once a press leaves its first
// key we drop that key from Steam's pending touches (m_mapTouched) and
// cancel its long press (Steam's own touch-end cleanup, minus the typing),
// then decode the path.
// - Output: one character or "Backspace" per HandleVirtualKeyDown, the path
// of Steam's own keys (incl. extraKeys' xdotool fallback for non-ASCII,
// which is async: we pause after such characters).