Re: [w3c/gamepad] Add algorithms for getGamepads and events (#151)

@marcoscaceres commented on this pull request.

Great stuff @nondebug! I didn't manage to get all the way through it yet, but here is the initial set of comments. 

> @@ -170,6 +170,43 @@ <h2>
           readonly attribute FrozenArray&lt;GamepadButton&gt; buttons;
         };
       </pre>
+      <p>
+        Instances of {{Navigator}} are created with the internal slots described in the following table:
+      </p>
+      <table class="simple" dfn-for="Navigator" dfn-type="attribute">
+        <tr>
+          <th>Internal slot
+          <th>Initial value
+          <th>Description (non-normative)
+        <tr>
+          <td><dfn>[[\exposed]]</dfn>
+          <td>`false`
+          <td>A flag indicating that the {{Gamepad}} object has been exposed to script.
+        <tr>
+          <td><dfn>[[\axisMapping]]</dfn>
+          <td>`{}`

In the internal slots, we can switch to using infra types. That gives us nicer ways of working with things. 

```suggestion
          <td>An empty [=ordered map=]. 
```

> +        <tr>
+          <td><dfn>[[\exposed]]</dfn>
+          <td>`false`
+          <td>A flag indicating that the {{Gamepad}} object has been exposed to script.
+        <tr>
+          <td><dfn>[[\axisMapping]]</dfn>
+          <td>`{}`
+          <td>Mapping from unmapped axis index to an index in the {{Gamepad/axes}} array
+        <tr>
+          <td><dfn>[[\axisMinimums]]</dfn>
+          <td>`null`
+          <td>An array containing the minimum logical value for each axis.
+        <tr>
+          <td><dfn>[[\axisMaximums]]</dfn>
+          <td>`null`
+          <td>An array containing the maximum logical value for each axis.

Probably want a list or [=ordered set=] here... 

```suggestion
          <td>A [=list=] containing the maximum logical value for each axis.
```

Same for the rest that use "array"... 

> +      <table class="simple" dfn-for="Navigator" dfn-type="attribute">
+        <tr>
+          <th>Internal slot
+          <th>Initial value
+          <th>Description (non-normative)
+        <tr>
+          <td><dfn>[[\exposed]]</dfn>
+          <td>`false`
+          <td>A flag indicating that the {{Gamepad}} object has been exposed to script.
+        <tr>
+          <td><dfn>[[\axisMapping]]</dfn>
+          <td>`{}`
+          <td>Mapping from unmapped axis index to an index in the {{Gamepad/axes}} array
+        <tr>
+          <td><dfn>[[\axisMinimums]]</dfn>
+          <td>`null`

Maybe better to just init to an empty list... then we don't need to check if it's null VS if it's empty. 

> @@ -258,6 +295,81 @@ <h2>
           different values (or values in a different order).
         </dd>
       </dl>
+      <h3>Receiving new input values</h3>
+      <p>
+        When the system receives new input values from a gamepad, run the following steps:
+      </p>
+      <ol>
+        <li>Let |gamepad:Gamepad| be the {{Gamepad}} instance in |navigator:Navigator|.{{[[gamepads]]}} representing the gamepad.
+        <li>Let |axisValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical axis input values</a>.
+        <li>Let |buttonValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical button input values</a>.
+        <li>Queue a task (where?) to <a>update gamepad state</a> for |gamepad| with |axisValues| and |buttonValues|.
+      </ol>
+      To <dfn>update gamepad state</dfn> for |gamepad| with an <a>ordered array of logical axis input values</a> |axisValues:sequence&lt;unsigned long&gt;| and an <a>ordered array of logical button input values</a> |buttonValues:sequence&lt;unsigned long&gt;|, run the following steps:
+      <ol>
+        <li>Let |now:DOMHighResTimeStamp| be a {{DOMHighResTimeStamp}} representing the current time.

 
```suggestion
        <li>Let |now| be the [=current high resolution time=].
```

> @@ -258,6 +295,81 @@ <h2>
           different values (or values in a different order).
         </dd>
       </dl>
