Gamepad

W3C Editor's Draft 20

This version:
https://w3c.github.io/gamepad/
Latest published version:
https://www.w3.org/TR/gamepad/
Latest editor's draft:
https://w3c.github.io/gamepad/
Test suite:
https://wpt.live/gamepad/
Implementation report:
https://wpt.fyi/results/gamepad
Editors:
Steve Agoston ( Sony )
James Hollyer ( Google )
Matt Reynolds ( Google )
Former editors:
Brandon Jones ( Google )
Scott Graham ( Google )
Ted Mielczarek ( Mozilla )
Participate:
GitHub w3c/gamepad
File an issue
Commit history
Pull requests
Browser support:
caniuse.com

Abstract

The Gamepad specification defines a low-level interface that represents gamepad devices.

Status of This Document

This is a preview

Do not attempt to implement this version of the specification. Do not reference this version as authoritative in any way. Instead, see https://w3c.github.io/gamepad/ for the Editor's draft.

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This is a work in progress.

This document was published by the Web Applications Working Group as an Editor's Draft.

GitHub Issues are preferred for discussion of this specification.

Publication as an Editor's Draft does not imply endorsement by the W3C Membership.

This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Patent Policy . W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy .

This document is governed by the 15 September 2020 W3C Process Document .

1. Introduction

This section is non-normative.

Some user agent s have connected gamepad devices. These devices are desirable and suited to input for gaming applications, and for "10 foot" user interfaces (presentations, media viewers).

Currently, the only way for a gamepad to be used as input would be to emulate mouse or keyboard events, however this would lose information and require additional software outside of the user agent to accomplish emulation.

Meanwhile, native applications are capable of accessing these devices via system APIs.

The Gamepad API provides a solution to this problem by specifying interfaces that allow web applications to directly act on gamepad data.

2. Scope

Interfacing with external devices designed to control games has the potential to become large and intractable if approached in full generality. In this specification we explicitly choose to narrow scope to provide a useful subset of functionality that can be widely implemented and broadly useful.

Specifically, we choose to only support the functionality required to support gamepads. Support for gamepads requires two input types: buttons and axes. Both buttons and axes are reported as analog values, buttons ranging from [0..1], and axes ranging from [-1..1].

While the primary goal is support for gamepad devices, supporting these two types of analog inputs allows support for other similar devices common to current gaming systems including joysticks, driving wheels, pedals, and accelerometers. As such, the name "gamepad" is exemplary rather than trying to be a generic name for the entire set of devices addressed by this specification.

We specifically exclude support for more complex devices that may also be used in some gaming contexts, including those that that do motion sensing, depth sensing, video analysis, gesture recognition, and so on.

3. Gamepad interface

This interface defines an individual gamepad device.

] interface
WebIDL[Exposed=Window, SecureContext]
interface Gamepad {
  attribute EventHandler onbuttondown;
  attribute EventHandler onbuttonup;
  attribute EventHandler onbuttonchange;
  attribute EventHandler onaxischange;

  readonly attribute DOMString id;
  readonly attribute long index;
  readonly attribute boolean connected;
  readonly attribute DOMHighResTimeStamp timestamp;
  readonly attribute GamepadMappingType mapping;
  readonly attribute FrozenArray<double> axes;
  readonly attribute FrozenArray<GamepadButton> buttons;
};


The algorithms used to communicate with the system typically complete asynchronously, queuing work on the gamepad task source .

Instances of Gamepad are created with the internal slots described in the following table:

Internal slot Initial value Description (non-normative)
[[connected]] false A flag indicating that the device is connected to the system
[[timestamp]] undefined The last time data for this Gamepad was updated
[[axes]] An empty sequence A sequence of double values representing the current state of axes exposed by this device
[[buttons]] An empty sequence A sequence of GamepadButton objects representing the current state of buttons exposed by this device
[[exposed]] false A flag indicating that the Gamepad object has been exposed to script
[[axisMapping]] An empty ordered map Mapping from unmapped axis index to an index in the axes array
[[axisMinimums]] An empty list A list containing the minimum logical value for each axis
[[axisMaximums]] An empty list A list containing the maximum logical value for each axis
[[buttonMapping]] An empty ordered map Mapping from unmapped button index to an index in the buttons array
[[buttonMinimums]] An empty list A list containing the minimum logical value for each button.
[[buttonMaximums]] An empty list A list containing the maximum logical value for each button
onbuttondown attribute
onbuttondown is an event handler IDL attribute for the buttondown event type.
onbuttonup attribute
onbuttonup is an event handler IDL attribute for the buttonup event type.
onbuttonchange attribute
onbuttonchange is an event handler IDL attribute for the buttonchange event type.
onaxischange attribute
onaxischange is an event handler IDL attribute for the axischange event type.
id attribute

