Signatur
Beschreibung
Die schreibgeschützte Eigenschaft gamepad einer XRInputSource liefert ein Gamepad-Objekt, über das du Tasten (buttons), Analogsticks und Touchpads (axes) eines XR-Controllers auslesen kannst. Sie stammt aus dem WebXR Gamepads Module und bildet die Brücke zwischen WebXR und der bekannten Gamepad-API.
Anders als bei klassischen Gamepads taucht dieses Objekt nicht in navigator.getGamepads() auf. Es gehört ausschließlich zur jeweiligen Eingabequelle und ist nur während einer aktiven XRSession gültig. Der Wert von gamepad.mapping ist bei XR-Controllern "xr-standard", sofern das Gerät dem Standard-Layout entspricht: buttons[0] = Trigger, buttons[1] = Griff (Squeeze), buttons[2] = Touchpad, buttons[3] = Thumbstick; axes[0/1] = Touchpad X/Y, axes[2/3] = Thumbstick X/Y.
Eingabequellen ohne Tasten oder Achsen – etwa Blickrichtungssteuerung (targetRayMode === "gaze"), Bildschirm-Touch oder reines Hand-Tracking – liefern null. Für einfache Aktionen wie „Auswählen“ und „Greifen“ solltest du daher bevorzugt die Ereignisse select und squeeze der Session nutzen und gamepad nur für zusätzliche Bedienelemente wie Thumbsticks abfragen.
Da der Zustand nicht per Event gemeldet wird, fragst du ihn typischerweise in jedem Frame innerhalb des Callbacks von XRSession.requestAnimationFrame() ab (Polling).
Rückgabewert
Gamepad-Objekt mit buttons, axes, mapping (meist "xr-standard") und timestamp – oder null, wenn die Eingabequelle keine Tasten/Achsen besitzt.Beispiele
Thumbstick und Trigger pro Frame auslesen
const session = await navigator.xr.requestSession('immersive-vr');
const refSpace = await session.requestReferenceSpace('local');
const onFrame = (time, frame) => {
for (const source of session.inputSources) {
const gp = source.gamepad;
if (!gp) continue; // z. B. Blicksteuerung oder Hand-Tracking
const [, , stickX = 0, stickY = 0] = gp.axes;
const trigger = gp.buttons[0];
if (Math.abs(stickX) > 0.2 || Math.abs(stickY) > 0.2) {
console.log(`${source.handedness}: Stick ${stickX.toFixed(2)} / ${stickY.toFixed(2)}`);
}
if (trigger?.pressed) {
console.log(`${source.handedness}: Trigger ${trigger.value.toFixed(2)}`);
}
}
session.requestAnimationFrame(onFrame);
};
session.requestAnimationFrame(onFrame);
Tastendruck erkennen (Flanke statt Dauerzustand)
const previous = new WeakMap(); // XRInputSource -> bisherige Tastenzustände
const handleButtons = (session) => {
for (const source of session.inputSources) {
const gp = source.gamepad;
if (!gp) continue;
const before = previous.get(source) ?? [];
gp.buttons.forEach((btn, i) => {
if (btn.pressed && !before[i]) {
console.log(`Taste ${i} am ${source.handedness}-Controller gedrückt`);
}
});
previous.set(source, gp.buttons.map((b) => b.pressed));
}
};
// Aufruf innerhalb des XR-Frame-Callbacks:
// session.requestAnimationFrame((t, frame) => { handleButtons(session); ... });
Controller-Fähigkeiten beim Verbinden prüfen
session.addEventListener('inputsourceschange', ({ added }) => {
for (const source of added) {
const gp = source.gamepad;
if (!gp) {
console.log(`${source.targetRayMode}: kein Gamepad – nur select/squeeze verfügbar`);
continue;
}
console.log(
`${source.handedness} | Mapping: ${gp.mapping} | ` +
`${gp.buttons.length} Tasten, ${gp.axes.length} Achsen | Profile: ${source.profiles.join(', ')}`
);
}
});
// Wichtig · Fallstricke
- Immer auf
nullprüfen: Blicksteuerung, Touch-Eingaben (AR auf Smartphones) und Hand-Tracking liefern meist kein Gamepad. - Nicht in
navigator.getGamepads(): XR-Controller erscheinen dort nicht, und das Ereignisgamepadconnectedwird für sie nicht ausgelöst. Neue Controller erkennst du überinputsourceschange. - Layouts unterscheiden sich: Welche Indizes über das
xr-standard-Layout hinaus belegt sind (z. B. A/B/X/Y abbuttons[4]), hängt vom Gerät ab. Mitsource.profilesund der Bibliothek WebXR Input Profiles kannst du die Belegung zuverlässig zuordnen. Fehlende Bedienelemente werden als Platzhalter-Einträge bzw. mit dem Wert0gemeldet. - Totzone: Analogsticks liefern im Ruhezustand selten exakt
0. Setze einen Schwellwert (etwa 0,1–0,2). - Nur Momentaufnahme: Der Zustand gilt nur während der Session. Werte nach Möglichkeit im Frame-Callback lesen und keine Referenzen über das Session-Ende hinaus aufbewahren.
- Kompatibilität: Wird von Chromium-Browsern (Chrome, Edge, Samsung Internet) und dem Meta Quest Browser unterstützt. Firefox (Desktop) und Safari unterstützen es nicht. Safari auf der Apple Vision Pro bietet WebXR nur eingeschränkt an, meist ohne Gamepad-Daten. WebXR setzt einen sicheren Kontext (HTTPS) voraus.