+      <h3>Receiving new input values</h3>
+      <p>
+        When the system receives new input values from a gamepad, run the following steps:
+      </p>
+      <ol>
+        <li>Let |gamepad:Gamepad| be the {{Gamepad}} instance in |navigator:Navigator|.{{[[gamepads]]}} representing the gamepad.
+        <li>Let |axisValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical axis input values</a>.
+        <li>Let |buttonValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical button input values</a>.
+        <li>Queue a task (where?) to <a>update gamepad state</a> for |gamepad| with |axisValues| and |buttonValues|.
+      </ol>
+      To <dfn>update gamepad state</dfn> for |gamepad| with an <a>ordered array of logical axis input values</a> |axisValues:sequence&lt;unsigned long&gt;| and an <a>ordered array of logical button input values</a> |buttonValues:sequence&lt;unsigned long&gt;|, run the following steps:
+      <ol>
+        <li>Let |now:DOMHighResTimeStamp| be a {{DOMHighResTimeStamp}} representing the current time.
+        <li>Let |gamepadsStart:DOMHighResTimeStamp| be the |navigationStart:DOMHighResTimeStamp| attribute of the {{PerformanceTiming}} interface.

Hmm... this bit is not right for a couple of reasons:  

 1.  `PerformanceTiming` is just an interface (not an instance)
 2. `PerformanceTiming` was not initiated to anything. 
 3. `navigationStart` is "obsolete".

If we just need "when the global object was created", then:  
  
```suggestion
        <li>Let |gamepadsStart| be the [=time origin=] of the [=global object=].
```

Also, we probably don't need an instance of `DOMHighResTimeStamp` above. 


> @@ -258,6 +295,81 @@ <h2>
           different values (or values in a different order).
         </dd>
       </dl>
+      <h3>Receiving new input values</h3>
+      <p>
+        When the system receives new input values from a gamepad, run the following steps:
+      </p>
+      <ol>
+        <li>Let |gamepad:Gamepad| be the {{Gamepad}} instance in |navigator:Navigator|.{{[[gamepads]]}} representing the gamepad.
+        <li>Let |axisValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical axis input values</a>.
+        <li>Let |buttonValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical button input values</a>.
+        <li>Queue a task (where?) to <a>update gamepad state</a> for |gamepad| with |axisValues| and |buttonValues|.
+      </ol>
+      To <dfn>update gamepad state</dfn> for |gamepad| with an <a>ordered array of logical axis input values</a> |axisValues:sequence&lt;unsigned long&gt;| and an <a>ordered array of logical button input values</a> |buttonValues:sequence&lt;unsigned long&gt;|, run the following steps:
+      <ol>
+        <li>Let |now:DOMHighResTimeStamp| be a {{DOMHighResTimeStamp}} representing the current time.
+        <li>Let |gamepadsStart:DOMHighResTimeStamp| be the |navigationStart:DOMHighResTimeStamp| attribute of the {{PerformanceTiming}} interface.
+        <li>Set |gamepad|.{{Gamepad/timestamp}} to |now| − |gamepadsStart|.

```suggestion
        <li>Set |gamepad|.{{Gamepad/timestamp}} to |now| − |gamepadsStart|.
        <p class="warning">User agents SHOULD set a minimum resolution of |gamepad|’s {{Gampad/timestamp}} attribute to 5 microseconds, following [[HR-TIME]]'s [=clock resolution=] recommendation.
        </p>
```