An identification string for the gamepad. This string identifies the brand or style of connected gamepad device.

The exact format of the id string is left unspecified. It is RECOMMENDED that the user agent select a string that identifies the product without uniquely identifying the device. For example, a USB gamepad may be identified by its idVendor and idProduct values. Unique identifiers like serial numbers or Bluetooth device addresses MUST NOT be included in the id string.

index attribute
The index of the gamepad in the Navigator . When multiple gamepads are connected to a user agent , indices MUST be assigned on a first-come, first-serve basis, starting at zero. If a gamepad is disconnected, previously assigned indices MUST NOT be reassigned to gamepads that continue to be connected. However, if a gamepad is disconnected, and subsequently the same or a different gamepad is then connected, the lowest previously used index MUST be reused.
connected attribute

Indicates whether the physical device represented by this object is still connected to the system. When a gamepad becomes unavailable, whether by being physically disconnected, powered off or otherwise unusable, the connected attribute MUST be set to false .

The connected getter steps are:

  1. Return this . [[connected]] .
timestamp attribute

The timestamp allows the author to determine the last time the axes or buttons attribute for this gamepad was updated. The value MUST be set to the current high resolution time each time the system receives new button or axis input values from the device. If no data has been received from the hardware, timestamp MUST be the current high resolution time at the time when the Gamepad was first made available to script.

Warning

User agent s SHOULD set a minimum resolution of gamepad 's timestamp attribute to 5 microseconds, following [ HR-TIME ]'s clock resolution recommendation.

The timestamp getter steps are:

  1. Return this . [[timestamp]] .
mapping attribute

The mapping in use for this device. If the user agent has knowledge of the layout of the device, then it SHOULD indicate that a mapping is in use by setting mapping to the corresponding GamepadMappingType value.

To select a mapping for a gamepad device, run the following steps:

  1. If the button and axis layout of the gamepad device corresponds with the Standard Gamepad layout, then return " standard ".
  2. Return " ".
axes attribute

Array of values for all axes of the gamepad. All axis values MUST be linearly normalized to the range [-1.0 .. 1.0]. If the controller is perpendicular to the ground with the directional stick pointing up, -1.0 SHOULD correspond to "forward" or "left", and 1.0 SHOULD correspond to "backward" or "right". Axes that are drawn from a 2D input device SHOULD appear next to each other in the axes array, X then Y. It is RECOMMENDED that axes appear in decreasing order of importance, such that element 0 and 1 typically represent the X and Y axis of a directional stick. The same object MUST be returned until the user agent needs to return different values (or values in a different order).

The axes getter steps are:

  1. Return this . [[axes]] .
buttons attribute

Array of button states for all buttons of the gamepad. It is RECOMMENDED that buttons appear in decreasing importance such that the primary button, secondary button, tertiary button, and so on appear as elements 0, 1, 2, ... in the buttons array. The same object MUST be returned until the user agent needs to return different values (or values in a different order).

The buttons getter steps are:

  1. Return this . [[buttons]] .

3.1 Receiving inputs

When the system receives new button or axis input values , run the following steps:

  1. Let gamepad be the Gamepad object representing the device that received new button or axis input values.
  2. Queue a task on the gamepad task source to update gamepad state for gamepad .

