Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made the xr-standard gamepad mapping more rigid #735

Merged
merged 7 commits into from Jun 27, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 30 additions & 28 deletions images/xr-standard-mapping.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 20 additions & 20 deletions index.bs
Expand Up @@ -1551,7 +1551,6 @@ Gamepad API Integration {#gamepad-api-integration}
ISSUE: <a href="https://github.com/immersive-web/webxr/issues/550">GitHub #550</a> - Additional restrictions, still under discussion, will be applied to the formatting of the {{XRInputSource/gamepad}}'s {{Gamepad/id}} attribute. Until those restrictions have been identified, all {{XRInputSource/gamepad}} {{Gamepad/id}}'s should default to <code>"unknown"</code>.
</section>

<section class="unstable">
"xr-standard" Gamepad Mapping {#xr-standard-gamepad-mapping}
-----------------------------

Expand All @@ -1567,13 +1566,13 @@ The WebXR Device API extends the {{GamepadMappingType}} to describe the mapping

The <dfn enum-value for="GamepadMappingType">xr-standard</dfn> mapping indicates that the layout of the buttons and axes of the {{XRInputSource/gamepad}} corresponds as closely as possible to the tables below.

In order to report a {{Gamepad/mapping}} of {{GamepadMappingType/xr-standard}} the device MUST report an {{XRInputSource/targetRayMode}} of {{XRTargetRayMode/tracked-pointer}} and MUST have a non-<code>null</code> {{XRInputSource/gripSpace}}. It also MUST have at least one touchpad or joystick and MUST have at least one primary button, often a trigger, separate from the touchpad or joystick. If a device does not meet the requirements for the {{GamepadMappingType/xr-standard}} mapping it may still be exposed on an {{XRInputSource}} with the <code>""</code> (empty string) mapping. The {{GamepadMappingType/xr-standard}} mapping MUST only be used by {{Gamepad}} instances reported by an {{XRInputSource}}.
In order to report a {{Gamepad/mapping}} of {{GamepadMappingType/xr-standard}} the device MUST report an {{XRInputSource/targetRayMode}} of {{XRTargetRayMode/tracked-pointer}} and MUST have a non-<code>null</code> {{XRInputSource/gripSpace}}. It also MUST have at least one touchpad or thumbstick and MUST have at least one primary button, often a trigger, separate from the touchpad or thumbstick. If a device does not meet the requirements for the {{GamepadMappingType/xr-standard}} mapping it may still expose a {{XRInputSource/gamepad}} with a {{Gamepad/mapping}} of <code>""</code> (empty string). The {{GamepadMappingType/xr-standard}} mapping MUST only be used by {{Gamepad}} instances reported by an {{XRInputSource}}.

<table class="tg">
<thead>
<tr>
<th>Buttons</th>
<th><code>xr-standard</code> Location</th>
<th><code>xr-standard</code> Binding</th>
toji marked this conversation as resolved.
Show resolved Hide resolved
<th>Required</th>
</tr>
</thead>
Expand All @@ -1585,18 +1584,18 @@ In order to report a {{Gamepad/mapping}} of {{GamepadMappingType/xr-standard}} t
</tr>
<tr>
<td>buttons[1]</td>
<td>Primary Touchpad/Joystick Button</td>
<td>Yes</td>
<td>Secondary Button/Grip Trigger</td>
<td>No</td>
</tr>
<tr>
<td>buttons[2]</td>
<td>Secondary Button/Grip Trigger</td>
<td>No</td>
<td>Touchpad Press</td>
<td>If thumbstick is not present</td>
toji marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<td>buttons[3]</td>
<td>Secondary Touchpad/Joystick Button</td>
<td>No</td>
<td>Thumbstick Press</td>
<td>If touchpad is not present</td>
toji marked this conversation as resolved.
Show resolved Hide resolved
</tr>
</tbody>
</table>
Expand All @@ -1605,39 +1604,40 @@ In order to report a {{Gamepad/mapping}} of {{GamepadMappingType/xr-standard}} t
<thead>
<tr>
<th>Axes</th>
<th><code>xr-standard</code> Location</th>
<th><code>xr-standard</code> Binding</th>
toji marked this conversation as resolved.
Show resolved Hide resolved
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>axes[0]</td>
<td>Primary Touchpad/Joystick X</td>
<td>Yes</td>
<td>Touchpad X</td>
<td>If thumbstick is not present</td>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side question, since primary axes were already required before: Are we requiring that all xr-standard gamepads have either a touchpad or thumbstick? What about simpler "remote-style" controllers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thoughts when initially laying out the mapping were that we wanted to ensure that if something was advertised as xr-standard developers could depend on it having a certain baseline level of functionality. I still think that's a reasonable goal, though it's maybe less important if paired with the profiles concept. And yes, that would mean that some input devices (Like the Daydream controller) wouldn't qualify for xr-standard.

If we wanted to loosen up on that restriction and simply say that xr-standard only means that the inputs are mapped to a predictable place, and does not imply which of them are present then we could do so. I think we might want to look at expanding the proposed generic profile set to be a bit more descriptive in that case, with variants like:

  • button-controller
  • touchpad-controller // This is basically just the daydream controller and.... anything else?
  • touchpad-button-controller
  • thumbstick-controller // Never seen a thumbstick controller without a separate trigger
  • thumbstick-button-controller
  • touchpad-thumbstick-controller // Is this actually a thing anywhere?
  • touchpad-thumbstick-button-controller

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we wanted to loosen up on that restriction and simply say that xr-standard only means that the inputs are mapped to a predictable place, and does not imply which of them are present then we could do so.

This aligns with what I've been thinking here. Before, we only had one concept, xr-standard, overloaded to serve two purposes:

  • xr-standard defined which controller parts map to which buttons/axes IDs
  • xr-standard promised a minimum profile of controller parts that developers could assume were present

We've now split these into two distinct mapping and profile concepts in the API. It seems reasonable to embrace that, simplifying the meaning of the xr-standard mapping to a pure ID mapping, and allowing profiles to make more specific promises.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we continue this thread as part of #738?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I support this direction. I'd kinda been feeling the same way as I looked over the actual spec text changes.

toji marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<td>axes[1]</td>
<td>Primary Touchpad/Joystick Y</td>
<td>Yes</td>
<td>Touchpad Y</td>
<td>If thumbstick is not present</td>
toji marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<td>axes[2]</td>
<td>Secondary Touchpad/Joystick X</td>
<td>No</td>
<td>Thumbstick X</td>
<td>If touchpad is not present</td>
toji marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<td>axes[3]</td>
<td>Secondary Touchpad/Joystick Y</td>
<td>No</td>
<td>Thumbstick Y</td>
<td>If touchpad is not present</td>
toji marked this conversation as resolved.
Show resolved Hide resolved
</tr>
</tbody>
</table>

Devices that lack one of the optional inputs listed in the tables above MUST preserve their place in the {{Gamepad/buttons}} or {{Gamepad/axes}} array, reporting a <dfn>placeholder button</dfn> or <dfn>placeholder axis</dfn>, respectively. A [=placeholder button=] MUST report <code>0</code> for {{GamepadButton/value}}, <code>false</code> for {{GamepadButton/pressed}}, and <code>false</code> for {{GamepadButton/touched}}. A [=placeholder axis=] MUST report <code>0</code>. [=Placeholder buttons=] and [=placeholder axis|axes=] MUST be omitted if they are the last element in the array or all following elements are also [=placeholder buttons=] or [=placeholder axis|axes=].

Additional buttons or axes may be exposed after these reserved indices, and SHOULD appear in order of decreasing importance. Related axes (such both axes of a joystick) SHOULD be grouped and, if applicable, SHOULD appear in X, Y, Z order. If a device has both a touchpad and a joystick the UA MAY designate whichever it chooses to be the primary axis-based input. Buttons reserved by the UA or platform MUST NOT be exposed.
Additional buttons or axes may be exposed after these reserved indices, and SHOULD appear in order of decreasing importance. Related axes (such as both axes of a thumbstick) MUST be grouped and, if applicable, MUST appear in X, Y, Z order. Buttons reserved by the UA or platform MUST NOT be exposed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to introduce further reserved indices in the future, we'd need some way to reconcile the additional indices. (I suppose this is true before this change as well)

Perhaps apps need to be explicit that they want an xr-standard mapping for their Gamepad - that way, we can later introduce an xr-standard-2 mapping or such that pushes out into button/axis 5, 6, etc.

Should the gamepad attribute perhaps be getGamepad(mapping)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty strongly against making that large of a change to this chunk of the API this late. (Though I don't object to introducing a xr-standard-2 at some point if needed.)

I do think we'll likely outgrow the current shape of the gamepad API at some point, but when that time comes I have a hunch that we'll be better served by introducing something along the lines of an action mapping API rather than continue to hack more robust concepts onto an API that obviously never expected to deal with them. (And hopefully at that point we have a few years of insight into how developers are using OpenXR to help inform our direction.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

Even if we later do need to support what I said in the gamepad API, there are slightly less clean ways to do it later without changes now - for example, when requesting your XRSession, you could centrally set xr-standard-2 as your preferring mapping for receiving xr-standard* gamepad buttons/axes.


NOTE: This diagram demonstrates how two potential controllers would be exposed with the {{GamepadMappingType/xr-standard}} mapping. <img src="images/xr-standard-mapping.svg" alt="Simple 'xr-standard' controller and Advanced 'xr-standard' controller">
<section class="note">
This diagram demonstrates how two example controllers would be exposed with the {{GamepadMappingType/xr-standard}} mapping. Images are not intended to represent any particular device and are used for reference purposes only. <img src="images/xr-standard-mapping.svg" alt="Simple 'xr-standard' controller and Advanced 'xr-standard' controller">
</section>

Layers {#layers}
Expand Down
49 changes: 26 additions & 23 deletions input-explainer.md
Expand Up @@ -313,7 +313,7 @@ function onXRFrame(timestamp, frame) {
if (inputSource && inputSource.gamepad) {
let gamepad = inputSource.gamepad;

// Use joystick or touchpad values for movement.
// Use touchpad values for movement.
if (gamepad.axes.length >= 2) {
MoveUser(gamepad.axes[0], gamepad.axes[1]);
}
Expand All @@ -336,29 +336,29 @@ The UA may update the `gamepad` state at any point, but it must remain constant

### XR gamepad mapping

The WebXR Device API also introduces a new standard controller layout indicated by the `mapping` value of `xr-standard`. (Additional mapping variants may be added in the future if necessary.) This defines a specific layout for the inputs most commonly found on XR controller devices today. The following table describes the buttons/axes and their physical locations:
The WebXR Device API also introduces a new standard controller layout indicated by the `mapping` value of `xr-standard`. (Additional mapping variants may be added in the future if necessary.) This defines a specific layout for the inputs most commonly found on XR controller devices today. The following table describes the buttons/axes and their associated physical inputs:

| Button | `xr-standard` Location |
| ---------- | --------------------------------- |
| buttons[0] | Primary trigger |
| buttons[1] | Primary Touchpad/Joystick click |
| buttons[2] | Grip/Secondary trigger |
| buttons[3] | Secondary Touchpad/Joystick click |
| Button | `xr-standard` Binding |
| ---------- | -----------------------|
| buttons[0] | Primary trigger |
toji marked this conversation as resolved.
Show resolved Hide resolved
| buttons[1] | Grip/Secondary trigger |
| buttons[2] | Touchpad press |
| buttons[3] | Thumbstick press |

| Axis | `xr-standard` Location |
| ------- | ----------------------------- |
| axes[0] | Primary Touchpad/Joystick X |
| axes[1] | Primary Touchpad/Joystick Y |
| axes[2] | Secondary Touchpad/Joystick X |
| axes[3] | Secondary Touchpad/Joystick Y |
| Axis | `xr-standard` Binding |
| ------- | ----------------------|
| axes[0] | Touchpad X |
| axes[1] | Touchpad Y |
| axes[2] | Thumbstick X |
| axes[3] | Thumbstick Y |

Additional device-specific inputs may be exposed after these reserved indices, but devices that lack one of the canonical inputs must still preserve their place in the array. If a device has both a touchpad and a joystick the UA should designate one of them to be the primary axis-based input and expose the other at axes[2] and axes[3] with an associated button at button[3].
Additional device-specific inputs may be exposed after these reserved indices, but devices that lack one of the canonical inputs must still preserve their place in the array.

In order to make use of the `xr-standard` mapping, a device must meet **at least** the following criteria:

- Is a `tracked-pointer` device.
- Has a trigger or similarly accessed button
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems fine to require at least a primary button/trigger for buttons[0].

Should we more strongly state then that this button MUST also trigger onselect for this XRInputSource?

- Has at least one touchpad or joystick
- Has at least one touchpad or thumbstick
toji marked this conversation as resolved.
Show resolved Hide resolved

devices that lack one of those elements may still expose `gamepad` data, but must not claim the `xr-standard` mapping. For example: The controls on the side of a Gear VR would not qualify for the `xr-standard` mapping because they represent a `gaze`-style input. Similarly, a Daydream controller would not qualify for the `xr-standard` mapping since it lacks a trigger.

Expand All @@ -368,13 +368,16 @@ Some native APIs rely on what's commonly referred to as an "action mapping" syst

When using an API that limits reading controller input to use of an action map, it is suggested that a mapping be created with one action per possible input, given the same name as the target input. For example, an similar mapping to the following may be used for each device:

| Button/Axis | Action name | Sample binding |
|-------------|------------------|---------------------------|
| button[0] | "trigger" | "[device]/trigger" |
| button[1] | "touchpad-click" | "[device]/touchpad/click" |
| button[2] | "grip" | "[device]/grip" |
| axis[0] | "touchpad-x" | "[device]/touchpad/x" |
| axis[1] | "touchpad-y" | "[device]/touchpad/y" |
| Button/Axis | Action name | Sample binding |
|-------------|--------------------|-----------------------------|
| button[0] | "trigger" | "[device]/trigger" |
| button[1] | "grip" | "[device]/grip" |
| button[2] | "touchpad-click" | "[device]/touchpad/click" |
| button[3] | "thumbstick-click" | "[device]/thumbstick/click" |
| axis[0] | "touchpad-x" | "[device]/touchpad/x" |
| axis[1] | "touchpad-y" | "[device]/touchpad/y" |
| axis[2] | "thumbstick-x" | "[device]/thumbstick/x" |
| axis[3] | "thumbstick-y" | "[device]/thumbstick/y" |

If the API does not provided a way to enumerate the available input devices, the UA should provide bindings for the left and right hand instead of a specific device and expose a `Gamepad` for any hand that has at least one non-`null` input.

Expand Down