> +        When the system receives new input values from a gamepad, run the following steps:
+      </p>
+      <ol>
+        <li>Let |gamepad:Gamepad| be the {{Gamepad}} instance in |navigator:Navigator|.{{[[gamepads]]}} representing the gamepad.
+        <li>Let |axisValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical axis input values</a>.
+        <li>Let |buttonValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical button input values</a>.
+        <li>Queue a task (where?) to <a>update gamepad state</a> for |gamepad| with |axisValues| and |buttonValues|.
+      </ol>
+      To <dfn>update gamepad state</dfn> for |gamepad| with an <a>ordered array of logical axis input values</a> |axisValues:sequence&lt;unsigned long&gt;| and an <a>ordered array of logical button input values</a> |buttonValues:sequence&lt;unsigned long&gt;|, run the following steps:
+      <ol>
+        <li>Let |now:DOMHighResTimeStamp| be a {{DOMHighResTimeStamp}} representing the current time.
+        <li>Let |gamepadsStart:DOMHighResTimeStamp| be the |navigationStart:DOMHighResTimeStamp| attribute of the {{PerformanceTiming}} interface.
+        <li>Set |gamepad|.{{Gamepad/timestamp}} to |now| − |gamepadsStart|.
+        <li>Let |axisCount:long| be the length of |axisValues|.
+        <li>Initialize |rawAxisIndex:long| to be 0.
+        <li>While |rawAxisIndex| < |axisCount|:

```suggestion
        <li>While |rawAxisIndex| is less than |axisCount|:
```
😇

> +      <ol>
+        <li>Let |gamepad:Gamepad| be the {{Gamepad}} instance in |navigator:Navigator|.{{[[gamepads]]}} representing the gamepad.
+        <li>Let |axisValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical axis input values</a>.
+        <li>Let |buttonValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical button input values</a>.
+        <li>Queue a task (where?) to <a>update gamepad state</a> for |gamepad| with |axisValues| and |buttonValues|.
+      </ol>
+      To <dfn>update gamepad state</dfn> for |gamepad| with an <a>ordered array of logical axis input values</a> |axisValues:sequence&lt;unsigned long&gt;| and an <a>ordered array of logical button input values</a> |buttonValues:sequence&lt;unsigned long&gt;|, run the following steps:
+      <ol>
+        <li>Let |now:DOMHighResTimeStamp| be a {{DOMHighResTimeStamp}} representing the current time.
+        <li>Let |gamepadsStart:DOMHighResTimeStamp| be the |navigationStart:DOMHighResTimeStamp| attribute of the {{PerformanceTiming}} interface.
+        <li>Set |gamepad|.{{Gamepad/timestamp}} to |now| − |gamepadsStart|.
+        <li>Let |axisCount:long| be the length of |axisValues|.
+        <li>Initialize |rawAxisIndex:long| to be 0.
+        <li>While |rawAxisIndex| < |axisCount|:
+          <ol>
+            <li>Let |mappedIndex:long| be the value for key |rawAxisIndex| in |gamepad|.{{[[axisMapping]]}}.

Because we are using an [=ordered map=], Infra let's us do: 

```suggestion
            <li>Let |mapping:ordered map| be |gamepad|.{{[[axisMapping]]}}.
            <li>Let |mappedIndex:long| be |mapping|["rawAxisIndex"].
```
And so on... 

> @@ -258,6 +295,81 @@ <h2>
           different values (or values in a different order).
         </dd>
       </dl>
+      <h3>Receiving new input values</h3>
+      <p>
+        When the system receives new input values from a gamepad, run the following steps:
+      </p>
+      <ol>
+        <li>Let |gamepad:Gamepad| be the {{Gamepad}} instance in |navigator:Navigator|.{{[[gamepads]]}} representing the gamepad.
+        <li>Let |axisValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical axis input values</a>.
+        <li>Let |buttonValues:sequence&lt;unsigned long&gt;| be the gamepad's <a>ordered array of logical button input values</a>.
+        <li>Queue a task (where?) to <a>update gamepad state</a> for |gamepad| with |axisValues| and |buttonValues|.
+      </ol>
+      To <dfn>update gamepad state</dfn> for |gamepad| with an <a>ordered array of logical axis input values</a> |axisValues:sequence&lt;unsigned long&gt;| and an <a>ordered array of logical button input values</a> |buttonValues:sequence&lt;unsigned long&gt;|, run the following steps:

I think we might want a generalized initializer algorithm for creating Gamepad instances. Check out how I did it in Geo:

https://www.w3.org/TR/geolocation/#constructing-a-geolocationposition