To update gamepad state for gamepad , run the following steps:

  1. Initialize oldAxisValues to be an empty list .
  2. For each axis of gamepad . [[axes]] , append axis to oldAxisValues .
  3. Initialize oldButtonValues to be an empty list .
  4. Initialize oldButtonPressed to be an empty list .
  5. For each button of gamepad . [[buttons]] :
    1. Append button . value to oldButtonValues .
    2. Append button . pressed to oldButtonPressed .
  6. Let now be the current high resolution time .
  7. Set gamepad . [[timestamp]] to now .
  8. Run the steps to map and normalize axes for gamepad .
  9. Run the steps to map and normalize buttons for gamepad .
  10. Let navigator be gamepad 's relevant global object 's Navigator object.
  11. If navigator . [[hasGamepadGesture]] is false and gamepad contains a gamepad user gesture :
    1. Set navigator . [[hasGamepadGesture]] to true .
    2. For each connectedGamepad of navigator . [[gamepads]] :
      1. If connectedGamepad is not equal to null :
        1. Set connectedGamepad . [[exposed]] to true .
        2. Set connectedGamepad . [[timestamp]] to now .
        3. Let document be gamepad 's relevant global object 's associated Document ; otherwise null .
        4. If document is not null and is fully active , then queue a task on the gamepad task source to fire an event named gamepadconnected at gamepad 's relevant global object using GamepadEvent with its gamepad attribute initialized to connectedGamepad .
  12. If navigator . [[hasGamepadGesture]] is false , abort these steps.
  13. For each axisIndex of the range from 0 to the size of gamepad . axes − 1:
    1. If oldAxisValues [ axisIndex ] is not equal to gamepad . [[axes]] [ axisIndex ], queue a task on the gamepad task source to fire an event named axischange at gamepad using GamepadAxisEvent with its gamepadIndex attribute initialized to gamepad . index , its axisIndex attribute initialized to axisIndex , its axisSnapshot attribute initialized to newValue , and its gamepadTimestamp attribute initialized to now .
  14. For each buttonIndex of the range from 0 to the size of gamepad . buttons − 1:
    1. Let button be gamepad . [[buttons]] [ buttonIndex ].
    2. If oldButtonValues [ buttonIndex ] is not equal to button . value :
      1. Queue a task on the gamepad task source to fire an event named buttonchange at gamepad using GamepadButtonEvent with its gamepadIndex attribute initialized to gamepad . index , its buttonIndex attribute initialized to buttonIndex , its buttonSnapshot attribute initialized to the result of creating a button snapshot of button , and its gamepadTimestamp attribute initialized to now .
    3. If oldButtonPressed [ buttonIndex ] is not equal to button . pressed :
      1. If button . pressed is true , queue a task on the gamepad task source to fire an event named buttondown at gamepad using GamepadButtonEvent with its gamepadIndex attribute initialized to gamepad . index , its buttonIndex attribute initialized to buttonIndex , its buttonSnapshot attribute initialized to the result of creating a button snapshot of button , and its gamepadTimestamp attribute initialized to now .

        Otherwise, queue a task on the gamepad task source to fire an event named buttonup at gamepad using GamepadButtonEvent with its gamepadIndex attribute initialized to gamepad . index , its buttonIndex attribute initialized to buttonIndex , its buttonSnapshot attribute initialized to the result of creating a button snapshot of button , and its gamepadTimestamp attribute initialized to now .

To map and normalize axes for gamepad , run the following steps:

  1. Let axisValues be a list of unsigned long values representing the most recent logical axis input values for each axis input of the device represented by gamepad .
  2. Let maxRawAxisIndex be the size of axisValues − 1.
  3. For each rawAxisIndex of the range from 0 to maxRawAxisIndex :
    1. Let mappedIndex be gamepad . [[axisMapping]] [ rawAxisIndex ].
    2. Let logicalValue be axisValues [ rawAxisIndex ].
    3. Let logicalMinimum be gamepad . [[axisMinimums]] [ rawAxisIndex ].
    4. Let logicalMaximum be gamepad . [[axisMaximums]] [ rawAxisIndex ].
    5. Let normalizedValue be 2 ( logicalValue logicalMinimum ) / ( logicalMaximum logicalMinimum ) − 1.
    6. Set gamepad . [[axes]] [ axisIndex ] to be normalizedValue .

To map and normalize buttons for gamepad , run the following steps:

  1. Let buttonValues be a list of unsigned long values representing the most recent logical button input values for each button input of the device represented by gamepad .
  2. Let maxRawButtonIndex be the size of buttonValues − 1.
  3. For each rawButtonIndex of the range from 0 to maxRawButtonIndex :
    1. Let mappedIndex be gamepad . [[buttonMapping]] [ rawButtonIndex ].
    2. Let logicalValue be buttonValues [ rawButtonIndex ].
    3. Let logicalMinimum be gamepad . [[buttonMinimums]] [ rawButtonIndex ].
    4. Let logicalMaximum be gamepad . [[buttonMaximums]] [ rawButtonIndex ].
    5. Let normalizedValue be ( logicalValue logicalMinimum ) / ( logicalMaximum logicalMinimum ).
    6. Let button be gamepad . [[buttons]] [ mappedIndex ].
    7. Set button . [[value]] to normalizedValue .
    8. If the button has a digital switch to indicate a pure pressed or released state, set button . [[pressed]] to true if the button is pressed or false if it is not pressed.

      Otherwise, set button . [[pressed]] to true if the value is above the button press threshold or false if it is not above the threshold.

    9. If the button is capable of detecting touch, set button . [[touched]] to true if the button is currently being touched.

      Otherwise, set button . [[touched]] to button . [[pressed]] .

