Start · Sprachen · JavaScript · Referenz · XRSession: squeeze

XRSession: squeeze

Ereignis

Wird an eine <code>XRSession</code> gesendet, sobald eine Eingabequelle ihre primäre Squeeze-Aktion abgeschlossen hat, also z. B. der Greiftaster losgelassen wurde.

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

Signatur

xrSession.addEventListener("squeeze", handler)

Beschreibung

Das Ereignis squeeze gehört zu einer Gruppe von Ereignissen, mit denen WebXR die primäre Squeeze-Aktion einer Eingabequelle meldet. Auf den meisten Controllern ist das der seitliche Greiftaster („Grip“). Bei Hand-Tracking kann es auch eine Greifgeste sein. Der Ablauf ist immer derselbe: Zuerst kommt squeezestart, wenn die Aktion beginnt. Wurde sie erfolgreich abgeschlossen, folgt squeeze und direkt danach squeezeend. Wird die Aktion abgebrochen, etwa weil der Controller die Verbindung verliert, kommt nur squeezeend und kein squeeze.

Der Handler erhält ein XRInputSourceEvent. Es enthält die auslösende Eingabequelle (inputSource) und einen XRFrame (frame). Mit diesem Frame lässt sich die Position des Controllers zum Zeitpunkt des Ereignisses abfragen. Er gilt aber nur während des Handler-Aufrufs.

Nutzen Sie squeeze für einzelne, abgeschlossene Aktionen wie „Menü öffnen“ oder „Objekt einmal greifen bzw. ablegen“. Wenn etwas solange passieren soll, wie der Taster gedrückt ist (z. B. ein Objekt festhalten und mitbewegen), eignet sich die Kombination aus squeezestart und squeezeend besser.

Sie können den Handler mit addEventListener("squeeze", …) registrieren oder alternativ über die Eigenschaft XRSession.onsqueeze setzen.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "squeeze".
$handler Pflicht (event: XRInputSourceEvent) => void Callback-Funktion, die ein XRInputSourceEvent erhält. Darin stehen event.inputSource (die auslösende XRInputSource) und event.frame (ein XRFrame, der nur während des Aufrufs gültig ist).
$options boolean|AddEventListenerOptions false Die üblichen Listener-Optionen wie once oder signal.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Rückgabewert des Handlers wird ignoriert.

Beispiele

Squeeze-Aktion mit addEventListener auswerten

const startXR = async () => {
  if (!navigator.xr || !(await navigator.xr.isSessionSupported('immersive-vr'))) {
    console.log('immersive-vr wird nicht unterstützt');
    return;
  }
  const session = await navigator.xr.requestSession('immersive-vr');
  const refSpace = await session.requestReferenceSpace('local');

  session.addEventListener('squeeze', (event) => {
    const { inputSource, frame } = event;
    // Die Pose ist nur innerhalb des Handlers abrufbar
    const pose = frame.getPose(inputSource.gripSpace ?? inputSource.targetRaySpace, refSpace);
    console.log(`Squeeze an Hand: ${inputSource.handedness}`);
    if (pose) {
      const { x, y, z } = pose.transform.position;
      console.log(`Position: ${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)}`);
    }
  });
};

// requestSession braucht eine Nutzeraktion
document.querySelector('#enter-vr').addEventListener('click', startXR);
Squeeze an Hand: left Position: -0.21, 1.12, -0.35

Menü per onsqueeze umschalten und Handler wieder entfernen

let menuVisible = false;

const toggleMenu = (event) => {
  // Nur auf den linken Controller reagieren
  if (event.inputSource.handedness !== 'left') return;
  menuVisible = !menuVisible;
  console.log(`Menü ${menuVisible ? 'geöffnet' : 'geschlossen'}`);
};

const setupSession = (session) => {
  // Variante über die on-Property
  session.onsqueeze = toggleMenu;

  session.addEventListener('end', () => {
    session.onsqueeze = null; // Handler entfernen
    console.log('Sitzung beendet, Handler entfernt');
  });
};
Menü geöffnet Menü geschlossen Sitzung beendet, Handler entfernt

Vollständigen Ablauf squeezestart → squeeze → squeezeend protokollieren

const logSqueezeLifecycle = (session) => {
  const controller = new AbortController();
  const { signal } = controller;
  const pressed = new Set();

  session.addEventListener('squeezestart', (e) => {
    pressed.add(e.inputSource);
    console.log('squeezestart');
  }, { signal });

  session.addEventListener('squeeze', () => {
    console.log('squeeze (erfolgreich abgeschlossen)');
  }, { signal });

  session.addEventListener('squeezeend', (e) => {
    pressed.delete(e.inputSource);
    console.log('squeezeend');
  }, { signal });

  // Alle drei Listener auf einmal entfernen
  session.addEventListener('end', () => controller.abort(), { once: true });
};
squeezestart squeeze (erfolgreich abgeschlossen) squeezeend

// Wichtig · Fallstricke

  • Nur für abgeschlossene Aktionen: Wird die Aktion abgebrochen, bleibt squeeze aus. Aufräumarbeiten (z. B. ein festgehaltenes Objekt loslassen) gehören deshalb in squeezeend, nicht in squeeze.
  • Frame nur kurz gültig: event.frame ist nur während des Handler-Aufrufs aktiv. Ein späterer Aufruf von frame.getPose(), etwa in einem setTimeout oder nach await, wirft einen InvalidStateError.
  • Nicht jedes Gerät hat eine Squeeze-Aktion: Einfache Controller, Blick- oder Bildschirmeingabe (z. B. Handheld-AR) bieten oft keine. Planen Sie deshalb eine Alternative über select ein.
  • Auch in transienten Sitzungen: Das Ereignis kann ebenso in immersive-ar-Sitzungen auftreten.
  • Kompatibilität: WebXR steht nur in sicheren Kontexten (HTTPS) zur Verfügung und funktioniert vor allem in Chromium-Browsern und im Meta Quest Browser. Firefox und Safari (Desktop) unterstützen es nicht, Safari auf der Apple Vision Pro nur eingeschränkt. Prüfen Sie vorher mit navigator.xr?.isSessionSupported().
  • Für Tastenwerte, die nicht zur primären Squeeze-Aktion gehören, fragen Sie im Render-Loop inputSource.gamepad.buttons ab.