> +        <li>Set |gamepad|.{{Gamepad/timestamp}} to |now| − |gamepadsStart|.
+        <li>Let |axisCount:long| be the length of |axisValues|.
+        <li>Initialize |rawAxisIndex:long| to be 0.
+        <li>While |rawAxisIndex| < |axisCount|:
+          <ol>
+            <li>Let |mappedIndex:long| be the value for key |rawAxisIndex| in |gamepad|.{{[[axisMapping]]}}.
+            <li>Let |logicalValue:unsigned long| be the value at index |rawAxisIndex| in |axisValues|.
+            <li>Let |logicalMinimum:unsigned long| be the value for key |rawAxisIndex| in |gamepad|.{{[[axisMinimums]]}}.
+            <li>Let |logicalMaximum:unsigned long| be the value for key |rawAxisIndex| in |gamepad|.{{[[axisMaximums]]}}.
+            <li>Let |normalizedValue:double| be 2 (|logicalValue| − |logicalMinimum|) / (|logicalMaximum| − |logicalMinimum|) − 1.
+            <li>Set the value at index |axisIndex| of |gamepad|.{{Gamepad/axes}} to |normalizedValue|.
+            <li>Increment |rawAxisIndex|.
+          </ol>
+        <li>Let |buttonCount:long| be the length of |buttonValues|.
+        <li>Initialize |rawButtonIndex:long| to be 0.
+        <li>While |rawButtonIndex| < |buttonCount|:

```suggestion
        <li>While |rawButtonIndex| is less than |buttonCount|:
```

> +        <li>Initialize |rawAxisIndex:long| to be 0.
+        <li>While |rawAxisIndex| < |axisCount|:
+          <ol>
+            <li>Let |mappedIndex:long| be the value for key |rawAxisIndex| in |gamepad|.{{[[axisMapping]]}}.
+            <li>Let |logicalValue:unsigned long| be the value at index |rawAxisIndex| in |axisValues|.
+            <li>Let |logicalMinimum:unsigned long| be the value for key |rawAxisIndex| in |gamepad|.{{[[axisMinimums]]}}.
+            <li>Let |logicalMaximum:unsigned long| be the value for key |rawAxisIndex| in |gamepad|.{{[[axisMaximums]]}}.
+            <li>Let |normalizedValue:double| be 2 (|logicalValue| − |logicalMinimum|) / (|logicalMaximum| − |logicalMinimum|) − 1.
+            <li>Set the value at index |axisIndex| of |gamepad|.{{Gamepad/axes}} to |normalizedValue|.
+            <li>Increment |rawAxisIndex|.
+          </ol>
+        <li>Let |buttonCount:long| be the length of |buttonValues|.
+        <li>Initialize |rawButtonIndex:long| to be 0.
+        <li>While |rawButtonIndex| < |buttonCount|:
+          <ol>
+            <li>Let |mappedIndex:long| be the value for key |rawButtonIndex| in |gamepad|.{{[[buttonMapping]]}}.

Nit: Might be nice to pull these steps and the ones above into a two little algorithms. Pass in |gamepad| and it computes and stores the |normalizedValue|. 

> +      <p>
+        The <a>user agent</a> MUST provide methods for retrieving <dfn data-lt="ordered array of axis inputs">ordered arrays of axis inputs</dfn> and <dfn data-lt="ordered array of button inputs">button inputs</dfn> for a gamepad such that there is a unique element in the axis array for each axis input and a unique element in the button array for each button input.
+        If the system enumerates axis and button inputs in a consistent order, then the methods SHOULD provide the inputs in that order.
+        Otherwise, the methods MAY use any consistent ordering.
+      </p>
+      <p>
+        The <a>user agent</a> MUST provide methods for retrieving <dfn data-lt="ordered array of minimum logical values">ordered arrays of minimum logical values</dfn> and <dfn data-lt="ordered array of maximum logical values">maximum logical values</dfn> for each gamepad input.
+        The ordering of these arrays MUST match the ordering of the <a>ordered array of axis inputs</a> and <a>ordered array of button inputs</a>.
+      </p>
+      <p>
+        The <a>user agent</a> MUST provide methods for retrieving <dfn data-lt="ordered array of logical axis input values">ordered arrays of logical axis input values</dfn> and <dfn data-lt="ordered array of logical button input values">button input values</dfn>.
+        These arrays MUST contain the most recent values received from the gamepad for each button and axis input.
+        The ordering of these arrays MUST match the ordering of the <a>ordered array of axis inputs</a> and <a>ordered array of button inputs</a>.
+      </p>

