Signatur
Beschreibung
Die schreibgeschützte Eigenschaft added des XRInputSourcesChangeEvent ist ein eingefrorenes Array mit null oder mehr XRInputSource-Objekten. Jedes davon steht für eine Eingabequelle, die gerade neu verfügbar geworden ist, zum Beispiel ein Controller, der eingeschaltet oder verbunden wurde, eine Hand, die das Hand-Tracking erkannt hat, oder ein Blick- bzw. Bildschirm-Eingabegerät.
Das Ereignis wird als inputsourceschange an der XRSession ausgelöst. Registrieren kannst du es mit session.addEventListener("inputsourceschange", handler) oder über die Eigenschaft session.oninputsourceschange. Normalerweise wertest du added und removed zusammen aus, damit deine eigene Liste der Eingabequellen, die zugehörigen 3D-Modelle (etwa Controller-Meshes) und Zuordnungen wie „linke Hand/rechte Hand“ zur aktuellen Hardware passen.
Die meisten Informationen zu jeder neuen Quelle stehen sofort bereit: handedness, targetRayMode, profiles, gripSpace sowie gegebenenfalls gamepad und hand. Die aktuelle Position erhältst du aber erst im Render-Loop über XRFrame.getPose().
Rückgabewert
XRInputSource-Objekten. Gibt es keine neuen Quellen, ist es leer.Beispiele
Neue Controller protokollieren (addEventListener)
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
);
}
});
Eigene Map für Controller-Modelle aktuell halten
const controllerModels = new Map();
const createModelFor = (source) => ({ name: `Modell-${source.handedness}` });
const onInputSourcesChange = ({ added, removed }) => {
for (const source of removed) {
controllerModels.delete(source);
}
for (const source of added) {
// Hand-Tracking und Controller getrennt behandeln
if (source.hand) {
console.log(`Hand erkannt: ${source.handedness}`);
continue;
}
controllerModels.set(source, createModelFor(source));
}
console.log(`Aktive Controller: ${controllerModels.size}`);
};
const session = await navigator.xr.requestSession("immersive-vr", {
optionalFeatures: ["hand-tracking"]
});
session.oninputsourceschange = onInputSourcesChange;
Gamepad-Tasten neuer Quellen im Render-Loop auswerten
const session = await navigator.xr.requestSession("immersive-vr");
const refSpace = await session.requestReferenceSpace("local");
const gamepadSources = new Set();
session.addEventListener("inputsourceschange", (e) => {
e.added.filter((s) => s.gamepad).forEach((s) => gamepadSources.add(s));
e.removed.forEach((s) => gamepadSources.delete(s));
});
const onFrame = (time, frame) => {
for (const source of gamepadSources) {
const pose = frame.getPose(source.gripSpace ?? source.targetRaySpace, refSpace);
if (pose && source.gamepad.buttons[0]?.pressed) {
console.log("Trigger gedrückt bei", pose.transform.position);
}
}
session.requestAnimationFrame(onFrame);
};
session.requestAnimationFrame(onFrame);
// Wichtig · Fallstricke
- Eingefrorenes Array:
addedlässt sich nicht verändern. Mitpush()o. ä. wirft der Code im Strict Mode einen Fehler. Kopiere den Inhalt deshalb in eine eigene Datenstruktur. - Anfangszustand: Quellen, die beim Start der Sitzung schon verbunden sind, meldet der Browser in der Regel über ein erstes
inputsourceschange-Ereignis. Zur Sicherheit solltest du zusätzlichsession.inputSourcesauswerten, falls dein Listener spät registriert wird. - Ersetzen statt Ändern: Ändern sich Eigenschaften einer Quelle (z. B.
handednessoderprofiles), entfernt der Browser das alte Objekt und legt ein neues an. Dasselbe Ereignis kann die Quelle dann inremovedund ihren Nachfolger inaddedenthalten. Werte daher zuerstremovedaus und danachadded. - Referenzen: Verwende die
XRInputSource-Objekte direkt als Schlüssel (z. B. in einerMap) und gib sie frei, sobald sie inremovedauftauchen. Sonst entstehen Speicherlecks. - Kompatibilität: WebXR funktioniert nur in sicheren Kontexten (HTTPS) und wird hauptsächlich von Chromium-Browsern und dem Meta Quest Browser unterstützt. Firefox und Safari (Desktop) unterstützen es nicht. Prüfe die Unterstützung vorher mit
'xr' in navigator.