Start · Sprachen · JavaScript · Referenz · XRInputSourceEvent.inputSource

XRInputSourceEvent.inputSource

Eigenschaft

Die schreibgeschützte Eigenschaft <code>inputSource</code> liefert das <code>XRInputSource</code>-Objekt des Eingabegeräts (Controller, Hand, Blick), das das Ereignis ausgelöst hat.

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

Signatur

XRInputSourceEvent.inputSource

Beschreibung

Die Eigenschaft inputSource eines XRInputSourceEvent verweist auf die XRInputSource, von der das Ereignis ausgeht. Solche Ereignisse löst eine XRSession bei primären Aktionen aus: select, selectstart, selectend (z. B. Abzug oder Pinch-Geste) sowie squeeze, squeezestart und squeezeend (Greiftaste).

Über das zurückgegebene Objekt lässt sich feststellen, welches Gerät die Aktion ausgelöst hat: handedness ("left", "right", "none"), targetRayMode ("tracked-pointer", "gaze", "screen", "transient-pointer"), profiles, gamepad und hand. Vor allem aber liefern targetRaySpace und gripSpace die Räume, mit denen du über event.frame.getPose() die Position und Ausrichtung des Zeigestrahls genau zum Zeitpunkt des Ereignisses bestimmen kannst.

Typische Anwendungen sind Raycasting zum Auswählen von Objekten, das Unterscheiden von linker und rechter Hand (z. B. linke Hand = Menü, rechte Hand = Werkzeug) und die Zuordnung von selectstart/selectend-Paaren zum selben Controller bei Drag-Interaktionen.

Rückgabewert

Typ
XRInputSource
Beschreibung
Das XRInputSource-Objekt des Eingabegeräts, das das Ereignis erzeugt hat. Während die Quelle verbunden ist, bleibt es dieselbe Objektinstanz, daher kann man es als Schlüssel (z. B. in einer Map) verwenden.

Beispiele

Hand des auslösenden Controllers bestimmen

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

  session.addEventListener('select', (event) => {
    const { handedness, targetRayMode, profiles } = event.inputSource;
    console.log(`Auswahl durch ${handedness}-Eingabe (${targetRayMode})`);
    console.log('Profile:', profiles.join(', '));
  });
};

// Muss durch eine Nutzergeste ausgelöst werden
document.querySelector('#vr-button').addEventListener('click', startXR);
Auswahl durch right-Eingabe (tracked-pointer) Profile: oculus-touch-v3, oculus-touch-v2, oculus-touch, generic-trigger-squeeze-thumbstick

Zeigestrahl zum Zeitpunkt des Ereignisses auslesen (Raycasting)

let refSpace;

const onSelect = (event) => {
  // event.frame ist nur während des Handlers gültig
  const pose = event.frame.getPose(event.inputSource.targetRaySpace, refSpace);
  if (!pose) return; // Tracking verloren

  const { position, orientation } = pose.transform;
  console.log('Strahlursprung:', position.x.toFixed(2), position.y.toFixed(2), position.z.toFixed(2));
  console.log('Ausrichtung (Quaternion):', orientation.w.toFixed(2));
  // hier: Strahl gegen die Szene testen und Treffer hervorheben
};

const init = async () => {
  const session = await navigator.xr.requestSession('immersive-vr');
  refSpace = await session.requestReferenceSpace('local');
  session.addEventListener('select', onSelect);
};

document.querySelector('#vr-button').addEventListener('click', init);
Strahlursprung: 0.21 -0.34 -0.12 Ausrichtung (Quaternion): 0.97

Drag-Interaktion pro Controller verfolgen

const activeDrags = new Map();

const setupDragging = (session) => {
  session.onselectstart = (event) => {
    activeDrags.set(event.inputSource, { start: performance.now() });
    console.log(`Drag gestartet: ${event.inputSource.handedness}`);
  };

  session.onselectend = (event) => {
    const drag = activeDrags.get(event.inputSource);
    if (!drag) return;
    const dauer = Math.round(performance.now() - drag.start);
    console.log(`Drag beendet: ${event.inputSource.handedness} nach ${dauer} ms`);
    activeDrags.delete(event.inputSource);
  };

  // Getrennte Controller aufräumen
  session.addEventListener('inputsourceschange', ({ removed }) => {
    removed.forEach((source) => activeDrags.delete(source));
  });
};

document.querySelector('#vr-button').addEventListener('click', async () => {
  const session = await navigator.xr.requestSession('immersive-vr');
  setupDragging(session);
});
Drag gestartet: left Drag beendet: left nach 842 ms

// Wichtig · Fallstricke

  • Schreibgeschützt: Die Eigenschaft wird im Konstruktor new XRInputSourceEvent(type, { frame, inputSource }) gesetzt und kann danach nicht geändert werden.
  • Frame nur kurz gültig: event.frame.getPose() funktioniert nur synchron im Handler. Wer die Pose später braucht (z. B. nach einem await oder in einem setTimeout), muss sie im Handler kopieren. Sonst gibt es einen InvalidStateError.
  • Transiente Quellen: Bei targetRayMode "screen" (AR auf dem Smartphone) oder "transient-pointer" gibt es die Quelle nur für die Dauer der Geste. Sie steht daher oft nicht dauerhaft in session.inputSources.
  • getPose() kann null zurückgeben, wenn das Tracking verloren geht. Prüfe das immer.
  • inputSource.gamepad und inputSource.hand können null sein, je nach Gerät und aktivierten Features (hand-tracking muss bei requestSession angefordert werden).
  • Kompatibilität: WebXR braucht einen sicheren Kontext (HTTPS). Unterstützt wird es vor allem in Chromium-Browsern und im Meta Quest Browser. Firefox und Safari auf dem Desktop unterstützen es nicht. Safari auf der Apple Vision Pro unterstützt WebXR, dort wird der Pinch als "transient-pointer" gemeldet. Prüfe die Unterstützung vorher mit navigator.xr?.isSessionSupported().