Start · Sprachen · JavaScript · Referenz · XRSession.inputSources

XRSession.inputSources

Eigenschaft

Schreibgeschützte Eigenschaft, die ein <code>XRInputSourceArray</code> mit allen aktuell mit der XR-Sitzung verbundenen Eingabequellen (Controller, Hände, Blick, Bildschirm-Tap) liefert.

seit JavaScript WebXR Device API – Chromium-Browser (Chrome/Edge 7 Kategorie: webapi

Signatur

XRSession.inputSources

Beschreibung

Die Eigenschaft inputSources einer XRSession liefert ein XRInputSourceArray. Darin steht für jedes Eingabegerät, das gerade mit dem XR-Gerät verbunden ist, ein XRInputSource-Objekt: Handcontroller, erkannte Hände (Hand-Tracking), Blicksteuerung (targetRayMode "gaze") oder Bildschirmberührungen in AR-Sitzungen auf dem Smartphone ("screen").

Das Array ist live. Es wird vom Browser laufend aktualisiert, sobald Geräte verbunden oder getrennt werden. Ein XRInputSourceArray ist array-ähnlich: Es hat length, einen Indexzugriff sowie forEach(), entries(), keys() und values() und lässt sich mit for...of durchlaufen. Methoden wie map() oder filter() fehlen jedoch. Für sie wandelt man es zuerst mit Array.from() um.

Typischerweise liest man inputSources in jedem Frame der Render-Schleife (requestAnimationFrame) aus. Dort ermittelt man mit frame.getPose(source.targetRaySpace, refSpace) die Zeigerichtung und mit source.gripSpace die Position der Hand. Knöpfe und Achsen fragt man über source.gamepad ab. Auf Änderungen der Geräteliste reagiert man über das Ereignis inputsourceschange.

Rückgabewert

Typ
XRInputSourceArray
Beschreibung
Ein live aktualisiertes, array-ähnliches Objekt mit einem XRInputSource pro verbundener Eingabequelle. Ist nichts verbunden, ist es leer (length === 0).

Beispiele

Verbundene Eingabequellen nach Sitzungsstart auflisten

const startXR = async () => {
  const session = await navigator.xr.requestSession('immersive-vr');

  for (const source of session.inputSources) {
    console.log(`Hand: ${source.handedness}, Modus: ${source.targetRayMode}, Profile: ${source.profiles.join(', ')}`);
  }
  console.log(`Anzahl: ${session.inputSources.length}`);
};

document.querySelector('#vr-button').addEventListener('click', startXR);
Hand: left, Modus: tracked-pointer, Profile: oculus-touch-v3, generic-trigger-squeeze-thumbstick Hand: right, Modus: tracked-pointer, Profile: oculus-touch-v3, generic-trigger-squeeze-thumbstick Anzahl: 2

Zeigestrahl und Trigger in der Render-Schleife auswerten

const runLoop = async (session) => {
  const refSpace = await session.requestReferenceSpace('local-floor');

  const onFrame = (time, frame) => {
    session.requestAnimationFrame(onFrame);

    for (const source of frame.session.inputSources) {
      const rayPose = frame.getPose(source.targetRaySpace, refSpace);
      if (!rayPose) continue; // Tracking kurzzeitig verloren

      const { x, y, z } = rayPose.transform.position;
      const triggerPressed = source.gamepad?.buttons[0]?.pressed ?? false;

      if (triggerPressed) {
        console.log(`${source.handedness}: Trigger bei (${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)})`);
      }
    }
  };

  session.requestAnimationFrame(onFrame);
};
right: Trigger bei (0.21, 1.34, -0.40)

Auf Geräteänderungen reagieren und nach Händigkeit filtern

const setupInputs = (session) => {
  const controllers = new Map();

  session.addEventListener('inputsourceschange', ({ added, removed }) => {
    added.forEach((src) => controllers.set(src.handedness, src));
    removed.forEach((src) => controllers.delete(src.handedness));
    console.log('Aktiv:', [...controllers.keys()]);
  });

  // XRInputSourceArray hat kein filter() – vorher umwandeln
  const handTracked = Array.from(session.inputSources).filter((s) => s.hand);
  console.log(`Hand-Tracking-Quellen: ${handTracked.length}`);
};
Hand-Tracking-Quellen: 0 Aktiv: [ 'left', 'right' ]

// Wichtig · Fallstricke

  • Live-Objekt: Wer den Inhalt einmalig in eine eigene Variable kopiert, hat danach veraltete Daten. Man sollte die Eigenschaft deshalb in jedem Frame neu lesen oder auf inputsourceschange reagieren.
  • Kein echtes Array: map(), filter() und find() gibt es nicht. Vorher mit Array.from() oder dem Spread-Operator umwandeln.
  • Kurz nach dem Start oft leer: Direkt nach requestSession() kann das Array noch leer sein, weil die Controller erst später gemeldet werden. Dafür ist inputsourceschange zuverlässiger.
  • Instabile Objekte: Wird ein Gerät getrennt und wieder verbunden, entsteht ein neues XRInputSource-Objekt. Referenzen auf das alte Objekt sollte man in removed freigeben.
  • source.gamepad ist bei Blick- oder Bildschirm-Eingaben oft null. Deshalb optionale Verkettung (?.) verwenden. Für einfache Klicks eignen sich die Sitzungsereignisse select und squeeze besser als das Abfragen der Knöpfe in jedem Frame.
  • Kompatibilität: WebXR braucht einen sicheren Kontext (HTTPS). Unterstützt wird es vor allem von Chromium-Browsern und dem Meta Quest Browser. Firefox (Desktop) und Safari bieten keine bzw. nur eingeschränkte Unterstützung (visionOS). Vorher mit navigator.xr?.isSessionSupported() prüfen.
  • Nach session.end() sind die Eingabequellen nicht mehr gültig.