To create a button snapshot for button , run the following steps:

  1. Let buttonCopy be a newly created GamepadButton instance:
    1. Initialize buttonCopy 's value attribute to button . value .
    2. Initialize buttonCopy 's pressed attribute to button . pressed .
    3. Initialize buttonCopy 's touched attribute to button . touched .
  2. Return buttonCopy .

3.2 Constructing a Gamepad

A new Gamepad representing a connected gamepad device is constructed by performing the following steps:

  1. Let gamepad be a newly created Gamepad instance:
    1. Initialize gamepad 's id attribute to an identification string for the gamepad.
    2. Initialize gamepad 's index attribute to the result of selecting an unused gamepad index for gamepad .
    3. Initialize gamepad 's mapping attribute to the result of selecting a mapping for the gamepad device.
    4. Initialize gamepad . [[connected]] to true .
    5. Initialize gamepad . [[timestamp]] to the current high resolution time .
    6. Initialize gamepad . [[axes]] to the result of initializing axes for gamepad .
    7. Initialize gamepad . [[buttons]] to the result of initializing buttons for gamepad .
  2. Return gamepad .

To select an unused gamepad index for gamepad , run the following steps:

  1. Let navigator be gamepad 's relevant global object 's Navigator object.
  2. Let maxGamepadIndex be the size of navigator . [[gamepads]] − 1.
  3. For each gamepadIndex of the range from 0 to maxGamepadIndex :
    1. If navigator . [[gamepads]] [ gamepadIndex ] is null , then return gamepadIndex .
  4. Append null to navigator . [[gamepads]] .
  5. Return the size of navigator . [[gamepads]] − 1.

To initialize axes for gamepad , run the following steps:

  1. Let inputCount be the number of axis inputs exposed by the device represented by gamepad .
  2. Set gamepad . [[axisMinimums]] to a list of unsigned long values with size equal to inputCount containing minimum logical values for each of the axis inputs.
  3. Set gamepad . [[axisMaximums]] to a list of unsigned long values with size equal to inputCount containing maximum logical values for each of the axis inputs.
  4. Initialize unmappedInputList to be an empty list .
  5. Initialize mappedIndexList to be an empty list .
  6. Initialize axesSize to be 0.
  7. For each rawInputIndex of the range from 0 to inputCount − 1:
    1. If the the gamepad axis at index rawInputIndex represents a Standard Gamepad axis :
      1. Let canonicalIndex be the canonical index for the axis.
      2. If mappedIndexList contain s canonicalIndex , then append rawInputIndex to unmappedInputList .

        Otherwise:

        1. Set gamepad . [[axisMapping]] [ rawInputIndex ] to canonicalIndex .
        2. Append canonicalIndex to mappedIndexList .
        3. If canonicalIndex + 1 is greater than axesSize , then set axesSize to canonicalIndex + 1.

      Otherwise, append rawInputIndex to unmappedInputList .

  8. Initialize axisIndex to be 0.
  9. For each rawInputIndex of unmappedInputList :
    1. While mappedIndexList contain s axisIndex :
      1. Increment axisIndex .
    2. Set gamepad . [[axisMapping]] [ rawInputIndex ] to axisIndex .
    3. Append axisIndex to mappedIndexList .
    4. If axisIndex + 1 is greater than axesSize , then set axesSize to axisIndex + 1.
  10. Initialize axes to be an empty list .
  11. For each axisIndex of the range from 0 to axesSize − 1, append 0 to axes .
  12. Return axes .

