v149 · gamepad · origin trial · experimental
Gamepad Event-Driven Input API
An extension to the Gamepad API that replaces polling (navigator.getGamepads()) with a rawgamepadinputchange event, firing synchronously on every hardware update for lower-latency, lower-CPU gamepad input.
at a glance
| Status in Chrome 149 | Origin trial (experimental) |
|---|---|
| Flag | None when origin trial token is present |
| Spec | w3c.github.io/gamepad (extension to existing Gamepad spec) |
| Standards position (Firefox) | No signal |
| Standards position (Safari) | No signal |
| Blink component | Blink>Input>Gamepad |
| ChromeStatus | 5989275208253440 — Gamepad Event-Driven Input API |
why it exists
The existing Gamepad API is polling-only: an application must call navigator.getGamepads() inside a requestAnimationFrame loop to read gamepad state. This introduces up to one frame of latency (16 ms at 60 Hz) and wastes CPU cycles even when no button is pressed. High-frequency controllers (e.g. 250 Hz gaming pads) can report 4 samples per frame that the polling model silently discards.
The event-driven model fires a rawgamepadinputchange event on window every time the hardware sends new data, regardless of the frame rate. Games and accessibility tools that need tight timing — fighting games, rhythm games, assistive devices — benefit immediately.
shape of the API
| Event | Target | Fires when |
|---|---|---|
rawgamepadinputchange | window | New input data arrives from any connected gamepad |
| Event property | Type | Description |
|---|---|---|
event.gamepad | Gamepad | Snapshot of the gamepad state at the moment of the hardware report |
event.timestamp | DOMHighResTimeStamp | Time of the hardware report, not the render frame |
The existing gamepadconnected / gamepaddisconnected events and navigator.getGamepads() remain available and unchanged.
example
// Event-driven: fires at hardware report rate, not frame rate
window.addEventListener('rawgamepadinputchange', (event) => {
const pad = event.gamepad;
// Read axes (e.g. left stick)
const [lx, ly] = pad.axes;
moveCharacter(lx, ly);
// Read buttons
if (pad.buttons[0].pressed) {
jump();
}
});
// Polling still works and is unaffected
function gameLoop() {
const pads = navigator.getGamepads();
for (const pad of pads) {
if (pad) renderHUD(pad);
}
requestAnimationFrame(gameLoop);
}
Pattern from W3C Gamepad spec
browser support
| Browser | Support | Notes |
|---|---|---|
| Chrome 149 | Origin trial | Requires OT token; event name subject to change |
| Firefox | No signal | — |
| Safari | No signal | — |