[gamepad]
. See
Bugzilla
for this specification's open bugs.
Some user agents 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.
This specification references interfaces from a number of other specifications:
This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.
Implementations that use ECMAScript to implement the APIs defined in this specification MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]] as this specification uses that specification and terminology.
A conforming implementation is required to implement all fields defined in this specification.
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.
This interface defines an individual gamepad device.
interface Gamepad { 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; };
connected
attribute MUST be set to false.
axes
and button
data
have been updated from the hardware. The value must be relative to
the navigationStart
attribute of the PerformanceTiming
interface. Since values are monotonically increasing they can be
compared to determine the ordering of updates, as newer values will
always be greater than or equal to older values.
If no data has been received from the hardware, the value of
the timestamp
attribute should be the time relative
to navigationStart
when the Gamepad object was first
made available to script.
"standard"
, which corresponds
to the Standard Gamepad layout.
If the user agent does not have knowledge of the device layout
and is simply providing the controls as represented by the
driver in use, then it MUST set the mapping
property
to an empty string.
This interface defines the state of an individual button on a gamepad device.
interface GamepadButton { readonly attribute boolean pressed; readonly attribute boolean touched; readonly attribute double value; };
This enum defines the set of known mappings for a Gamepad.
enum GamepadMappingType { "", "standard", };
This partial interface defines an extension to the Navigator interface.
partial interface Navigator { sequence<Gamepad?> getGamepads(); };
As an example, if there is one connected gamepad with an index of 1, then the following code snippet describes the expected behavior:
// gamepads should look like [null, [object Gamepad]] var gamepads = navigator.getGamepads(); // The following statements should all evaluate to true. gamepads[0] == null; gamepads[1].index == 1;
[Constructor(GamepadEventInit eventInitDict)] interface GamepadEvent: Event { readonly attribute Gamepad gamepad; };
dictionary GamepadEventInit: EventInit { required Gamepad gamepad; };
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 device, the "Standard
Gamepad". The standard gamepad has 4 axes, and up to 17 buttons.
When remapping, the indices in axes[]
and buttons[]
should correspond as closely as possible to the physical locations in
the diagram below. Additionally, the
mapping
property of the Gamepad SHOULD be set to the
string "standard"
.
The example below demonstrates typical access to gamepads. Note the relationship with the WindowAnimationTiming interface.
function runAnimation() { window.requestAnimationFrame(runAnimation); var gamepads = navigator.getGamepads(); for (var i = 0; i < gamepads.length; ++i) { var pad = gamepads[i]; // todo; simple demo of displaying pad.axes and pad.buttons } } window.requestAnimationFrame(runAnimation);
Coordination with WindowAnimationTiming
Interactive applications will typically be using the WindowAnimationTiming interface 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.
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. Registration for and firing of the
gamepadconnected
event MUST follow the usual behavior
of DOM4 Events. [[!DOM4]]
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.
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. Registration for and firing of the
gamepaddisconnected
event MUST follow the usual behavior
of DOM4 Events. [[!DOM4]]
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.
More discussion needed, on whether to include or exclude axis and button
changed events, and whether to roll them more together
(gamepadchanged
?), separate somewhat
(gamepadaxischanged
?), or separate by individual axis
and button.
Many have made contributions in code, comments, or documentation:
Please let me know if I have inadvertently omitted your name.