To initialize buttons for a gamepad, run the following steps:

  1. Let inputCount be the number of button inputs exposed by the device represented by gamepad .
  2. Set gamepad . [[buttonMinimums]] to be a list of unsigned long values with size equal to inputCount containing minimum logical values for each of the button inputs.
  3. Set gamepad . [[buttonMaximums]] to be a list of unsigned long values with size equal to inputCount containing maximum logical values for each of the button inputs.
  4. Initialize unmappedInputList to be an empty list .
  5. Initialize mappedIndexList to be an empty list .
  6. Initialize buttonsSize to be 0.
  7. For each rawInputIndex of the range from 0 to inputCount − 1:
    1. If the the gamepad button at index rawInputIndex represents a Standard Gamepad button :
      1. Let canonicalIndex be the canonical index for the button.
      2. If mappedIndexList contain s canonicalIndex , then append rawInputIndex to unmappedInputList .

        Otherwise:

        1. Set gamepad . [[buttonMapping]] [ rawInputIndex ] to canonicalIndex .
        2. Append canonicalIndex to mappedIndexList .
        3. If canonicalIndex + 1 is greater than buttonsSize , then set buttonsSize to canonicalIndex + 1.

      Otherwise, append rawInputIndex to unmappedInputList .

    2. Increment rawInputIndex .
  8. Initialize buttonIndex to be 0.
  9. For each rawInputIndex of unmappedInputList :
    1. While mappedIndexList contain s buttonIndex :
      1. Increment buttonIndex .
    2. Set gamepad . [[buttonMapping]] [ rawInputIndex ] to buttonIndex .
    3. Append buttonIndex to mappedIndexList .
    4. If buttonIndex + 1 is greater than buttonsSize , then set buttonsSize to buttonIndex + 1.
  10. Initialize buttons to be an empty list .
  11. For each buttonIndex of the range from 0 to buttonsSize − 1, append a new GamepadButton to buttons .
  12. Return buttons .

4. GamepadButton Interface

This interface defines the state of an individual button on a gamepad device.

WebIDL[Exposed=Window, SecureContext]
interface 
  readonly attribute
  readonly attribute
  readonly attribute

interface GamepadButton {
  readonly attribute boolean pressed;
  readonly attribute boolean touched;
  readonly attribute double value;

};


Instances of GamepadButton are created with the internal slots described in the following table:

Internal slot Initial value Description (non-normative)
[[pressed]] false A flag indicating that the button is pressed
[[touched]] false A flag indicating that the button is touched
[[value]] 0.0 A double representing the button value scaled to the range [0.0 .. 1.0]
pressed attribute

The pressed state of the button. This property MUST be true if the button is currently pressed, and false if it is not pressed. For buttons which do not have a digital switch to indicate a pure pressed or released state, the user agent MUST choose a button press threshold to indicate the button as pressed when its value is above a certain amount. If the platform API gives a recommended value, the user agent SHOULD use that. In other cases, the user agent SHOULD choose some other reasonable value.

The pressed getter steps are:

  1. Return this . [[pressed]] .
touched attribute

The touched state of the button. If the button is capable of detecting touch, this property MUST be true if the button is currently being touched, and false otherwise. If the button is not capable of detecting touch and is capable of reporting an analog value, this property MUST be true if the value property is greater than 0, and false if the value is 0. If the button is not capable of detecting touch and can only report a digital value, this property MUST mirror the pressed attribute.

The touched getter steps are:

  1. Return this . [[touched]] .
value attribute

For buttons that have an analog sensor, this property MUST represent the amount which the button has been pressed. All button values MUST be linearly normalized to the range [0.0 .. 1.0]. 0.0 MUST mean fully unpressed, and 1.0 MUST mean fully pressed. For buttons without an analog sensor, only the values 0.0 and 1.0 for fully unpressed and fully pressed respectively, MUST be provided.

The value getter steps are:

  1. Return this . [[value]] .

5. GamepadMappingType enum

This enum defines the set of known mappings for a Gamepad.

WebIDLenum GamepadMappingType {
  "",
  "standard",
  "xr-standard",
};


""
The empty string indicates that no mapping is in use for this gamepad.
"standard"
The Gamepad's controls have been mapped to the Standard Gamepad layout.
"xr-standard"
The Gamepad's controls have been mapped to the "xr-standard" gamepad mapping . This mapping is reserved for use by the WebXR Gamepads Module - Level 1 . Gamepads returned by getGamepads () MUST NOT report a mapping of " xr-standard ".

6. Extensions to the Navigator interface

WebIDL[Exposed=Window]
partial interface Navigator {
  sequence<Gamepad?> getGamepads();
};


Instances of Navigator are created with the internal slots described in the following table:

Internal slot Initial value Description (non-normative)
[[hasGamepadGesture]] false A flag indicating that a gamepad user gesture has been observed
[[gamepads]] [] A sequence<Gamepad?> with each Gamepad present at the index specified by its index attribute, or null for unassigned indices.

6.1 getGamepads() method

Note

The gamepad state returned from getGamepads () does not reflect disconnection or connection until after the gamepaddisconnected or gamepadconnected events have fired.

Note