I'd suggest we delete these and just use Infra types. Also, it will avoid descriptors for things that happen algorithmically anyway. 

> @@ -358,68 +470,84 @@ <h2>
     </section>
     <section data-dfn-for="Navigator">
       <h2>
-        Navigator Interface extension
+        Extensions to the {{Navigator}} interface

Just "code" (backticks) for headings is ok... the Navigator object will be hyperlinked in the IDL:
 
```suggestion
        Extensions to the `Navigator` interface
```

 

> -          connected Gamepad with the corresponding index should return null.
-          <p>
-            The gamepad state returned from getGamepads() does not reflect
-            disconnection or connection until after the
-            <a>gamepaddisconnected</a> or <a>gamepadconnected</a> events have
-            fired.
-          </p>
-          <p>
-            As an example, if there is one connected gamepad with an index of
-            1, then the following code snippet describes the expected behavior:
-          </p>
-          <pre class="example highlight">
+      <p>
+        Instances of {{Navigator}} are created with the internal slots described in the following table:
+      </p>
+      <table class="simple" dfn-for=Navigator dfn-type=attribute>

```suggestion
      <table class="simple" dfn-for=Navigator>
```

> -          </p>
-          <p>
-            As an example, if there is one connected gamepad with an index of
-            1, then the following code snippet describes the expected behavior:
-          </p>
-          <pre class="example highlight">
+      <p>
+        Instances of {{Navigator}} are created with the internal slots described in the following table:
+      </p>
+      <table class="simple" dfn-for=Navigator dfn-type=attribute>
+        <tr>
+          <th>Internal slot
+          <th>Initial value
+          <th>Description (non-normative)
+        <tr>
+          <td><dfn>[[\hasGamepadGesture]]</dfn>

These should be: 

```suggestion
          <td><dfn data-dfn-for="Navigator">[[\hasGamepadGesture]]</dfn>
```

And then... to link... a little ugly... I know: 

```
{{Navigator/[[hasGamepadGesture]]}}
```

> +      <p>
+        The <a>user agent</a> MUST provide methods for retrieving <dfn data-lt="ordered array of axis inputs">ordered arrays of axis inputs</dfn> and <dfn data-lt="ordered array of button inputs">button inputs</dfn> for a gamepad such that there is a unique element in the axis array for each axis input and a unique element in the button array for each button input.
+        If the system enumerates axis and button inputs in a consistent order, then the methods SHOULD provide the inputs in that order.
+        Otherwise, the methods MAY use any consistent ordering.
+      </p>
+      <p>
+        The <a>user agent</a> MUST provide methods for retrieving <dfn data-lt="ordered array of minimum logical values">ordered arrays of minimum logical values</dfn> and <dfn data-lt="ordered array of maximum logical values">maximum logical values</dfn> for each gamepad input.
+        The ordering of these arrays MUST match the ordering of the <a>ordered array of axis inputs</a> and <a>ordered array of button inputs</a>.
+      </p>
+      <p>
+        The <a>user agent</a> MUST provide methods for retrieving <dfn data-lt="ordered array of logical axis input values">ordered arrays of logical axis input values</dfn> and <dfn data-lt="ordered array of logical button input values">button input values</dfn>.
+        These arrays MUST contain the most recent values received from the gamepad for each button and axis input.
+        The ordering of these arrays MUST match the ordering of the <a>ordered array of axis inputs</a> and <a>ordered array of button inputs</a>.
+      </p>

Just a note, only add a `data-lt=` to `dfn`s if you are creating an alias.

Like 
```
<dfn data-lt="fruit of the gods">bananas</dfn>  where the [=fruit of the gods=], and yet...
```

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/gamepad/pull/151#pullrequestreview-681435584

Received on Friday, 11 June 2021 07:17:50 UTC