diff --git a/index.html b/index.html index c75088a..c6e4c6d 100644 --- a/index.html +++ b/index.html @@ -86,7 +86,7 @@

Introduction

- Some [=user agent=]s have connected gamepad devices. These devices are + 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).

@@ -120,7 +120,7 @@

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]. + buttons ranging from [0 .. 1], and axes ranging from [-1 .. 1].

While the primary goal is support for gamepad devices, supporting these @@ -386,10 +386,10 @@

- Gamepad interface + Gamepad Interface

- This interface defines an individual gamepad device. + This interface represents a [=gamepad=].

         [Exposed=Window]
@@ -430,10 +430,10 @@ 

[[\connected]] - `false` + `true` - A flag indicating that the device is connected to the system + A flag indicating that the [=gamepad=] is [=available=] @@ -456,7 +456,7 @@

A [=sequence=] of {{double}} values representing the current state - of axes exposed by this device + of each [=axis=] @@ -468,7 +468,7 @@

A [=sequence=] of {{GamepadButton}} objects representing the - current state of buttons exposed by this device + current state of each [=button=] @@ -491,30 +491,8 @@

An empty [=ordered map=] - Mapping from unmapped axis index to an index in the - {{Gamepad/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 + Mapping from indices in the [=axis list=] to indices in + {{Gamepad}}.{{Gamepad/axes}} @@ -525,30 +503,8 @@

An empty [=ordered map=] - Mapping from unmapped button index to an index in the - {{Gamepad/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 + Mapping from indices in the [=button list=] to indices in + {{Gamepad}}.{{Gamepad/buttons}} @@ -556,11 +512,12 @@

[[\touches]] - Initialize to an [=list/is empty=] [=list=] + An empty [=list=] - Holds the list of user-generated touches, if any. If the gamepad - does not support touch surfaces, then the list will remain empty. + Holds the [=list=] of {{GamepadTouch}} objects representing all + active [=touch points=] for the [=gamepad=]. If the [=gamepad=] has + no [=touch surfaces=], then the list will remain empty. @@ -568,10 +525,11 @@

[[\nextTouchId]] - Initialize to 0 + 0 - Touch id to use for the next incoming touch. + {{GamepadTouch/touchId}} value to use for the next [=touch point=] + that is not [=part of an existing active touch point=] @@ -582,8 +540,7 @@

undefined - A {{GamepadHapticActuator}} object capable of generating a haptic - effect that vibrates the entire gamepad + The [=gamepad=]'s [=vibration actuator=] @@ -593,8 +550,7 @@

- An identification string for the gamepad. This string identifies - the brand or style of connected gamepad device. + The [=gamepad=]'s [=gamepad identifier string=].

The exact format of the {{Gamepad/id}} string is left unspecified. @@ -610,24 +566,15 @@

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. + The index of the {{Gamepad}} object in + {{Navigator}}.{{Navigator/[[gamepads]]}}.
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 {{Gamepad/connected}} attribute MUST be set to - `false`. + Indicates whether the [=gamepad=] is [=available=].

The {{Gamepad/connected}} getter steps are: @@ -642,17 +589,11 @@

- The {{Gamepad/timestamp}} allows the author to determine the last - time the {{Gamepad/axes}} or {{Gamepad/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, {{Gamepad/timestamp}} MUST be the [=current high - resolution time=] at the time when the {{Gamepad}} was first made - available to script. + The {{Gamepad/timestamp}} allows the author to determine when the + [=input values=] for this {{Gamepad}} updated.

- [=User agent=]s SHOULD set a minimum resolution of |gamepad|'s + [=User agents=] SHOULD set a minimum resolution of the {{Gamepad/timestamp}} attribute to 5 microseconds, following [[HR-TIME]]'s clock resolution recommendation.

@@ -669,18 +610,20 @@

- 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 {{Gamepad/mapping}} to the corresponding - {{GamepadMappingType}} value. + Indicates whether inputs in the [=axis list=] and [=button list=] + are reordered when setting {{Gamepad}}.{{Gamepad/axes}} and + {{Gamepad}}.{{Gamepad/buttons}}. If the [=user agent=] has + knowledge of the [=input control layout=], then it SHOULD indicate + that a mapping is in use by setting {{Gamepad/mapping}} to the + corresponding {{GamepadMappingType}} value.

To select a mapping for a - gamepad device, run the following steps: + [=gamepad=], run the following steps:

    -
  1. If the button and axis layout of the gamepad device corresponds - with the [=Standard Gamepad=] layout, then return +
  2. If the [=input control layout=] [=corresponds with=] the + [=Standard Gamepad=] layout, then return {{GamepadMappingType/"standard"}}.
  3. Return {{GamepadMappingType/""}}. @@ -692,17 +635,18 @@

    - 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). + Array of values for all [=axis=] inputs of the [=gamepad=] + normalized to the range [-1 .. 1]. If the [=gamepad=] is + perpendicular to the ground with the thumbsticks pointing up, -1 + SHOULD correspond to "forward" or "left", and 1 SHOULD correspond + to "backward" or "right". [=Axis=] inputs with [=input values=] + from a thumbstick, joystick, or another input control that reports + X and Y values SHOULD appear next to each other in the + {{Gamepad/axes}} array, X then Y. It is RECOMMENDED that [=axis=] + inputs appear in decreasing order of importance, such that element + 0 and 1 typically represent the X and Y axes of a thumbstick or + joystick. The same object MUST be returned until the [=user agent=] + needs to return different values (or values in a different order).

    The {{Gamepad/axes}} getter steps are: @@ -717,12 +661,13 @@

    - 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). + 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 + {{Gamepad/buttons}} array. The same object MUST be returned until + the [=user agent=] needs to return different values (or values in a + different order).

    The {{Gamepad/buttons}} getter steps are: @@ -737,8 +682,8 @@

    - A [=list=] of {{GamepadTouch}} objects generated from all touch - surfaces. + A [=list=] of {{GamepadTouch}} objects representing the current + contact points across all [=touch surfaces=].

    The {{Gamepad/touches}} getter steps are: @@ -753,8 +698,8 @@

    - A {{GamepadHapticActuator}} object that represents the device's - primary vibration actuator. + A {{GamepadHapticActuator}} object that represents the + [=gamepad=]'s [=vibration actuator=].

    The {{Gamepad/vibrationActuator}} getter steps are: @@ -770,15 +715,27 @@

    Receiving inputs

    - When the system receives new button or axis input values, - run the following steps: + When an [=available=] [=gamepad=] has updated [=input values=], run + the following steps [=set/for each=] [=top-level traversable=] + |traversable| of the [=user agent=]'s [=user agent/top-level + traversable set=]:

      -
    1. Let |gamepad:Gamepad| be the {{Gamepad}} object representing the - device that received new button or axis input values. -
    2. -
    3. [=Queue a task=] on the [=gamepad task source=] to [=update - gamepad state=] for |gamepad|. +
    4. [=list/For each=] [=navigable=] of |traversable|'s + [=navigable/active document=]'s [=Document/inclusive descendant + navigables=]: +
        +
      1. Let |window:Window| be |navigable|'s [=navigable/active + window=]. +
      2. +
      3. Let |gamepad:Gamepad| be the {{Gamepad}} in + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}} + representing the [=gamepad=] that has updated [=input values=]. +
      4. +
      5. [=Queue a global task=] on the [=gamepad task source=] given + |window| to [=update gamepad state=] for |gamepad|. +
      6. +

    @@ -786,8 +743,13 @@

    following steps:

      +
    1. If |gamepad|'s [=relevant global object=] is not a {{Window}}, + abort these steps. +
    2. +
    3. Let |window| be |gamepad|'s [=relevant global object=]. +
    4. Let |now:DOMHighResTimeStamp| be the [=current high resolution - time=]. + time=] given |window|.
    5. Set |gamepad|.{{Gamepad/[[timestamp]]}} to |now|.
    6. @@ -797,17 +759,16 @@

    7. Run the steps to [=record touches=] for |gamepad|.
    8. -
    9. Let |navigator:Navigator| be |gamepad|'s [=relevant global - object=]'s {{Navigator}} object. -
    10. -
    11. If |navigator|.{{Navigator/[[hasGamepadGesture]]}} is `false` and - |gamepad| [=contains a gamepad user gesture=]: +
    12. If + |window|.{{Window/navigator}}.{{Navigator/[[hasGamepadGesture]]}} is + `false` and |gamepad| [=contains a gamepad user gesture=]:
        -
      1. Set |navigator|.{{Navigator/[[hasGamepadGesture]]}} to - `true`. +
      2. Set + |window|.{{Window/navigator}}.{{Navigator/[[hasGamepadGesture]]}} + to `true`.
      3. [=list/For each=] |connectedGamepad:Gamepad?| of - |navigator|.{{Navigator/[[gamepads]]}}: + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}:
        1. If |connectedGamepad| is not equal to `null`:
            @@ -817,16 +778,15 @@

          1. Set |connectedGamepad|.{{Gamepad/[[timestamp]]}} to |now|.
          2. -
          3. Let |document:Document?| be |gamepad|'s [=relevant - global object=]'s [=associated `Document`=]; otherwise - `null`. +
          4. Let |document:Document| be |window|'s [=associated + `Document`=].
          5. -
          6. If |document| is not `null` and is [=Document/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 {{GamepadEvent/gamepad}} - attribute initialized to |connectedGamepad|. +
          7. If |document| is [=Document/fully active=], then + [=queue a global task=] on the [=gamepad task source=] + given |window| to [=fire an event=] named + {{gamepadconnected}} at |window| using {{GamepadEvent}} + with its {{GamepadEvent/gamepad}} attribute initialized + to |connectedGamepad|.
        2. @@ -840,91 +800,101 @@

          following steps:

            -
          1. Let |axisValues:list| 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. -
          3. Let |maxRawAxisIndex:long| be the [=list/size=] of |axisValues| − - 1. +
          4. Let |rawGamepad| be the [=gamepad=] represented by |gamepad|.
          5. -
          6. [=list/For each=] |rawAxisIndex:long| of [=the range=] from 0 to - |maxRawAxisIndex|: +
          7. [=list/For each=] |rawAxisIndex:long| of the [=list/indices=] of + the [=axis list=] of |rawGamepad|:
              +
            1. Let |rawAxis| be the [=axis=] at index |rawAxisIndex| of the + [=axis list=]. +
            2. Let |mappedIndex:long| be |gamepad|.{{Gamepad/[[axisMapping]]}}[|rawAxisIndex|].
            3. -
            4. Let |logicalValue:unsigned long| be - |axisValues|[|rawAxisIndex|]. +
            5. Set |gamepad|.{{Gamepad/[[axes]]}}[|mappedIndex|] to the + current [=normalized axis value=] for |rawAxis|.
            6. -
            7. Let |logicalMinimum:unsigned long| be - |gamepad|.{{Gamepad/[[axisMinimums]]}}[|rawAxisIndex|]. -
            8. -
            9. Let |logicalMaximum:unsigned long| be - |gamepad|.{{Gamepad/[[axisMaximums]]}}[|rawAxisIndex|]. +
            +
          8. +
          +

          + To compute the normalized axis value for an [=axis=] + |rawAxis|: +

          +
            +
          1. Let |logicalValue:unsigned long| be the current [=logical + value=] for |rawAxis|. +
          2. +
          3. Let |logicalMinimum:unsigned long| be the [=logical minimum=] + for |rawAxis|. +
          4. +
          5. Let |logicalMaximum:unsigned long| be the [=logical maximum=] + for |rawAxis|. +
          6. +
          7. If |logicalValue| is less than |logicalMinimum|, set + |logicalValue| to |logicalMinimum|. +
          8. +
          9. If |logicalValue| is greater than |logicalMaximum|, set + |logicalValue| to |logicalMaximum|. +
          10. +
          11. +

            + If |rawAxis| has a [=center position value=]: +

            +
              +
            1. Let |center:unsigned long| be the [=center position value=] + for |rawAxis|.
            2. -
            3. Let |normalizedValue:double| be 2 (|logicalValue| − - |logicalMinimum|) / (|logicalMaximum| − |logicalMinimum|) − 1. +
            4. If |logicalValue| is greater than |center|, return + (|logicalValue| − |center|) / (|logicalMaximum| − |center|).
            5. -
            6. Set |gamepad|.{{Gamepad/[[axes]]}}[|axisIndex|] to be - |normalizedValue|. +
            7. Return (|logicalValue| − |center|) / (|center| − + |logicalMinimum|).
          12. +
          13. Return 2 (|logicalValue| − |logicalMinimum|) / (|logicalMaximum| + − |logicalMinimum|) − 1. +

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

            -
          1. Let |buttonValues:list| 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 |rawGamepad| be the [=gamepad=] represented by |gamepad|.
          3. -
          4. Let |maxRawButtonIndex:long| be the [=list/size=] of - |buttonValues| − 1. -
          5. -
          6. [=list/For each=] |rawButtonIndex:long| of [=the range=] from 0 - to |maxRawButtonIndex|: +
          7. [=list/For each=] |rawButtonIndex:long| of the [=list/indices=] + of the |rawGamepad|'s [=button list=]:
              +
            1. Let |rawButton| be the [=button=] at index |rawButtonIndex| + of |rawGamepad|'s [=button list=]. +
            2. Let |mappedIndex:long| be |gamepad|.{{Gamepad/[[buttonMapping]]}}[|rawButtonIndex|].
            3. -
            4. Let |logicalValue:unsigned long| be - |buttonValues|[|rawButtonIndex|]. -
            5. -
            6. Let |logicalMinimum:unsigned long| be - |gamepad|.{{Gamepad/[[buttonMinimums]]}}[|rawButtonIndex|]. -
            7. -
            8. Let |logicalMaximum:unsigned long| be - |gamepad|.{{Gamepad/[[buttonMaximums]]}}[|rawButtonIndex|]. -
            9. -
            10. Let |normalizedValue:double| be (|logicalValue| − - |logicalMinimum|) / (|logicalMaximum| − |logicalMinimum|). -
            11. -
            12. Let |button:GamepadButton| be - |gamepad|.{{Gamepad/[[buttons]]}}[|mappedIndex|]. -
            13. -
            14. Set |button|.{{GamepadButton/[[value]]}} to - |normalizedValue|. +
            15. Set + |gamepad|.{{Gamepad/[[buttons]]}}[|mappedIndex|].{{GamepadButton/[[value]]}} + to the current [=normalized button value=] for |rawButton|.
            16. - If the button has a digital switch to indicate a pure pressed - or released state, set |button|.{{GamepadButton/[[pressed]]}} - to `true` if the button is pressed or `false` if it is not - pressed. + If |rawButton| has a [=digital button value=], set + |button|.{{GamepadButton/[[pressed]]}} to the [=digital + button value=].

              Otherwise, set |button|.{{GamepadButton/[[pressed]]}} to - `true` if the value is above the [=button press threshold=] - or `false` if it is not above the threshold. + `true` if the current [=normalized button value=] for + |rawButton| is above the [=button press threshold=] or + `false` if it is not above the threshold.

            17. - If the button is capable of detecting touch, set - |button|.{{GamepadButton/[[touched]]}} to `true` if the - button is currently being touched. + If |rawButton| has a [=button touch value=], set + |button|.{{GamepadButton/[[touched]]}} to |rawButton|'s + [=button touch value=].

              Otherwise, set |button|.{{GamepadButton/[[touched]]}} to @@ -934,67 +904,100 @@

          +

          + To compute the normalized button value for a [=button=] + |rawButton|: +

          +
            +
          1. If |rawButton| has an [=analog button value=]: +
              +
            1. Let |logicalMinimum:unsigned long| be the [=logical minimum=] + for |rawButton|. +
            2. +
            3. Let |logicalMaximum:unsigned long| be the [=logical maximum=] + for |rawButton|. +
            4. +
            5. Let |logicalValue:unsigned long| be the current [=analog + button value=] for |rawButton|. +
            6. +
            7. If |logicalValue| is less than |logicalMinimum|, set + |logicalValue| to |logicalMinimum|. +
            8. +
            9. If |logicalValue| is greater than |logicalMaximum|, set + |logicalValue| to |logicalMaximum|. +
            10. +
            11. Return (|logicalValue| − |logicalMinimum|) / + (|logicalMaximum| − |logicalMinimum|). +
            12. +
            +
          2. +
          3. If |rawButton| has a [=digital button value=] and its [=digital + button value=] is `true`, return 1. +
          4. +
          5. Return 0. +
          6. +

          To record touches for |gamepad:Gamepad|, run the following steps:

            -
          1. Assert: {{Gamepad}}.{{Gamepad/[[touches]]}} is [=list/empty=]. +
          2. [=list/Empty=] |gamepad|.{{Gamepad/[[touches]]}}.
          3. -
          4. Repeat the following steps for each touch surface on |gamepad| in - touch surface enumeration order: +
          5. [=list/For each=] |surfaceId:unsigned long| of the + [=list/indices=] of the [=touch surface list=] of the [=gamepad=] + represented by |gamepad|:
              -
            1. Let |surfaceId:unsigned long| be the current surface - enumeration index. +
            2. Let |surface| be the [=touch surface=] at index |surfaceId| + in the [=touch surface list=].
            3. -
            4. If the touch surface exposes maximum surface dimensions in - device units, then set |touch|.{{GamepadTouch/surfaceDimensions}} - to a {{DOMRectReadOnly}} with {{DOMRectReadOnly/width}} and - {{DOMRectReadOnly/height}} initialized to the maximum X and Y - dimensions on the touch surface in device units. +
            5. If |surface| has surface dimensions, then set + |touch|.{{GamepadTouch/surfaceDimensions}} to a + {{DOMRectReadOnly}} with {{DOMRectReadOnly/width}} initialized to + the [=surface width=] and {{DOMRectReadOnly/height}} initialized + to the [=surface height=].
            6. -
            7. Repeat the following steps for each active touch point - reported by the |gamepad| for the current touch surface. +
            8. [=list/For each=] |point| in |surface|'s [=active touch point + list=]:
              1. Let |touch:GamepadTouch| be a newly created {{GamepadTouch}} object.
              2. Set |touch|.{{GamepadTouch/surfaceId}} to be |surfaceId|.
              3. -
              4. If the touch data is part of an existing active touch - point tracked by the user agent: -
                  -
                1. Set |touch|.{{GamepadTouch/touchId}} to the touchId - of the active touch point. -
                2. -
                3. Otherwise, set touchId to nextTouchId and increment - nextTouchId. -

                  - If the Gamepad has multiple touch surfaces the touch - id will be unique across surfaces. -

                  -
                4. -
                +
              5. +

                + If |point| is [=part of an existing active touch point=], + set |touch|.{{GamepadTouch/touchId}} to the [=active + touch point id=]. +

                +

                + Otherwise, set |touch|.{{GamepadTouch/touchId}} to + |gamepad|.{{Gamepad/[[nextTouchId]]}} and increment + |gamepad|.{{Gamepad/[[nextTouchId]]}}. +

                +

                + If the {{Gamepad}} has multiple [=touch surfaces=] the + {{GamepadTouch/touchId}} will be unique across surfaces. +

              6. Set |touch|.{{GamepadTouch/position}} to a [=new=] {{DOMPointReadOnly}} with {{DOMPointReadOnly/x}} initialized - to device X coordinate relative to the device touch surface - and normalized to [-1.0,1.0] where -1.0 is the leftmost - coordinate and 1.0 is the rightmost coordinate and - {{DOMPointReadOnly/y}} initialized to the device touch - surface and normalized to [-1.0,1.0] where -1.0 is the - leftmost coordinate and 1.0 is the rightmost coordinate. -

                - `x = (2.0 * touchData.x / surfaceDimensions.width) - 1` -

                + to the [=touch x coordinate=] normalized to [-1 .. 1] where + -1 is the leftmost coordinate and 1 is the rightmost + coordinate and {{DOMPointReadOnly/y}} initialized to the + [=touch y coordinate=] normalized to [-1 .. 1] where -1 is + the topmost coordinate and 1 is the bottommost coordinate.

                + `x = (2.0 * touchData.x / surfaceDimensions.width) - + 1`
                `y = (2.0 * touchData.y / surfaceDimensions.height) - 1`

              7. -
              8. Add |touch| to {{Gamepad}}.{{Gamepad/[[touches]]}}. +
              9. [=list/Append=] |touch| to + |gamepad|.{{Gamepad/[[touches]]}}.
            9. @@ -1007,64 +1010,60 @@

              Constructing a `Gamepad`

              - A new `Gamepad` representing a connected gamepad device is - constructed by performing the following steps: + A new `Gamepad` representing an [=available=] [=gamepad=] + for a |window:Window| is constructed by performing the following + steps:

              1. Let |gamepad:Gamepad| be a newly created {{Gamepad}} instance:
                  -
                1. Initialize |gamepad|'s {{Gamepad/id}} attribute to an - identification string for the gamepad. +
                2. Initialize |gamepad|'s {{Gamepad/id}} attribute to the + [=gamepad identifier string=] for the [=gamepad=].
                3. Initialize |gamepad|'s {{Gamepad/index}} attribute to the - result of [=selecting an unused gamepad index=] for |gamepad|. + result of [=selecting an unused gamepad index=] given |window|.
                4. Initialize |gamepad|'s {{Gamepad/mapping}} attribute to the - result of [=selecting a mapping=] for the gamepad device. -
                5. -
                6. Initialize |gamepad|.{{Gamepad/[[connected]]}} to `true`. -
                7. -
                8. Initialize |gamepad|.{{Gamepad/[[timestamp]]}} to the - [=current high resolution time=]. -
                9. -
                10. Initialize |gamepad|.{{Gamepad/[[axes]]}} to the result of - [=initializing axes=] for |gamepad|. -
                11. -
                12. Initialize |gamepad|.{{Gamepad/[[buttons]]}} to the result of - [=initializing buttons=] for |gamepad|. -
                13. -
                14. Initialize |gamepad|.{{Gamepad/[[vibrationActuator]]}} - following the steps of [=constructing a GamepadHapticActuator=] - for |gamepad|. + result of [=selecting a mapping=] for the [=gamepad=].
              2. +
              3. Set |gamepad|.{{Gamepad/[[timestamp]]}} to the [=current high + resolution time=] given |window|. +
              4. +
              5. Set |gamepad|.{{Gamepad/[[axes]]}} to the result of + [=initializing axes=] for |gamepad|. +
              6. +
              7. Set |gamepad|.{{Gamepad/[[buttons]]}} to the result of + [=initializing buttons=] for |gamepad|. +
              8. +
              9. If the [=gamepad=] has a [=vibration actuator=], set + |gamepad|.{{Gamepad/[[vibrationActuator]]}} to the result of + [=constructing a GamepadHapticActuator=] for the [=gamepad=]'s + [=vibration actuator=]. +
              10. Return |gamepad|.

              To select an unused - gamepad index for |gamepad:Gamepad|, run the following steps: + gamepad index given |window:Window|, run the following steps:

                -
              1. Let |navigator:Navigator| be |gamepad|'s [=relevant global - object=]'s {{Navigator}} object. -
              2. -
              3. Let |maxGamepadIndex:long| be the [=list/size=] of - |navigator|.{{Navigator/[[gamepads]]}} − 1. -
              4. -
              5. [=list/For each=] |gamepadIndex:long| of [=the range=] from 0 to - |maxGamepadIndex|: +
              6. [=list/For each=] |gamepadIndex:long| of the [=list/indices=] of + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}:
                  -
                1. If |navigator|.{{Navigator/[[gamepads]]}}[|gamepadIndex|] is - `null`, then return |gamepadIndex|. +
                2. If + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}[|gamepadIndex|] + is `null`, then return |gamepadIndex|.
              7. -
              8. [=list/Append=] `null` to |navigator|.{{Navigator/[[gamepads]]}}. +
              9. [=list/Append=] `null` to + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}.
              10. Return the [=list/size=] of - |navigator|.{{Navigator/[[gamepads]]}} − 1. + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}} − 1.

              @@ -1072,33 +1071,18 @@

              |gamepad:Gamepad|, run the following steps:

                -
              1. Let |inputCount:long| be the number of axis inputs exposed by the - device represented by |gamepad|. -
              2. -
              3. Set |gamepad|.{{Gamepad/[[axisMinimums]]}} to a [=list=] of - {{unsigned long}} values with [=list/size=] equal to |inputCount| - containing minimum logical values for each of the axis inputs. -
              4. -
              5. Set |gamepad|.{{Gamepad/[[axisMaximums]]}} to a [=list=] of - {{unsigned long}} values with [=list/size=] equal to |inputCount| - containing maximum logical values for each of the axis inputs. -
              6. -
              7. Initialize |unmappedInputList| to be an empty [=list=]. -
              8. -
              9. Initialize |mappedIndexList| to be an empty [=list=]. -
              10. -
              11. Initialize |axesSize:long| to be 0. -
              12. -
              13. [=list/For each=] |rawInputIndex:long| of [=the range=] from 0 to - |inputCount| − 1: +
              14. [=list/For each=] |rawInputIndex:long| of the [=list/indices=] of + the [=axis list=] of the [=gamepad=] represented by |gamepad|:
                  -
                1. If the the gamepad axis at index |rawInputIndex| [=represents - a Standard Gamepad axis=]: +
                2. Let |rawAxis| be the [=axis=] at index |rawInputIndex| of the + [=axis list=]. +
                3. +
                4. If |rawAxis| [=represents a Standard Gamepad axis=]:
                  1. Let |canonicalIndex:long| be the [=canonical index=] for - the axis. + |rawAxis|.
                  2. -
                  3. If |mappedIndexList| [=list/contain=]s |canonicalIndex|, +
                  4. If |mappedIndexList| [=list/contains=] |canonicalIndex|, then append |rawInputIndex| to |unmappedInputList|.

                    Otherwise: @@ -1124,11 +1108,11 @@

                5. -
                6. Initialize |axisIndex:long| to be 0. +
                7. Let |axisIndex:long| be 0.
                8. [=list/For each=] |rawInputIndex:long| of |unmappedInputList|:
                    -
                  1. While |mappedIndexList| [=list/contain=]s |axisIndex|: +
                  2. While |mappedIndexList| [=list/contains=] |axisIndex|:
                    1. Increment |axisIndex|.
                    2. @@ -1144,7 +1128,7 @@

                  3. -
                  4. Initialize |axes| to be an empty [=list=]. +
                  5. Let |axes| be an empty [=list=].
                  6. [=list/For each=] |axisIndex:long| of [=the range=] from 0 to |axesSize| − 1, [=list/append=] 0 to |axes|. @@ -1153,35 +1137,20 @@

                  - To initialize buttons for a - gamepad, run the following steps: + To initialize buttons for + |gamepad:Gamepad|, run the following steps:

                    -
                  1. Let |inputCount:long| be the number of button inputs exposed by - the device represented by |gamepad|. -
                  2. -
                  3. Set |gamepad|.{{Gamepad/[[buttonMinimums]]}} to be a [=list=] of - {{unsigned long}} values with [=list/size=] equal to |inputCount| - containing minimum logical values for each of the button inputs. -
                  4. -
                  5. Set |gamepad|.{{Gamepad/[[buttonMaximums]]}} to be a [=list=] of - {{unsigned long}} values with [=list/size=] equal to |inputCount| - containing maximum logical values for each of the button inputs. -
                  6. -
                  7. Initialize |unmappedInputList| to be an empty [=list=]. -
                  8. -
                  9. Initialize |mappedIndexList| to be an empty [=list=]. -
                  10. -
                  11. Initialize |buttonsSize:long| to be 0. -
                  12. -
                  13. [=list/For each=] |rawInputIndex:long| of [=the range=] from 0 to - |inputCount| − 1: +
                  14. [=list/For each=] |rawInputIndex:long| of the [=list/indices=] of + the [=button list=] of the [=gamepad=] represented by |gamepad|:
                      -
                    1. If the the gamepad button at index |rawInputIndex| - [=represents a Standard Gamepad button=]: +
                    2. Let |rawButton| be the [=button=] at index |rawInputIndex| in + the [=button list=]. +
                    3. +
                    4. If |rawButton| [=represents a Standard Gamepad button=]:
                      1. Let |canonicalIndex:long| be the [=canonical index=] for - the button. + |rawButton|.
                      2. If |mappedIndexList| [=list/contain=]s |canonicalIndex|, then append |rawInputIndex| to |unmappedInputList|. @@ -1212,11 +1181,11 @@

                    5. -
                    6. Initialize |buttonIndex:long| to be 0. +
                    7. Let |buttonIndex:long| be 0.
                    8. [=list/For each=] |rawInputIndex:long| of |unmappedInputList|:
                        -
                      1. While |mappedIndexList| [=list/contain=]s |buttonIndex|: +
                      2. While |mappedIndexList| [=list/contains=] |buttonIndex|:
                        1. Increment |buttonIndex|.
                        2. @@ -1232,7 +1201,7 @@

                      3. -
                      4. Initialize |buttons| to be an empty [=list=]. +
                      5. Let |buttons| be an empty [=list=].
                      6. [=list/For each=] |buttonIndex:long| of [=the range=] from 0 to |buttonsSize| − 1, [=list/append=] a [=new=] {{GamepadButton}} to @@ -1248,8 +1217,8 @@

                        GamepadButton Interface

                        - This interface defines the state of an individual button on a gamepad - device. + This interface defines the state of an individual [=button=] on a + [=gamepad=] at a single point in time.

                                 [Exposed=Window]
                        @@ -1283,7 +1252,7 @@ 

                        `false` - A flag indicating that the button is pressed + A flag indicating that the [=button=] is pressed @@ -1294,7 +1263,7 @@

                        `false` - A flag indicating that the button is touched + A flag indicating that the [=button=] is touched @@ -1302,11 +1271,11 @@

                        [[\value]] - 0.0 + 0 - A {{double}} representing the button value scaled to the range [0.0 - .. 1.0] + A {{double}} in the range [0 .. 1] representing the degree to which + the [=button=] is activated @@ -1316,14 +1285,15 @@

                        - 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 + Indicates whether the [=button=] is pressed. 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. + a recommended value, the [=user agent=] SHOULD use that. In other + cases, the [=user agent=] SHOULD choose some other reasonable + value.

                        The {{GamepadButton/pressed}} getter steps are: @@ -1338,14 +1308,16 @@

                        - 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 {{GamepadButton/pressed}} attribute. + Indicates whether the [=button=] is detecting any interaction, + including interactions that do not cause the button to activate. If + the [=button=] has a [=button touch value=], + {{GamepadButton/touched}} is the [=button touch value=]. If the + [=button=] does not have a [=button touch value=] but has an + [=analog button value=], {{GamepadButton/touched}} is `true` if the + current [=analog button value=] is greater than the [=logical + minimum=], otherwise `false`. If the [=button=] does not have + a [=button touch value=] or an [=analog button value=], + {{GamepadButton/touched}} mirrors {{GamepadButton/pressed}}.

                        The {{GamepadButton/touched}} getter steps are: @@ -1360,12 +1332,15 @@

                        - 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. + A value in the range [0 .. 1] representing the degree to which the + [=button=] is activated. For [=buttons=] that have an [=analog + button value=], this property MUST be the [=analog button value=] + clamped to the [=logical minimum=] and [=logical maximum=] + and then linearly normalized to the range [0 .. 1]. 0 MUST + mean fully unpressed, and 1 MUST mean fully pressed. For + [=buttons=] without an [=analog button value=], only the values 0 + and 1 for fully unpressed and fully pressed respectively, MUST be + provided.

                        The {{GamepadButton/value}} getter steps are: @@ -1382,12 +1357,11 @@

                        GamepadTouch Interface

                        - This interface defines a touch on a gamepad's touch surface that - supports such input. The object consists of a touch - {{GamepadTouch/touchId}} that uniquely identifies the touch point from - the time the input medium (e.g. finger, stylus, etc) makes contact with - the touch device, up to the time the input medium is no longer making - contact with the touch device. + This interface represents a [=touch point=] on a [=touch surface=]. The + object consists of a {{GamepadTouch/touchId}} that uniquely identifies + the [=touch point=] from the time the input medium (e.g. finger, + stylus, etc) makes contact with the [=touch surface=], up to the time + the input medium is no longer making contact with the surface.

                                 dictionary GamepadTouch {
                        @@ -1402,42 +1376,47 @@ 

                        touchId attribute
                        - Unique id of the touch. Range is [0, 4294967295]. + Identifier shared by [=touch points=] that are [=part of an existing + active touch point=]. Range is [0 .. 4294967295].
                        - surfaceId + surfaceId attribute
                        - Unique id of the surface that generated the touch. + Identifier of the [=touch surface=] that generated the [=touch + point=].
                        - position + position attribute
                        - A {{DOMPointReadOnly}} which holds the {{DOMPointReadOnly/x}}, - {{DOMPointReadOnly/y}} coordinates of the touch. The z and w value - are currently unused. The range of each coordinate is normalized to - [-1.0, 1.0]. Along the x-axis, -1.0 references the leftmost - coordinate and 1.0 references the rightmost coordinate. Along the - y-axis, -1.0 references the topmost coordinate and 1.0 references the - bottommost coordinate. + A {{DOMPointReadOnly}} which holds the normalized [=touch x + coordinate=] and [=touch y coordinate=] of the [=touch point=] as + {{DOMPointReadOnly/x}} and {{DOMPointReadOnly/y}}. The + {{DOMPointReadOnly/z}} and {{DOMPointReadOnly/w}} values are + currently unused. The range of each coordinate is normalized to [-1 + .. 1]. Along the x-axis, -1 references the leftmost coordinate and 1 + references the rightmost coordinate. Along the y-axis, -1 references + the topmost coordinate and 1 references the bottommost coordinate.
                        - surfaceDimensions + surfaceDimensions attribute
                        - A {{DOMRectReadOnly}} initialized with the {{DOMRectReadOnly/width}} - and {{DOMRectReadOnly/height}} of the touch surface in integer units. - If not available then null. + A {{DOMRectReadOnly}} initialized with the [=surface width=] and + [=surface height=] of the [=touch surface=] as + {{DOMRectReadOnly/width}} and {{DOMRectReadOnly/height}}, if the + [=touch surface=] has surface dimensions. Otherwise, `null`.

- GamepadMappingType enum + GamepadMappingType Enum

- This enum defines the set of known mappings for a Gamepad. + This enum defines the mapping types for mapping from a [=gamepad=] to a + {{Gamepad}}.

         enum GamepadMappingType {
@@ -1451,23 +1430,27 @@ 

""
- The empty string indicates that no mapping is in use for this - gamepad. + The empty string indicates that the [=gamepad=] does not have an + [=input control layout=], or the [=user agent=] does not know the + [=gamepad=]'s [=input control layout=], or the layout [=corresponds + with=] none of the standard layouts. The {{Gamepad/axes}} and + {{Gamepad/buttons}} arrays are not reordered.
"standard"
- The Gamepad's controls have been mapped to the [=Standard Gamepad=] - layout. + The [=gamepad=]'s [=input control layout=] [=corresponds with=] the + [=Standard Gamepad=] layout. The {{Gamepad/axes}} and + {{Gamepad/buttons}} arrays are reordered.
"xr-standard"
- The Gamepad's controls have been mapped to the [="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-1]]]. Gamepads returned by + [[[webxr-gamepads-module-1]]]. {{Gamepad}} objects returned by {{Navigator/getGamepads()}} MUST NOT report a {{Gamepad/mapping}} of {{GamepadMappingType/"xr-standard"}}.
@@ -1479,9 +1462,9 @@

GamepadHapticActuator Interface

- A {{GamepadHapticActuator}} corresponds to a configuration of motors or - other actuators that can apply a force for the purposes of haptic - feedback. + This interface represents a [=haptic actuator=] capable of playing + [=haptic effects=] that move the [=gamepad=] in a way that can be felt + by the user.

         [Exposed=Window]
@@ -1542,10 +1525,11 @@ 

Array of {{Gamepad/GamepadHapticEffectType}} values representing - all the types of haptic effects that the actuator supports. This - property lists the {{Gamepad/GamepadHapticEffectType}} values that - the actuator supports, unless the [=user agent=] does not support - playing effects of that type. + all the types of [=haptic effects=] that the + {{GamepadHapticActuator}} supports. This property lists the + {{Gamepad/GamepadHapticEffectType}} values that the actuator + supports, unless the [=user agent=] does not support playing + effects of that type.

The {{GamepadHapticActuator/effects}} getter steps are: @@ -1562,20 +1546,25 @@

The {{GamepadHapticActuator/playEffect()}} method steps, called with {{GamepadHapticEffectType}} |type:GamepadHapticEffectType| and - {{GamepadEffectParameters}} |params:GamepadEffectParameters |, are: + {{GamepadEffectParameters}} |params:GamepadEffectParameters|, are:

  1. If |params:GamepadEffectParameters| does not describe a [=valid effect=] of type |type:GamepadHapticEffectType|, return [=a promise rejected with=] a {{TypeError}}.
  2. -
  3. Let |document:Document?| be the [=current settings object=]'s - [=relevant global object=]'s [=associated `Document`=]. +
  4. If the [=current global object=] is not a {{Window}}, return + [=a promise rejected with=] an "{{InvalidStateError}}" + {{DOMException}}. +
  5. +
  6. Let |window:Window| be the [=current global object=].
  7. -
  8. If |document| is `null` or |document| is not [=Document/fully - active=] or |document|'s [=Document/visibility state=] is - `"hidden"`, return [=a promise rejected with=] an - "{{InvalidStateError}}" {{DOMException}}. +
  9. Let |document:Document| be the |window|'s [=associated + `Document`=]. +
  10. +
  11. If |document| is not [=Document/fully active=] or |document|'s + [=Document/visibility state=] is `"hidden"`, return [=a promise + rejected with=] an "{{InvalidStateError}}" {{DOMException}}.
  12. If [=this=].{{GamepadHapticActuator/[[playingEffectPromise]]}} is not `null`: @@ -1587,33 +1576,32 @@

    [=this=].{{GamepadHapticActuator/[[playingEffectPromise]]}} to `null`.

  13. -
  14. [=Queue a global task=] on the [=relevant global object=] - of [=this=] using the [=gamepad task source=] to [=resolve=] - |effectPromise| with {{GamepadHapticsResult/"preempted"}}. +
  15. [=Queue a global task=] on the [=gamepad task source=] with + |window| to [=resolve=] |effectPromise| with + {{GamepadHapticsResult/"preempted"}}.
-
  • If |this|'s gamepad's actuator cannot [=play effects with - type=] |type|, return [=a promise rejected with=] reason +
  • If [=this=] {{GamepadHapticActuator}} cannot [=play effects + with type=] |type|, return [=a promise rejected with=] reason {{NotSupportedError}}.
  • Let {{GamepadHapticActuator/[[playingEffectPromise]]}} be [=a new promise=].
  • -
  • Let |playEffectTimestamp:DOMHighResTimestamp| be the [=current - high resolution time=] given the |document|'s [=relevant global - object=]. +
  • Let |playEffectTimestamp:DOMHighResTimeStamp| be the [=current + high resolution time=] given |window|.
  • Do the following steps [=in parallel=]:
      -
    1. [=Issue a haptic effect=] to the actuator with |type|, - |params|, and the |playEffectTimestamp|. +
    2. [=Play a haptic effect=] on the [=haptic actuator=] + represented by [=this=] with |type|, |params|, and the + |playEffectTimestamp|.
    3. When the effect completes, if [=this=].{{GamepadHapticActuator/[[playingEffectPromise]]}} is - not `null`, [=queue a global task=] on the [=relevant global - object=] of [=this=] using the [=gamepad task source=] to run - the following steps: + not `null`, [=queue a global task=] on the [=gamepad task + source=] with |window| to run the following steps:
      1. If [=this=].{{GamepadHapticActuator/[[playingEffectPromise]]}} @@ -1643,13 +1631,18 @@

        The {{GamepadHapticActuator/reset()}} method steps are:

          -
        1. Let |document:Document?| be the [=current settings object=]'s - [=relevant global object=]'s [=associated `Document`=]. +
        2. If the [=current global object=] is not a {{Window}}, return + [=a promise rejected with=] an "{{InvalidStateError}}" + {{DOMException}}. +
        3. +
        4. Let |window:Window| be the [=current global object=].
        5. -
        6. If |document| is `null` or |document| is not [=Document/fully - active=] or |document|'s [=Document/visibility state=] is - `"hidden"`, return [=a promise rejected with=] an - "{{InvalidStateError}}" {{DOMException}}. +
        7. Let |document:Document| be |window|'s [=associated + `Document`=]. +
        8. +
        9. If |document| is not [=Document/fully active=] or |document|'s + [=Document/visibility state=] is `"hidden"`, return [=a promise + rejected with=] an "{{InvalidStateError}}" {{DOMException}}.
        10. Let |resetResultPromise:Promise| be [=a new promise=].
        11. @@ -1659,7 +1652,8 @@

        12. Let |effectPromise| be [=this=].{{GamepadHapticActuator/[[playingEffectPromise]]}}.
        13. -
        14. [=Stop haptic effects=] on [=this=]'s gamepad's actuator. +
        15. [=Stop haptic effects=] on the [=haptic actuator=] + represented by [=this=] {{GamepadHapticActuator}}.
        16. If the effect has been successfully stopped, do:
            @@ -1669,9 +1663,8 @@

            [=this=].{{GamepadHapticActuator/[[playingEffectPromise]]}} to `null`. -
          1. [=Queue a global task=] on the [=relevant global - object=] of [=this=] using the [=gamepad task source=] to - [=resolve=] |effectPromise| with +
          2. [=Queue a global task=] on [=gamepad task source=] with + |window| to [=resolve=] |effectPromise| with {{GamepadHapticsResult/"preempted"}}.
          @@ -1721,56 +1714,70 @@

        - To issue a haptic effect on an actuator, the [=user agent=] - MUST send a command to the device to render an effect of - |type:GamepadHapticEffectType| and try to make it use the provided - |params:GamepadEffectParameters|. The [=user agent=] SHOULD use the - provided |playEffectTimestamp:DOMHighResTimestamp| for more precise - playback timing when |params|.{{GamepadEffectParameters/startDelay}} is - not `0.0`. The [=user agent=] MAY modify the effect to increase - compatibility. For example, an effect intended for a rumble motor may - be transformed into a waveform-based effect for a device that supports - waveform haptics but lacks rumble motors. + To play a haptic effect on a [=haptic actuator=], the [=user + agent=] MUST command the [=haptic actuator=] to render a [=haptic + effect=] of |type:GamepadHapticEffectType| and try to make it use the + provided |params:GamepadEffectParameters|. The [=user agent=] SHOULD + use the provided |playEffectTimestamp:DOMHighResTimeStamp| for more + precise playback timing when + |params|.{{GamepadEffectParameters/startDelay}} is not 0. The [=user + agent=] MAY modify the effect to increase compatibility. For example, + an effect intended for a rumble motor may be transformed into a + waveform-based effect for a device that supports waveform haptics but + lacks rumble motors.

        - To stop haptic effects on an actuator, the [=user agent=] - MUST send a command to the device to abort any effects currently being - played. If a haptic effect was interrupted, the actuator SHOULD return - to a motionless state as quickly as possible. + To stop haptic effects on a [=haptic actuator=], the [=user + agent=] MUST command the [=haptic actuator=] to abort any effects + currently being played on that actuator. If a [=haptic effect=] was + interrupted, the actuator SHOULD return to a motionless state as + quickly as possible.

        Handling visibility change

        - When the |document|'s [=Document/visibility state=] becomes - `"hidden"`, run these steps for each {{GamepadHapticActuator}} - |actuator:GamepadHapticActuator|: + When the |document:Document|'s [=Document/visibility state=] becomes + `"hidden"`, run these steps:

          -
        1. If |actuator|.{{GamepadHapticActuator/[[playingEffectPromise]]}} - is `null`, abort these steps. +
        2. Let |window:Window| be |document|'s [=relevant global object=].
        3. -
        4. [=Queue a global task=] on the [=relevant global object=] of - |actuator| using the [=gamepad task source=] to run the following - steps: +
        5. [=list/For each=] |gamepad:Gamepad?| of + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}:
            +
          1. If |gamepad| is `null`, continue. +
          2. +
          3. If |gamepad|.{{Gamepad/vibrationActuator}} is `null`, + continue. +
          4. If - |actuator|.{{GamepadHapticActuator/[[playingEffectPromise]]}} is - `null`, abort these steps. + |gamepad|.{{Gamepad/vibrationActuator}}.{{GamepadHapticActuator/[[playingEffectPromise]]}} + is `null`, continue.
          5. -
          6. [=Resolve=] - |actuator|.{{GamepadHapticActuator/[[playingEffectPromise]]}} - with {{GamepadHapticsResult/"preempted"}}. +
          7. [=Queue a global task=] on the [=gamepad task source=] with + |window| to run the following steps: +
              +
            1. If + |gamepad|.{{Gamepad/vibrationActuator}}.{{GamepadHapticActuator/[[playingEffectPromise]]}} + is `null`, abort these steps. +
            2. +
            3. [=Resolve=] + |gamepad|.{{Gamepad/vibrationActuator}}.{{GamepadHapticActuator/[[playingEffectPromise]]}} + with {{GamepadHapticsResult/"preempted"}}. +
            4. +
            5. Set + |gamepad|.{{Gamepad/vibrationActuator}}.{{GamepadHapticActuator/[[playingEffectPromise]]}} + to `null`. +
            6. +
          8. -
          9. Set - |actuator|.{{GamepadHapticActuator/[[playingEffectPromise]]}} to - `null`. +
          10. [=Stop haptic effects=] on the [=haptic actuator=] + represented by |gamepad|.{{Gamepad/vibrationActuator}}.
        6. -
        7. [=Stop haptic effects=] on |actuator|. -
        @@ -1780,22 +1787,19 @@

        A new |gamepadHapticActuator:GamepadHapticActuator| representing a - {{Gamepad}}'s primary vibration actuator is constructed by performing - the following steps: + [=gamepad=]'s [=vibration actuator=] is constructed by performing the + following steps:

        1. Let |gamepadHapticActuator:GamepadHapticActuator| be a newly created {{GamepadHapticActuator}} instance.
        2. -
        3. Let `supportedEffectsList` be an empty list. +
        4. Set |gamepadHapticActuator|.{{GamepadHapticActuator/[[effects]]}} + to the [=supported effect types=] for the [=vibration actuator=].
        5. -
        6. For each enum value |type:GamepadHapticEffectType| of - {{GamepadHapticEffectType}}, if the [=user agent=] can send a command - to initiate effects of that type on that actuator, append |type| to - `supportedEffectsList`. +
        7. Return |gamepadHapticActuator|.
        8. -
        9. Set |gamepadHapticActuator|.{{GamepadHapticActuator/[[effects]]}} - to `supportedEffectsList`. +
        10. Return |gamepadHapticActuator|.

        @@ -1816,7 +1820,7 @@

        - The haptic effected completed playing. + The [=haptic effect=] completed playing.

        @@ -1824,19 +1828,20 @@

        - The current effect was stopped or replaced (i.e., "preempted") by - another effect. + The current [=haptic effect=] was stopped or replaced (i.e., + "preempted") by another effect.

  • - GamepadHapticEffectType enum + GamepadHapticEffectType Enum

    - The effect type defines how the effect parameters are interpreted by - the actuator. + Each value represents a different style of [=haptic effect=]. The + effect type defines how to generate a [=haptic effect=] from the + {{GamepadEffectParameters}}.

             enum GamepadHapticEffectType {
    @@ -1852,10 +1857,10 @@ 

    {{GamepadHapticEffectType/"dual-rumble"}} describes a haptic configuration with an eccentric rotating mass (ERM) vibration motor - in each handle of a standard gamepad. In this configuration, either - motor is capable of vibrating the whole gamepad. The vibration + in each handle of a [=gamepad=]. In this configuration, either + motor is capable of vibrating the whole [=gamepad=]. The vibration effects created by each motor are unequal so that the effects of - each can be combined to create more complex haptic effects. + each can be combined to create more complex [=haptic effects=].

    A {{GamepadHapticEffectType/"dual-rumble"}} effect is a @@ -1871,7 +1876,7 @@

    {{GamepadEffectParameters/strongMagnitude}} and {{GamepadEffectParameters/weakMagnitude}} set the intensity levels for the low-frequency and high-frequency vibrations, normalized to - the range `[0,1]`, defaulting to 0. + the range [0 .. 1], defaulting to 0.

    Given {{GamepadEffectParameters}} |params:GamepadEffectParameters|, @@ -1879,8 +1884,8 @@

    effect|valid=] {{GamepadEffectParameters/duration}}, a [=valid effect|valid=] {{GamepadEffectParameters/startDelay}}, and both the {{GamepadEffectParameters/strongMagnitude}} and the - {{GamepadEffectParameters/weakMagnitude}} must be in the range - `[0,1]`. + {{GamepadEffectParameters/weakMagnitude}} must be in the range [0 + .. 1].

    @@ -1918,7 +1923,7 @@

    {{GamepadEffectParameters/leftTrigger}} and {{GamepadEffectParameters/rightTrigger}}, respectively, set the intensity levels for the left and right bottom front buttons - vibrations, normalized to the range `[0,1]`, defaulting to 0. + vibrations, normalized to the range [0 .. 1], defaulting to 0.

    Given {{GamepadEffectParameters}} |params:GamepadEffectParameters|, @@ -1928,8 +1933,8 @@

    {{GamepadEffectParameters/strongMagnitude}}, {{GamepadEffectParameters/weakMagnitude}}, {{GamepadEffectParameters/leftTrigger}}, and - {{GamepadEffectParameters/rightTrigger}} must be in the range - `[0,1]`. + {{GamepadEffectParameters/rightTrigger}} must be in the range [0 .. + 1].

    @@ -1939,9 +1944,9 @@

    GamepadEffectParameters Dictionary

    - A GamepadEffectParameters dictionary contains keys for - parameters used by haptic effects. The meaning of each key is defined - by the haptic effect, and some keys may be unused. + A `GamepadEffectParameters` dictionary contains keys for parameters + used by [=haptic effects=]. The meaning of each key is defined by the + haptic effect type, and some keys may be unused.

    To mitigate unwanted long-running effects, the [=user agent=] MAY limit @@ -2076,9 +2081,11 @@

    @@ -2170,11 +2180,11 @@

    - gamepad + gamepad attribute
    The {{GamepadEvent/gamepad}} attribute provides access to the - associated gamepad data for this event. + associated [=gamepad=] data for this event.
    @@ -2202,7 +2212,7 @@

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

    @@ -2220,35 +2230,36 @@

    {{Gamepad/mapping}} SHOULD be set to {{GamepadMappingType/"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. + 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 [=axis=] inputs 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 input + controls 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 + An [=axis=] input represents a Standard Gamepad axis if it + reports the [=input values=] 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 + [=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. + Gamepad=] [=axis=]. If there are multiple [=axis=] inputs 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. + A [=button=] input represents a Standard Gamepad button if + it reports the [=input values=] for a button or trigger, and the button + or trigger is located in approximately the same location as the + corresponding [=Standard Gamepad=] button or trigger.

    - 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. + 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=].

    @@ -2456,9 +2467,9 @@

    means of active fingerprinting. The [=user agent=] MAY alter the device information exposed through the API to reduce the fingerprinting surface. As an example, an implementation can require - that a {{Gamepad}} object have exactly the number of buttons and axes - defined in the [=Standard Gamepad=] layout even if more or fewer - inputs are present on the connected device. + that a {{Gamepad}} object have exactly the number of [=button=] and + [=axis=] inputs defined in the [=Standard Gamepad=] layout even if + more or fewer inputs are present on the connected device. [[FINGERPRINTING-GUIDANCE]]

    @@ -2485,7 +2496,7 @@

    Coordination with - requestAnimationFrame() + `requestAnimationFrame()`

    Interactive applications will typically be using the {{AnimationFrameProvider/requestAnimationFrame()}} method to drive @@ -2499,42 +2510,57 @@

    -

    +

    The gamepadconnected event -

    +

    - When a gamepad becomes available on the system, run the following - steps: + When a [=gamepad=] |availableGamepad| becomes [=available=], run the + following steps [=set/for each=] [=top-level traversable=] + |traversable| of the [=user agent=]'s [=user agent/top-level + traversable set=]:

      -
    1. Let |document:Document?| be the [=current global object=]'s - [=associated `Document`=]; otherwise `null`. +
    2. [=list/For each=] [=navigable=] |navigable| of |traversable|'s + [=navigable/active document=]'s [=Document/inclusive descendant + navigables=]: +
        +
      1. Let |window:Window| be |navigable|'s [=navigable/active + window=]. +
      2. +
      3. Run the steps to [=add an available gamepad=] + |availableGamepad| given |window|. +
      4. +
    3. -
    4. If |document| is not `null` and is not [=allowed to use=] the - `"gamepad"` permission, then abort these steps. +
    +

    + To add an available gamepad |rawGamepad| given + |window:Window|: +

    +
      +
    1. If |window|'s [=associated `Document`=] is not [=allowed to use=] + the `"gamepad"` permission, then abort these steps.
    2. -
    3. [=Queue a task=] on the [=gamepad task source=] to perform the - following steps: +
    4. [=Queue a global task=] on the [=gamepad task source=] given + |window| to perform the following steps:
        -
      1. Let |gamepad:Gamepad| be [=a new `Gamepad`=] representing the - gamepad. -
      2. -
      3. Let |navigator:Navigator| be |gamepad|'s [=relevant global - object=]'s {{Navigator}} object. +
      4. Let |gamepad:Gamepad| be [=a new `Gamepad`=] representing + |availableGamepad| for |window|.
      5. Set - |navigator|.{{Navigator/[[gamepads]]}}[|gamepad|.{{Gamepad/index}}] + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}[|gamepad|.{{Gamepad/index}}] to |gamepad|.
      6. -
      7. If |navigator|.{{Navigator/[[hasGamepadGesture]]}} is `true`: +
      8. If + |window|.{{Window/navigator}}.{{Navigator/[[hasGamepadGesture]]}} + is `true`:
        1. Set |gamepad|.{{Gamepad/[[exposed]]}} to `true`.
        2. If |document| is not `null` and is [=Document/fully active=], then [=fire an event=] named {{gamepadconnected}} at - |gamepad|'s [=relevant global object=] using {{GamepadEvent}} - with its {{GamepadEvent/gamepad}} attribute initialized to - |gamepad|. + |window| using {{GamepadEvent}} with its + {{GamepadEvent/gamepad}} attribute initialized to |gamepad|.
      9. @@ -2542,74 +2568,93 @@

      - User agents implementing this specification must provide a new DOM + [=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. + A [=user agent=] MUST dispatch this event type to indicate a + [=gamepad=] has become [=available=]. If a [=gamepad=] was already + [=available=] when the page was loaded, the {{gamepadconnected}} event + SHOULD be dispatched once any {{Gamepad}} [=contains a gamepad user + gesture=].

      -

      +

      The gamepaddisconnected event -

      + +

      + When a [=gamepad=] |unavailableGamepad| becomes [=unavailable=], run + the following steps [=set/for each=] [=top-level traversable=] + |traversable| of the [=user agent=]'s [=user agent/top-level + traversable set=]: +

      +
        +
      1. [=list/For each=] [=navigable=] |navigable| of |traversable|'s + [=navigable/active document=]'s [=Document/inclusive descendant + navigables=]: +
          +
        1. Let |window:Window| be |navigable|'s [=navigable/active + window=]. +
        2. +
        3. Run the steps to [=remove an unavailable gamepad=] + |unavailableGamepad| given |window|. +
        4. +
        +
      2. +

      - When a gamepad becomes unavailable on the system, run the following - steps: + To remove an unavailable gamepad |rawGamepad| given + |window:Window|:

        -
      1. Let |gamepad:Gamepad| be the {{Gamepad}} representing the - unavailable device. +
      2. Let |gamepad:Gamepad| be the {{Gamepad}} in + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}} representing + |unavailableGamepad|.
      3. -
      4. [=Queue a task=] on the [=gamepad task source=] to perform the - following steps: +
      5. [=Queue a global task=] on the [=gamepad task source=] given + |window| to perform the following steps:
        1. Set |gamepad|.{{Gamepad/[[connected]]}} to `false`.
        2. -
        3. Let |document:Document?| be |gamepad|'s [=relevant global - object=]'s [=associated `Document`=]; otherwise `null`. +
        4. Let |document:Document| be |window|'s [=associated + `Document`=].
        5. If |gamepad|.{{Gamepad/[[exposed]]}} is `true` and |document| - is not `null` and is [=Document/fully active=], then [=fire an - event=] named {{gamepaddisconnected}} at |gamepad|'s [=relevant - global object=] using {{GamepadEvent}} with its + is [=Document/fully active=], then [=fire an event=] named + {{gamepaddisconnected}} at |window| using {{GamepadEvent}} with its {{GamepadEvent/gamepad}} attribute initialized to |gamepad|.
        6. -
        7. Let |navigator:Navigator| be |gamepad|'s [=relevant global - object=]'s {{Navigator}} object. -
        8. Set - |navigator|.{{Navigator/[[gamepads]]}}[|gamepad|.{{Gamepad/index}}] + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}[|gamepad|.{{Gamepad/index}}] to `null`.
        9. -
        10. While |navigator|.{{Navigator/[[gamepads]]}} [=list/is not - empty=] and the last [=list/item=] of - |navigator|.{{Navigator/[[gamepads]]}} is `null`, [=list/remove=] - the last [=list/item=] of |navigator|.{{Navigator/[[gamepads]]}}. +
        11. While |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}} + [=list/is not empty=] and the last [=list/item=] of + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}} is `null`, + [=list/remove=] the last [=list/item=] of + |window|.{{Window/navigator}}.{{Navigator/[[gamepads]]}}.

      - User agents implementing this specification must provide a new DOM + [=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}}. + When a [=gamepad=] becomes [=unavailable=], 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}}.

      -

      +

      Other events -

      +

      More discussion needed, on whether to include or exclude axis and button changed events, and whether to roll them more together @@ -2645,7 +2690,7 @@

      - A [=document=]’s [=Document/permissions policy=] determines whether + A [=document=]'s [=Document/permissions policy=] determines whether any content in that document is allowed to access {{Navigator/getGamepads()}}. If disabled in any document, no content in the document will be [=allowed to use=]