To mitigate fingerprinting, getGamepads () returns an empty list before a gamepad user gesture has been seen. [ FINGERPRINTING-GUIDANCE ]

The getGamepads () method steps are:

  1. If the current settings object 's responsible document is not allowed to use the "gamepad" permission, then throw a " SecurityError " DOMException and abort these steps.
  2. If this . [[hasGamepadGesture]] is false , then return an empty list .
  3. Let now be the current high resolution time .
  4. For each gamepad of this . [[gamepads]] :
    1. If gamepad is not null and gamepad . [[exposed]] is false :
      1. Set gamepad . [[exposed]] to true .
      2. Set gamepad . [[timestamp]] to now .
  5. Return gamepads .

A gamepad contains a gamepad user gesture if the current input state indicates that the user is currently interacting with the gamepad. The user agent MUST provide an algorithm to check if the input state contains a gamepad user gesture. For buttons that support a neutral default value and have reported a pressed value of false at least once, a pressed value of true SHOULD be considered interaction. If a button does not support a neutral default value (for example, a toggle switch), then a pressed value of true SHOULD NOT be considered interaction. If a button has never reported a pressed value of false then it SHOULD NOT be considered interaction. Axis movements SHOULD be considered interaction if the axis supports a neutral default value, the current displacement from neutral is greater than a threshold chosen by the user agent , and the axis has reported a value below the threshold at least once. If an axis does not support a neutral default value (for example, an axis for a joystick that does not self-center), or an axis has never reported a value below the axis gesture threshold, then the axis SHOULD NOT be considered when checking for interaction. The axis gesture threshold SHOULD be large enough that random jitter is not considered interaction.

7. GamepadEvent Interface

] interface
WebIDL[Exposed=Window, SecureContext]
interface GamepadEvent : Event {

  constructor(DOMString type, GamepadEventInit eventInitDict);
  [SameObject] readonly attribute Gamepad gamepad;
};


gamepad
The gamepad attribute provides access to the associated gamepad data for this event.

7.1 GamepadEventInit dictionary

WebIDLdictionary GamepadEventInit : EventInit {
  required Gamepad gamepad;
};


gamepad member
The Gamepad associated with this event.

8. GamepadAxisEvent Interface

WebIDL[Exposed=Window, SecureContext]
interface GamepadAxisEvent : Event {
  constructor(DOMString type, GamepadAxisEventInit eventInitDict);
  readonly attribute long gamepadIndex;
  readonly attribute long axisIndex;
  readonly attribute double axisSnapshot;
  readonly attribute DOMHighResTimeStamp gamepadTimestamp;
};
gamepadIndex attribute
The index attribute of the Gamepad associated with this event.
axisIndex attribute
The index of the axis in the axes array.
axisSnapshot attribute
The axis value at the time when this event was created.
gamepadTimestamp attribute
The timestamp of the Gamepad associated with this event at the time when the event was created.

8.1 GamepadAxisEventInit dictionary

WebIDLdictionary GamepadAxisEventInit : EventInit {
  required long gamepadIndex;
  required long axisIndex;
  required double axisSnapshot;
  required DOMHighResTimeStamp gamepadTimestamp;
};
gamepadIndex member
The gamepad index for the event.
axisIndex member
The button index for the event.
axisSnapshot member
A copy of the current button state.
gamepadTimestamp member
The gamepad timestamp for the event.

9. GamepadButtonEvent Interface

WebIDL[Exposed=Window, SecureContext]
interface GamepadButtonEvent : Event {
  constructor(DOMString type, GamepadButtonEventInit eventInitDict);
  readonly attribute long gamepadIndex;
  readonly attribute long buttonIndex;
  readonly attribute GamepadButton buttonSnapshot;
  readonly attribute DOMHighResTimeStamp gamepadTimestamp;
};
gamepadIndex attribute
The index attribute of the Gamepad associated with this event.
buttonIndex attribute
The index of the GamepadButton in the buttons array.
buttonSnapshot attribute
A copy of the GamepadButton at the time when this event was created.
gamepadTimestamp attribute
The timestamp of the Gamepad associated with this event at the time when the event was created.

9.1 GamepadButtonEventInit dictionary

WebIDLdictionary GamepadButtonEventInit : EventInit {
  required long gamepadIndex;
  required long buttonIndex;
  required GamepadButton buttonSnapshot;
  required DOMHighResTimeStamp gamepadTimestamp;
};
gamepadIndex member
The gamepad index for the event.
buttonIndex member
The button index for the event.
buttonSnapshot member
A copy of the current button state.
gamepadTimestamp member
The gamepad timestamp for the event.

