close
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,7 @@ interface XRInputSource {
[SameObject] readonly attribute XRSpace targetRaySpace;
[SameObject] readonly attribute XRSpace? gripSpace;
[SameObject] readonly attribute Gamepad? gamepad;
[SameObject] readonly attribute FrozenArray<DOMString> profiles;
};
</pre>

Expand All @@ -1419,6 +1420,24 @@ The <dfn attribute for="XRInputSource">gripSpace</dfn> attribute is an {{XRSpace

The {{gripSpace}} MUST be <code>null</code> if the input source isn't inherently trackable such as for input sources with a {{targetRayMode}} of {{XRTargetRayMode/gaze}} or {{XRTargetRayMode/screen}}.

The <dfn attribute for="XRInputSource">profiles</dfn> attribute is a [=/list=] of [=input profile name=]s indicating both the preffered visual representation and behavior of the input source. For example, if the {{XRInputSource/gamepad}} attribute is not <code>null</code> the profile identifies the mapping of the buttons and axes of the attribute of the {{XRInputSource}}.

An <dfn for="XRInputSource">input profile name</dfn> is a lowercase {{DOMString}} containing no spaces, with separate words concatenated with a hyphen (<code>-</code>) character. A descriptive name should be chosen, using the preffered verbiage of the device vendor when possible. If the platform provides an appropriate identifier, such as a USB vendor and product ID, it MAY be used. Values that uniquely identify a single device, such as serial numbers, MUST NOT be used. The [=input profile name=] MUST NOT contain an indication of device handedness. If multiple user agents expose the same device, they SHOULD make an effort to report the same [=input profile name=].

Profiles are given in descending order of preference. Any [=input profile name=]s given after the first entry in the list should provide fallback values that represent alternative representations of the device. This may include a more generic or prior version of the device, a more widely recognized device that is sufficently similar, or a broad description of the device type (such as "touchpad-wand"). If multiple profiles are given, the {{XRInputSource/gamepad}} layouts they describe must all represent a superset or subset of every other profile in the list.

If the {{XRSession}}'s [=mode=] is {{XRSessionMode/inline}}, {{XRInputSource/profiles}} MUST be an empty list.

If the input device cannot be reliably identified, or the user agent wishes to mask the input device being used, it MAY choose to only report generic [=input profile name=]s or an empty list.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Given that we're now enumerating generic profile names in PR #738, how do we feel about requiring the profiles list to have at least one generic profile name in the list?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We should absolutely strongly recommend it, but I'm not sure if I'm comfortable requiring that for a few reasons:

  • If we're going to require that we really should put the profile names in the spec.
  • I don't think we'll have a generic profile for everything that might be exposed. (Hands, tracking pucks, stylus, body tracking markers...)
  • It's possible that there's some situations in which the underlying native API doesn't give you a sense of what the device looks like? (Especially true if you're using some custom attachment to a tracking puck.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That makes sense, though I do feel like we could reasonably bend the rules on the first point if we wanted to require a generic profile name for "masked" hardware. Not a blocking issue, though. If this turns out to be a problem we can always add it later.


<p class="note">
For example, the Samsung Odyssey controller is a design variant of the standard Windows Mixed Reality controller. Both controllers share the same input layout. As a result, the {{XRInputSource/profiles}} for a Samsung Odyssey controller could be: <code>["samsung-odyssey", "windows-mixed-reality", "touchpad-thumbstick-controller"]</code>. Here the first two profiles would indicate the same input layout for the {{XRInputSource/gamepad}} attribute, but the appearance of the controller is more precisely communicated by the first profile in the list, with the second profile describing an acceptable substitute. The last profile is a generic fallback that describes the device in the roughest sense. (It's a wand with a touchpad and thumbstick.)

Similarly, the Valve Index controller is backwards compatible with the HTC Vive controller, but the Index controller has additional buttons and axes. As a result, the {{XRInputSource/profiles}} for the Valve Index controller could be: <code>["valve-index", "htc-vive", "touchpad-thumbstick-controller"]</code>. In this case the gamepad layout described by the <code>"valve-index"</code> profile must be a superset of the layout described by the <code>"htc-vive"</code> profile. Also, the <code>"valve-index"</code> profile indicates the precise appearance of the controller, while the <code>"htc-vive"</code> controller has a significantly different appearance. In this case the UA would have deemed that difference acceptable. And as in the first example, the last profile is a generic fallback.

(Exact strings are examples only. This specification does not make any recommendation for profile strings.)
Comment thread
NellWaliczek marked this conversation as resolved.
</p>

The <dfn attribute for="XRInputSource">gamepad</dfn> attribute is a {{Gamepad}} that describes the state of any buttons and axes on the [=XR input source=]. If the [=XR input source=] does not have at least one of the following properties, the {{gamepad}} attribute MUST be <code>null</code>:

- Multiple buttons
Expand Down Expand Up @@ -1524,17 +1543,11 @@ Gamepad API Integration {#gamepad-api-integration}
{{Gamepad}} instances returned by an {{XRInputSource}}'s {{XRInputSource/gamepad}} attribute behave as described by the <a href="https://w3c.github.io/gamepad/">Gamepad API</a>, with several additional behavioral restrictions:

- {{XRInputSource/gamepad}} MUST NOT be included in the array returned by {{navigator.getGamepads()}}.
- {{XRInputSource/gamepad}}'s {{Gamepad/id}} attribute MUST be an empty string (<code>""</code>).
- {{XRInputSource/gamepad}}'s {{Gamepad/index}} attribute MUST be <code>-1</code>.
- {{XRInputSource/gamepad}}'s {{Gamepad/connected}} attribute MUST be <code>true</code> until the {{XRInputSource}} is removed from the [=list of active XR input sources=] or the {{XRSession}} is ended.
- If an axis reported by the {{XRInputSource/gamepad}}'s {{Gamepad/axes}} array represents an axis of a touchpad, the value MUST be <code>0</code> when the associated {{GamepadButton}}'s {{GamepadButton/touched}} is <code>false</code>.


The {{XRInputSource/gamepad}}'s {{Gamepad/id}} also enforces additional behavioral restrictions, and MUST conform to the following rules:

- If the {{XRSession}}'s [=mode=] is {{XRSessionMode/inline}} the {{XRInputSource/gamepad}}'s {{Gamepad/id}} MUST be <code>"unknown"</code>.
- If the input device cannot be reliably identified the {{XRInputSource/gamepad}}'s {{Gamepad/id}} MUST be <code>"unknown"</code>.
- If the UA masks the input device type for any reason the {{XRInputSource/gamepad}}'s {{Gamepad/id}} MUST be <code>"unknown"</code>

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>

Expand Down
49 changes: 28 additions & 21 deletions input-explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,21 +228,35 @@ For `tracked-pointer` input sources, it is often appropriate for the application
#### Choosing renderable models
The majority of `tracked-pointer` input sources will have a non-null `gamepad` attribute on the `XRInputSource` object. The `Gamepad`'s `id` is used to determine what should be rendered if the app intends to visualize the input source itself, rather than an alternative virtual object. (See the section on [Button and Axis State](#button-and-axis-state) for more details.)

The WebXR Device API currently does not offer any way to retrieve renderable resources that represent the input devices from the API itself, and as such the `Gamepad`'s `id` must be used as a key to load an appropriate resources from the application's server or a CDN. The example below presumes that the `getInputSourceRenderableModel` call would do the required lookup and caching.
The WebXR Device API currently does not offer any way to retrieve renderable resources that represent the input devices from the API itself, and as such the `XRInputSource`'s `profiles` must be used to identify and load an appropriate resources. (For example, from the application's server, a CDN, or a local cache.) The `profiles` provides a list of strings that identify the device, given in descending order of preference.
Comment thread
NellWaliczek marked this conversation as resolved.

For example, the Samsung Odyssey controller is a variant of the standard Windows Mixed Reality controller. As a result, the `profiles` for that controller could be:

```js
function loadRenderableInputModels(xrInputSource) {
// Don't load renderable models if the input source doesn't have a gamepad.
if (!inputSource.gamepad)
return;
// Exact strings are examples only.
["samsung-odyssey", "windows-mixed-reality", "touchpad-thumbstick-controller"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@thetuvix , given that this is your hardware, would you prefer the example strings to be different?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm curious to hear Alex's take on this, but given the time zone differences at the moment I'm going to assume that we can safely handle any concerns that do come up as a follow-up PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"Samsung Odyssey" is a headset and "Windows Mixed Reality" is a platform, so I'd probably go with samsung-odyssey-controller and windows-mixed-reality-controller, to differentiate from windows-mixed-reality-clicker, etc.

However, when we populate the initial registry with the identifiers we expect to be used at WebXR 1.0, we can shake out this example to match the registry then.

```

// Retrieve a mesh to render based on the gamepad object's id and handedness
let renderableModel = getInputSourceRenderableModel(inputSource.gamepad.id, inputSource.handedness);
if (!renderableModel)
return;
Applications should iterate through the list until a string is located that corresponds to a known model, which should then be used when rendering the input device. The example below presumes that the `getInputSourceRenderableModel` call would do the required lookup and caching.
Comment thread
NellWaliczek marked this conversation as resolved.

// Add the model to the imaginary 3D engine's scene.
scene.inputObjects.add(renderableModel, xrInputSource);
```js
function loadRenderableInputModels(xrInputSource) {
for (let profile of xrInputSource.profiles) {
// Retrieve a mesh to render based on the gamepad object's profile and handedness
let renderableModel = getInputSourceRenderableModel(profile, xrInputSource.handedness);

if (renderableModel) {
// Add the model to the imaginary 3D engine's scene.
scene.inputObjects.add(renderableModel, xrInputSource);
return;
}
}

// If the profiles list was empty or a corresponding model could not be found
// for any entry in it the application could respond by not rendering the
// device at all or rendering a generic device that is not intended to be a
// visual match. This sample chooses the latter approach.
scene.inputObjects.add(getDefaultInputSourceRenderableModel(), xrInputSource);
}
```

Expand Down Expand Up @@ -285,19 +299,11 @@ Examples of input sources that may expose their state this way include Oculus To
`Gamepad` instances reported in this way have several notable behavioral changes vs. the ones reported by `navigator.getGamepads()`:

- `Gamepad` instances connected to an `XRInputSource` must not be included in the array returned by `navigator.getGamepads()`.
- The `Gamepad`'s `id` attribute must be `""` (empty string).
- The `Gamepad`'s `index` attribute must be `-1`.
- The `Gamepad`'s `connected` attribute must be `true` unless the related `XRInputSource` is removed from the `inputSources` array or the related `XRSession` is ended.

Finally, the `id` attribute for `Gamepad`s surfaced by the WebXR API are more strictly formatted than those of traditional gamepads in order to make them a more appropriate key for determining rendering assets.

- The `id` MAY be `'unknown'` if the type of input source cannot be reliably identified or the UA determines that the input source type must be masked for any reason. Applications should render a generic input device in this case.
- Inline sessions MUST only expose `id`s of `'unknown'`.
- Otherwise the `id` must be a lower-case string that describes the physical input source.
- The exact format is [still under discussion](https://github.com/immersive-web/webxr/issues/550), but will probably need to include at least an indication of the input device's manufacturer and model. (Such as `oculus-touch`)
- It must not include an indication of the handedness of the input source (such as `oculus-touch-left`), as that can be determined from the `handedness` attribute.
- UAs SHOULD make an effort to align on the strings that are returned for any given device.

All other attributes behave as described in the [Gamepad](https://w3c.github.io/gamepad/) specification.
The exact button and axes layout is given by the `XRInputSource`'s `profiles` attribute, which contains an array of strings that identify the button and axes layout or subsets of it, ordered from most specific to least specific.

```js
function onXRFrame(timestamp, frame) {
Expand Down Expand Up @@ -413,6 +419,7 @@ interface XRInputSource {
readonly attribute XRSpace targetRaySpace;
readonly attribute XRSpace? gripSpace;
readonly attribute Gamepad? gamepad;
readonly attribute FrozenArray<DOMString> profiles;
};

[SecureContext, Exposed=Window]
Expand Down