Signatur
Beschreibung
XRInputSource steht für genau ein Eingabegerät, mit dem der Benutzer in einer WebXR-Sitzung interagiert: einen Motion-Controller in der linken oder rechten Hand, eine per Kamera getrackte Hand, ein blickgesteuertes System (Gaze) oder einen Tipp auf den Bildschirm bei AR auf dem Smartphone. Man erzeugt diese Objekte nicht selbst. Der Browser stellt sie über XRSession.inputSources bereit, eine Liste vom Typ XRInputSourceArray, sowie über die Eigenschaft inputSource von Events wie select, squeeze und inputsourceschange.
Die wichtigsten Eigenschaften (alle schreibgeschützt):
handedness:"left","right"oder"none".targetRayMode:"tracked-pointer","gaze","screen"oder"transient-pointer". Beschreibt, wie der Zielstrahl entsteht.targetRaySpace: einXRSpacefür den Zielstrahl, etwa zum Zeigen und Auswählen per Raycast.gripSpace: einXRSpacefür die Handposition, um ein Controller-Modell darzustellen. Istnull, wenn das Gerät nicht gehalten wird, z. B. bei Gaze.gamepad: einGamepad-Objekt mit Tasten und Achsen (Layout"xr-standard") odernull.hand: einXRHandmit 25 Gelenken, wenn Hand-Tracking aktiv ist, sonstnull.profiles: ein Array von Profil-Kennungen wie["oculus-touch-v3", "generic-trigger-squeeze-thumbstick"], sortiert vom spezifischsten zum allgemeinsten Profil.
Typischer Ablauf: In jedem Frame (XRSession.requestAnimationFrame) geht man die Liste session.inputSources durch, fragt mit frame.getPose(source.targetRaySpace, refSpace) die Lage des Zielstrahls ab und zeichnet Laserstrahl und Controller-Modell. Aktionen wie „Auswählen“ oder „Greifen“ verarbeitet man am besten über die Events select und squeeze. Für eigene Tastenbelegungen fragt man gamepad.buttons und gamepad.axes ab.
Rückgabewert
XRSession.inputSources oder aus event.inputSource von XRInputSourceEvent.Beispiele
Eingabequellen einer Sitzung auflisten
const session = await navigator.xr.requestSession('immersive-vr');
session.addEventListener('inputsourceschange', (event) => {
for (const source of event.added) {
console.log(
`Neu: ${source.handedness} | ${source.targetRayMode} | ${source.profiles.join(', ')}`
);
}
for (const source of event.removed) {
console.log(`Entfernt: ${source.handedness}`);
}
});
Zielstrahl und Griff-Pose in jedem Frame auslesen
const refSpace = await session.requestReferenceSpace('local-floor');
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
for (const source of session.inputSources) {
const rayPose = frame.getPose(source.targetRaySpace, refSpace);
if (rayPose) {
const { position } = rayPose.transform;
// Laserstrahl ab Controller-Position zeichnen
console.log(source.handedness, position.x.toFixed(2), position.y.toFixed(2), position.z.toFixed(2));
}
if (source.gripSpace) {
const gripPose = frame.getPose(source.gripSpace, refSpace);
// gripPose?.transform.matrix für das Controller-3D-Modell verwenden
}
}
};
session.requestAnimationFrame(onFrame);
Auswahl und Greifen über Events verarbeiten
session.addEventListener('select', (event) => {
const { inputSource, frame } = event;
const pose = frame.getPose(inputSource.targetRaySpace, refSpace);
if (pose) {
console.log(`Auswahl mit ${inputSource.handedness}er Hand`);
// Raycast in die Szene entlang pose.transform
}
});
session.addEventListener('squeeze', ({ inputSource }) => {
console.log(`Greifen: ${inputSource.handedness}`);
});
Thumbstick über das Gamepad-Objekt abfragen
const readThumbstick = (source) => {
const gp = source.gamepad;
if (!gp || gp.mapping !== 'xr-standard') return null;
// xr-standard: axes[2]/axes[3] = Thumbstick X/Y, buttons[0] = Trigger
return {
x: gp.axes[2] ?? 0,
y: gp.axes[3] ?? 0,
trigger: gp.buttons[0]?.value ?? 0,
};
};
for (const source of session.inputSources) {
const state = readThumbstick(source);
if (state) console.log(source.handedness, state);
}
// Wichtig · Fallstricke
- Kompatibilität: Wird von Chromium-Browsern (Chrome, Edge, Meta Quest Browser, Samsung Internet) und Safari auf der Apple Vision Pro unterstützt, dort vor allem mit
"transient-pointer". Firefox auf dem Desktop unterstützt WebXR nicht. Die API funktioniert nur in sicheren Kontexten (HTTPS) und kann per Permissions-Policyxr-spatial-trackinggesperrt sein. - Instanzen können sich ändern: Wenn ein Controller neu verbunden wird oder zwischen Controller und Hand-Tracking umgeschaltet wird, entstehen neue Objekte. Man sollte daher keine Referenzen dauerhaft zwischenspeichern, sondern auf
inputsourceschangereagieren. - Posen können fehlen:
frame.getPose()gibtnullzurück, wenn das Tracking verloren geht.gripSpace,gamepadundhandkönnen ebenfallsnullsein. Diese Fälle immer abfragen. transient-pointerundscreenexistieren nur während einer Interaktion und tauchen dann kurz ininputSourcesauf.- Hand-Tracking muss beim Start mit
optionalFeatures: ['hand-tracking']angefordert werden, sonst isthandimmernull. - Datenschutz: Wenn die Seite nicht im Fokus ist (
visibilityStateist"visible-blurred"), liefert der Browser keine Eingabedaten.profileskann aus Datenschutzgründen generisch gehalten sein. - Controller-Modelle passend zu
profilesliefert die Bibliothek@webxr-input-profiles/motion-controllers.