10. Remapping

Each device manufacturer creates many different products and each has unique styles and layouts of buttons and axes. It is intended that the user agent support as many of these as possible.

Additionally there are de facto standard layouts that have been made popular by game consoles. When the user agent recognizes the attached device, it is RECOMMENDED that it be remapped to a canonical ordering when possible. Devices that are not recognized should still be exposed in their raw form.

There is currently one canonical layout, the Standard Gamepad . When remapping, the indices in axes and buttons should correspond as closely as possible to the physical locations in the diagram below. Additionally, mapping SHOULD be set to " standard ".

The Standard Gamepad buttons are laid out in a left cluster of four buttons, a right cluster of four buttons, a center cluster of three buttons, and a pair of front facing buttons on the left and right side of the gamepad. The four axes of the "Standard Gamepad" are associated with a pair of analog sticks, one on the left and one on the right. The following table describes the buttons/axes and their physical locations.

An axis input represents a Standard Gamepad axis if it reports the input value for a thumbstick axis, the thumbstick is located in approximately the same location as the corresponding Standard Gamepad thumbstick, and the orientation of the axis (up-down or left-right) matches the orientation of the Standard Gamepad axis. If there are multiple axes that represent the same Standard Gamepad axis, then the user agent SHOULD select one to be the Standard Gamepad axis and assign a different index to the other axis.

A button input represents a Standard Gamepad button if it reports the input value for a button or trigger, and the button or trigger is located in approximately the same location as the corresponding Standard Gamepad button.

If an axis or button input represents a Standard Gamepad axis or button, then its canonical index is the index of the corresponding Standard Gamepad axis or button.

Button/Axis Location
buttons[0] Bottom button in right cluster
buttons[1] Right button in right cluster
buttons[2] Left button in right cluster
buttons[3] Top button in right cluster
buttons[4] Top left front button
buttons[5] Top right front button
buttons[6] Bottom left front button
buttons[7] Bottom right front button
buttons[8] Left button in center cluster
buttons[9] Right button in center cluster
buttons[10] Left stick pressed button
buttons[11] Right stick pressed button
buttons[12] Top button in left cluster
buttons[13] Bottom button in left cluster
buttons[14] Left button in left cluster
buttons[15] Right button in left cluster
buttons[16] Center button in center cluster
axes[0] Horizontal axis for left stick (negative left/positive right)
axes[1] Vertical axis for left stick (negative up/positive down)
axes[2] Horizontal axis for right stick (negative left/positive right)
axes[3] Vertical axis for right stick (negative up/positive down)
Figure 1 Visual representation of a Standard Gamepad layout.

9. 11. Usage Examples

This section is non-normative.

The example below demonstrates typical access to gamepads. Note the relationship with the requestAnimationFrame () method.

function runAnimation() {
    window.requestAnimationFrame(runAnimation);
    for (const pad of navigator.getGamepads()) {
      // todo; simple demo of displaying pad.axes and pad.buttons
      console.log(pad);
    }
}

window
.requestAnimationFrame(runAnimation);

Best Practice 1 : Coordination with requestAnimationFrame()

Interactive applications will typically be using the requestAnimationFrame () method to drive animation, and will want coordinate animation with user gamepad input. As such, the gamepad data should be polled as closely as possible to immediately before the animation callbacks are executed, and with frequency matching that of the animation. That is, if the animation callbacks are running at 60Hz, the gamepad inputs should also be sampled at that rate.

10. 12. The gamepadconnected event

When a gamepad becomes available on the system, run the following steps:

  1. Let document be the current settings object 's responsible document ; otherwise null .
  2. If document is not null and is not allowed to use the "gamepad" permission, then abort these steps.
  3. Queue a task on the gamepad task source to perform the following steps:
    1. Let gamepad be a new Gamepad representing the gamepad.
    2. Let navigator be gamepad 's relevant global object 's Navigator object.
    3. Set navigator . [[gamepads]] [ gamepad . index ] to gamepad .
    4. If navigator . [[hasGamepadGesture]] is true :
      1. Set gamepad . [[exposed]] to true .
      2. If document is not null and is fully active , then fire an event named gamepadconnected at gamepad 's relevant global object using GamepadEvent with its gamepad attribute initialized to gamepad .

User agents implementing this specification must provide a new DOM event, named gamepadconnected . The corresponding event MUST be of type GamepadEvent and MUST fire on the Window object.

A user agent MUST dispatch this event type to indicate the user has connected a gamepad. If a gamepad was already connected when the page was loaded, the gamepadconnected event SHOULD be dispatched when the user presses a button or moves an axis.

11. 13. The gamepaddisconnected event

When a gamepad becomes unavailable on the system, run the following steps:

  1. Let gamepad be the Gamepad representing the unavailable device.
  2. Queue a task on the gamepad task source to perform the following steps:
    1. Set gamepad . [[connected]] to false .
    2. Let document be gamepad 's relevant global object 's associated Document ; otherwise null .
    3. If gamepad . [[exposed]] is true and document is not null and is fully active , then fire an event named gamepaddisconnected at gamepad 's relevant global object using GamepadEvent with its gamepad attribute initialized to gamepad .
    4. Let navigator be gamepad 's relevant global object 's Navigator object.
    5. Set navigator . [[gamepads]] [ gamepad . index ] to null .
    6. While navigator . [[gamepads]] is not empty and the last item of navigator . [[gamepads]] is null , remove the last item of navigator . [[gamepads]] .

User agents implementing this specification must provide a new DOM event, named gamepaddisconnected . The corresponding event MUST be of type GamepadEvent and MUST fire on the Window object.

When a gamepad is disconnected from the user agent , if the user agent has previously dispatched a gamepadconnected event for that gamepad to a Window , a gamepaddisconnected event MUST be dispatched to that same Window .

12. 14. Other The axischange, buttonchange, buttondown, and buttonup events

More discussion needed, User agent s implementing this specification MUST provide new DOM events named axischange , buttonchange , buttondown , and buttonup . The corresponding event MUST be of type GamepadAxisEvent for axischange , or GamepadButtonEvent for buttonchange , buttondown , and buttonup . All events MUST fire on whether to include the Gamepad object.

When the user agent receives new button or exclude axis and input values from a gamepad, the user agent MUST compare the current button changed events, and whether to roll them more together ( axis values with the previous values and dispatch "gamepadchanged" axischange ?), separate somewhat ( and "gamepadaxischanged" buttonchange ?), or separate by individual events for each axis and button. button with a changed value. The user agent MUST also compare the current button pressed state with the previous button pressed state and dispatch buttondown and buttonup events.

These events MUST NOT be dispatched before the user agent has dispatched a gamepadconnected event for that gamepad.

13. 15. Extensions to the WindowEventHandlers Interface Mixin

This specification extends the WindowEventHandlers interface mixin from HTML to add event handler IDL attributes to facilitate the event handler registration.

WebIDLpartial interface mixin WindowEventHandlers {
  attribute EventHandler ongamepadconnected;
  attribute EventHandler ongamepaddisconnected;
};


14. 16. Integration with Permissions Policy

This specification defines a policy-controlled feature identified by the string "gamepad" . Its default allowlist is 'self' .

Note

A document ’s permissions policy determines whether any content in that document is allowed to access getGamepads () . If disabled in any document, no content in the document will be allowed to use getGamepads () , nor will the gamepadconnected and gamepaddisconnected events fire.

15. 17. Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words MUST , MUST NOT , RECOMMENDED , SHOULD , and SHOULD NOT in this document are to be interpreted as described in BCP 14 [ RFC2119 ] [ RFC8174 ] when, and only when, they appear in all capitals, as shown here.

A. Acknowledgements

This section is non-normative.

The following people contributed to the development of this document.

B. References

B.1 Normative references

[dom]
DOM Standard . Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[HR-TIME]
High Resolution Time . Yoav Weiss; Ilya Grigorik; James Simonsen; Jatinder Mann. W3C. 15 July 2021. W3C Working Draft. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
HTML Standard . Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard . Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[permissions-policy]
Permissions Policy . Ian Clelland. W3C. 16 July 2020. W3C Working Draft. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels . S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words . B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[WebIDL]
Web IDL . Boris Zbarsky. W3C. 15 December 2016. W3C Editor's Draft. URL: https://heycam.github.io/webidl/
[webxr-gamepads-module-1]
WebXR Gamepads Module - Level 1 . Brandon Jones; Nell Waliczek. W3C. 10 October 2019. W3C Working Draft. URL: https://www.w3.org/TR/webxr-gamepads-module-1/

B.2 Informative references

[FINGERPRINTING-GUIDANCE]
Mitigating Browser Fingerprinting in Web Specifications . Nick Doty. W3C. 28 March 2019. W3C Note. URL: https://www.w3.org/TR/fingerprinting-guidance/