From 701a3884157eee13194cb596b8cd0f2712e47ef9 Mon Sep 17 00:00:00 2001 From: Matt Reynolds Date: Tue, 18 Mar 2025 15:32:40 -0700 Subject: [PATCH 1/7] Add a model section --- index.html | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/index.html b/index.html index d7eda7e..34287c5 100644 --- a/index.html +++ b/index.html @@ -136,6 +136,164 @@

sensing, depth sensing, video analysis, gesture recognition, and so on.

+
+

+ Model +

+

+ A gamepad is a collection of input controls (buttons, + triggers, joysticks, thumbsticks, touch surfaces) and output controls + (haptic actuators). A [=gamepad=] is available if the [=user + agent=] can read the current state of its input controls. A [=gamepad=] + that is not [=available=] is unavailable. The collection of + input and output controls for a [=gamepad=] cannot change while the + [=gamepad=] is [=available=]. Each input control has one or more + input values that may update over time. +

+

+ The [=user agent=] is responsible for enumerating [=available=] + [=gamepads=], detecting when [=gamepads=] become [=available=] or + [=unavailable=], and detecting when input controls have updated input + values. +

+

+ A [=gamepad=] has a gamepad identifier string, a + human-readable string that identifies the brand or style of + [=gamepad=]. The content is decided by the [=user agent=]. +

+

+ A [=gamepad=] may be a physical device. If so, it has an input + control layout that describes the position, orientation and type + of each input control on the physical device. The [=user agent=] is + responsible for recognizing when an [=input control layout=] + corresponds with a standard + layout, meaning the relative positions and orientations of its + input controls are close enough to the standard layout that a user can + use it interchangeably with other devices that have the same input + controls and correspond with the same layout. +

+

+ A [=gamepad=] may have [=axis=] inputs. An axis is an input + control with the following [=input values=]: +

+
    +
  • A logical axis value, an integer value that represents + the current displacement of the control from a reference position. +
  • +
  • A minimum axis value, the smallest in-bounds [=logical + axis value=]. +
  • +
  • A maximum axis value, the largest in-bounds [=logical + axis value=]. +
  • +
+

+ A [=gamepad=] has an axis list which is a [=list=] + containing all the [=axis=] inputs for the [=gamepad=] in some order + determined by the [=user agent=]. +

+

+ An input control may be designed to automatically return an [=axis=] to + a center position when the user stops interacting with the input + control. If so, the [=axis=] has a preferred axis state. An + An [=axis=] with a [=preferred axis state=] may also have a center + position value [=input value=] which is the [=logical axis + value=] when the [=axis=] is centered. +

+

+ A [=gamepad=] may have [=button=] inputs. A button is an + input control that can be pressed to activate. A [=gamepad=] has a + button list which is a [=list=] containing all the + [=button=] inputs for the [=gamepad=] in some order determined by the + [=user agent=]. +

+

+ An input control may be designed to automatically return a [=button=] + to an unpressed state when the user stops interacting with the input + control. If so, the [=button=] has a preferred button state. +

+

+ A [=button=] may have a digital switch to indicate when the [=button=] + is activated. If so, the [=button=] has a digital button + value [=input value=] that is `true` when the [=button=] is + activated and `false` otherwise. +

+

+ A [=button=] may have an analog sensor enabling the [=button=] to + report the degree to which the [=button=] is activated. If so, the + [=button=] has these [=input values=]: +

+
    +
  • An analog button value, an integer value that represents + the degree of activation. +
  • +
  • A minimum analog value representing no activation. The + smallest in-bounds [=analog button value=]. +
  • +
  • A maximum analog value representing full activation. The + largest in-bounds [=analog button value=]. +
  • +
+

+ A [=button=] may be capable of detecting touch. If so, the [=button=] + has a button touch value [=input value=] that is `true` when + the [=button=] is touched and `false` otherwise. +

+

+ A [=gamepad=] may have [=touch surfaces=]. A touch surface + is an input control that provides 2D position data representing points + of contact. A [=gamepad=] has a touch surface list which is + a [=list=] containing the [=touch surfaces=] for the [=gamepad=]. The + list is ordered such that [=touch surfaces=] closer to the left side of + the [=gamepad=] appear closer to the start of the list. +

+

+ A [=touch surface=] has an active touch point list [=input + value=], a [=list=] of zero or more [=touch points=] representing the + points of contact currently detected by the sensor, ordered such that + earlier [=touch points=] appear closer to the start of the [=list=]. A + touch point represents a single point of contact at a single + point in time. A [=touch point=] has a touch x coordinate + representing its position along the user's left-right axis and a + touch y coordinate representing its position along the + perpendicular axis. +

+

+ A [=touch surface=] may have surface dimension [=input values=]. The + surface width and surface height [=input values=] + are the dimensions of the [=touch surface=] in the same units as the + [=touch x coordinate=] and [=touch y coordinate=]. A [=touch surface=] + has both dimension values or neither value. +

+

+ A [=touch point=] may be a new contact point or a continuation of an + earlier contact. A [=touch point=] is part of an existing active + touch point if the [=user agent=] identifies that it is a + continuation of a [=touch point=] represented by an earlier + {{GamepadTouch}}. The active touch point id for a [=touch + point=] is the {{GamepadTouch/touchId}} of the earlier + {{GamepadTouch}}. +

+

+ A [=gamepad=] may have [=haptic actuators=]. A haptic + actuator is an output control capable of moving the [=gamepad=] + in a way that can be felt by the user. A haptic effect is + the use of one or more [=haptic actuators=] to provide feedback to the + user. The [=user agent=] is responsible for commanding [=haptic + actuators=] to play and stop [=haptic effects=] on [=available=] + [=gamepads=]. +

+

+ A [=gamepad=] may have a vibration actuator which is a + [=haptic actuator=] capable of playing a [=haptic effect=] to vibrate + the whole [=gamepad=]. +

+

+ A [=haptic actuator=] has a [=list=] of supported effect + types containing one or more {{GamepadHapticEffectType}} values, + which cannot change while the [=gamepad=] is [=available=]. +

+

Gamepad interface From cd32d3ae1d60cb2478a1e60722bde8a448ab84d1 Mon Sep 17 00:00:00 2001 From: Matt Reynolds Date: Fri, 25 Apr 2025 20:23:36 -0700 Subject: [PATCH 2/7] Split model sections --- index.html | 113 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 38 deletions(-) diff --git a/index.html b/index.html index 34287c5..46742c2 100644 --- a/index.html +++ b/index.html @@ -141,37 +141,55 @@

Model

- A gamepad is a collection of input controls (buttons, - triggers, joysticks, thumbsticks, touch surfaces) and output controls - (haptic actuators). A [=gamepad=] is available if the [=user - agent=] can read the current state of its input controls. A [=gamepad=] - that is not [=available=] is unavailable. The collection of - input and output controls for a [=gamepad=] cannot change while the - [=gamepad=] is [=available=]. Each input control has one or more - input values that may update over time. + A gamepad is a collection of input controls and output controls. + An input control has a collection of input values that may update over time. + Input controls include the buttons, triggers, joysticks, thumbsticks, and touch surfaces of the [=gamepad=]. + An output control is a feature that changes the behavior of the [=gamepad=] to provide feedback to the user interacting with the [=gamepad=]. + Output controls include the haptic actuators of the [=gamepad=]. + A [=gamepad=] is available if the [=user agent=] can read the current state of its [=input controls=]. + A [=gamepad=] that is not [=available=] is unavailable. + The [=input controls=] and [=output controls=] for a [=gamepad=] cannot change while the [=gamepad=] is [=available=].

- The [=user agent=] is responsible for enumerating [=available=] - [=gamepads=], detecting when [=gamepads=] become [=available=] or - [=unavailable=], and detecting when input controls have updated input - values. + The [=user agent=] is responsible for: +

    +
  • Enumerating [=available=] [=gamepads=], +
  • +
  • Detecting when [=gamepads=] become [=available=] or [=unavailable=], +
  • +
  • Detecting when [=input controls=] have updated [=input values=], +
  • +
  • Reading the current state of [=input values=], and +
  • +
  • Commanding the [=gamepad=] to use its [=output controls=]. +
  • +

A [=gamepad=] has a gamepad identifier string, a human-readable string that identifies the brand or style of [=gamepad=]. The content is decided by the [=user agent=].

+
+

+ Input control layout +

- A [=gamepad=] may be a physical device. If so, it has an input - control layout that describes the position, orientation and type - of each input control on the physical device. The [=user agent=] is - responsible for recognizing when an [=input control layout=] - corresponds with a standard - layout, meaning the relative positions and orientations of its - input controls are close enough to the standard layout that a user can - use it interchangeably with other devices that have the same input - controls and correspond with the same layout. + A [=gamepad=] may have an input control layout that describes the position, orientation and type of each input control on the [=gamepad=]. + The [=user agent=] is responsible for recognizing when a [=gamepad=] corresponds with a standard layout, meaning the [=gamepad=] has an [=input control layout=] that enables it to be used interchangeably with other [=gamepads=] that correspond with the same standard layout. + The [=user agent=] SHOULD consider a layout to correspond with a standard layout if its [=input controls=] have approximately the same relative positions and orientations as [=input controls=] described in the standard layout.

+

+ The [=user agent=] typically cannot directly inspect the [=input control layout=] for a [=gamepad=] and MAY use heuristics to decide the layout. + The [=user agent=] SHOULD consider the device identifiers when deciding whether a [=gamepad=] [=corresponds with a standard layout=]. + If the system assigns a label to each [=input control=] and the labels imply a particular layout then the [=user agent=] SHOULD consider the [=gamepad=] to have that layout. + When there is a standard model and an accessible model with the same [=input controls=], the [=user agent=] SHOULD consider the accessible model to have the same [=input control layout=] as the standard model. +

+
+
+

+ Axes +

A [=gamepad=] may have [=axis=] inputs. An axis is an input control with the following [=input values=]: @@ -195,11 +213,16 @@

An input control may be designed to automatically return an [=axis=] to a center position when the user stops interacting with the input - control. If so, the [=axis=] has a preferred axis state. An - An [=axis=] with a [=preferred axis state=] may also have a center - position value [=input value=] which is the [=logical axis + control. If so, the [=axis=] has a preferred axis state. + An [=axis=] with a [=preferred axis state=] may also have an additional + [=input value=], the center position value, which is the [=logical axis value=] when the [=axis=] is centered.

+

+
+

+ Buttons +

A [=gamepad=] may have [=button=] inputs. A button is an input control that can be pressed to activate. A [=gamepad=] has a @@ -214,8 +237,8 @@

A [=button=] may have a digital switch to indicate when the [=button=] - is activated. If so, the [=button=] has a digital button - value [=input value=] that is `true` when the [=button=] is + is activated. If so, the [=button=] has an additional [=input value=], + the digital button value, that is `true` when the [=button=] is activated and `false` otherwise.

@@ -236,9 +259,14 @@

A [=button=] may be capable of detecting touch. If so, the [=button=] - has a button touch value [=input value=] that is `true` when + has an additional [=input value=], the button touch value, that is `true` when the [=button=] is touched and `false` otherwise.

+

+
+

+ Touch surfaces +

A [=gamepad=] may have [=touch surfaces=]. A touch surface is an input control that provides 2D position data representing points @@ -250,13 +278,15 @@

A [=touch surface=] has an active touch point list [=input value=], a [=list=] of zero or more [=touch points=] representing the - points of contact currently detected by the sensor, ordered such that - earlier [=touch points=] appear closer to the start of the [=list=]. A - touch point represents a single point of contact at a single - point in time. A [=touch point=] has a touch x coordinate - representing its position along the user's left-right axis and a - touch y coordinate representing its position along the - perpendicular axis. + points of contact currently detected by the sensor. A touch + point represents a single point of contact at a single point in + time. A [=touch point=] has a touch x coordinate + and a touch y coordinate representing the position in the [=touch surface=]'s coordinate system. + If a [=touch surface=] is on the top, bottom, front, or back side of the [=gamepad=] then the [=touch x coordinate=] is measured along the left-right axis, otherwise it is measured along the top-bottom axis. + The [=touch y coordinate=] is measured along the perpendicular axis. +

+

+ If a [=touch surface=] is on the left or right side of a [=gamepad=] then neither of its dimensions will align with the horizontal axis.

A [=touch surface=] may have surface dimension [=input values=]. The @@ -271,15 +301,21 @@

touch point if the [=user agent=] identifies that it is a continuation of a [=touch point=] represented by an earlier {{GamepadTouch}}. The active touch point id for a [=touch - point=] is the {{GamepadTouch/touchId}} of the earlier + point=] that is [=part of an existing active touch point=] is the {{GamepadTouch/touchId}} of the earlier {{GamepadTouch}}.

+

+
+

+ Output controls +

A [=gamepad=] may have [=haptic actuators=]. A haptic actuator is an output control capable of moving the [=gamepad=] - in a way that can be felt by the user. A haptic effect is - the use of one or more [=haptic actuators=] to provide feedback to the - user. The [=user agent=] is responsible for commanding [=haptic + in a way that can be felt by the user. + A [=haptic actuator=] can be used to generate a haptic effect that provides feedback to the user. + Vibrations from multiple actuators are combined to generate more complex effects. + The [=user agent=] is responsible for commanding [=haptic actuators=] to play and stop [=haptic effects=] on [=available=] [=gamepads=].

@@ -293,6 +329,7 @@

types containing one or more {{GamepadHapticEffectType}} values, which cannot change while the [=gamepad=] is [=available=].

+

From 86f434d26bda8dbd8c515f520bf11dc7a207b9fd Mon Sep 17 00:00:00 2001 From: Matt Reynolds Date: Thu, 8 May 2025 14:13:16 -0700 Subject: [PATCH 3/7] Add a section on input values and define logical values --- index.html | 65 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/index.html b/index.html index 46742c2..e453e4b 100644 --- a/index.html +++ b/index.html @@ -175,7 +175,7 @@

Input control layout

- A [=gamepad=] may have an input control layout that describes the position, orientation and type of each input control on the [=gamepad=]. + A [=gamepad=] may have an input control layout that describes the position, orientation and type of each [=input control=] on the [=gamepad=]. The [=user agent=] is responsible for recognizing when a [=gamepad=] corresponds with a standard layout, meaning the [=gamepad=] has an [=input control layout=] that enables it to be used interchangeably with other [=gamepads=] that correspond with the same standard layout. The [=user agent=] SHOULD consider a layout to correspond with a standard layout if its [=input controls=] have approximately the same relative positions and orientations as [=input controls=] described in the standard layout.

@@ -186,37 +186,42 @@

When there is a standard model and an accessible model with the same [=input controls=], the [=user agent=] SHOULD consider the accessible model to have the same [=input control layout=] as the standard model.

+
+

+ Input values +

+

+ Each input control has one or more associated [=input values=], which are numerical values that represent the current state of the control. + [=Input values=] can update at any time. + The [=user agent=] is responsible for detecting when [=input values=] have updated and SHOULD try to minimize the delay between the update and when the updated values are read. +

+

+ Reading an [=input value=] returns its logical value, an unscaled numerical representation of the current state. + An [=input value=] also has a logical minimum and logical maximum which define the minimum and maximum in-bounds [=logical values=]. +

+

+ An [=input value=] may have an associated HID usage identifier, a 32-bit value that identifies the type of data represented by the input value. + A HID usage does not precisely describe the [=input control layout=], but by convention many [=gamepads=] with similar layouts use similar usages. + The [=user agent=] SHOULD rely on conventions around [=HID usage identifiers=] when deciding the [=input control layout=]. +

+

Axes

- A [=gamepad=] may have [=axis=] inputs. An axis is an input - control with the following [=input values=]: -

-
    -
  • A logical axis value, an integer value that represents - the current displacement of the control from a reference position. -
  • -
  • A minimum axis value, the smallest in-bounds [=logical - axis value=]. -
  • -
  • A maximum axis value, the largest in-bounds [=logical - axis value=]. -
  • -
+ A [=gamepad=] may have [=axis=] inputs. An axis is an [=input value=] that represents the current displacement of the control from a reference position.

A [=gamepad=] has an axis list which is a [=list=] containing all the [=axis=] inputs for the [=gamepad=] in some order determined by the [=user agent=].

- An input control may be designed to automatically return an [=axis=] to - a center position when the user stops interacting with the input - control. If so, the [=axis=] has a preferred axis state. + An [=input control=] may be designed to automatically return an [=axis=] to + a center position when the user stops interacting with the [=input + control=]. If so, the [=axis=] has a preferred axis state. An [=axis=] with a [=preferred axis state=] may also have an additional - [=input value=], the center position value, which is the [=logical axis - value=] when the [=axis=] is centered. + [=input value=], the center position value, which is the [=logical value=] when the [=axis=] is centered.

@@ -225,15 +230,15 @@

A [=gamepad=] may have [=button=] inputs. A button is an - input control that can be pressed to activate. A [=gamepad=] has a + [=input control=] that can be pressed to activate. A [=gamepad=] has a button list which is a [=list=] containing all the [=button=] inputs for the [=gamepad=] in some order determined by the [=user agent=].

- An input control may be designed to automatically return a [=button=] - to an unpressed state when the user stops interacting with the input - control. If so, the [=button=] has a preferred button state. + An [=input control=] may be designed to automatically return a [=button=] + to an unpressed state when the user stops interacting with the [=input + control=]. If so, the [=button=] has a preferred button state.

A [=button=] may have a digital switch to indicate when the [=button=] @@ -244,17 +249,15 @@

A [=button=] may have an analog sensor enabling the [=button=] to report the degree to which the [=button=] is activated. If so, the - [=button=] has these [=input values=]: + [=button=] has:

    -
  • An analog button value, an integer value that represents - the degree of activation. +
  • An analog button value, a [=logical value=] that represents + the degree of activation,
  • -
  • A minimum analog value representing no activation. The - smallest in-bounds [=analog button value=]. +
  • A [=logical minimum=], the [=logical value=] representing no activation, and
  • -
  • A maximum analog value representing full activation. The - largest in-bounds [=analog button value=]. +
  • A [=logical maximum=], the [=logical value=] representing full activation.

From 4336aaa1229ce05ace6244d4b2569e0fe02a6e60 Mon Sep 17 00:00:00 2001 From: Matt Reynolds Date: Sat, 15 Mar 2025 01:41:51 -0700 Subject: [PATCH 4/7] Integrate with WebDriver and WebDriver-BiDi for automation --- index.html | 917 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 914 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index e453e4b..9864e29 100644 --- a/index.html +++ b/index.html @@ -65,7 +65,7 @@ implementationReportURI: "https://wpt.fyi/results/gamepad", caniuse: "gamepad", - xref: ["HTML", "DOM", "PERMISSIONS-POLICY", "HR-TIME", "Infra", "geometry-1"], + xref: ["HTML", "DOM", "PERMISSIONS-POLICY", "HR-TIME", "Infra", "geometry-1", "WebDriver", "WebDriver-BiDi"], }; @@ -1559,6 +1559,8 @@

  • [=Issue a haptic effect=] to the actuator with |type|, |params|, and the |playEffectTimestamp|.
  • +
  • If |this|'s [=gamepad=] is a [=simulated gamepad=], run the steps to [=vibrate a simulated gamepad=] for |this|'s [=gamepad=] with |params|. +
  • When the effect completes, if [=this=].{{GamepadHapticActuator/[[playingEffectPromise]]}} is not `null`, [=queue a global task=] on the [=relevant global @@ -1611,6 +1613,8 @@

  • [=Stop haptic effects=] on [=this=]'s gamepad's actuator.
  • +
  • If [=this=]'s [=gamepad=] is a [=simulated gamepad=], run the steps to [=stop vibration for a simulated gamepad=] for [=this=]'s [=gamepad=]. +
  • If the effect has been successfully stopped, do:
    1. If |effectPromise| and @@ -2453,7 +2457,7 @@

      The gamepadconnected event

      - When a gamepad becomes available on the system, run the following + When a gamepad becomes available on the system, run the following steps:

        @@ -2508,7 +2512,7 @@

        The gamepaddisconnected event

        - When a gamepad becomes unavailable on the system, run the following + When a gamepad becomes unavailable on the system, run the following steps:

          @@ -2604,6 +2608,913 @@

  • +
    +

    + Automation +

    +

    + For the purposes of [=user agent=] automation and application testing, this document defines extensions to the [[WebDriver-BiDi]] expecification. + It is OPTIONAL for a [=user agent=] to support them. +

    +

    + Each [=top-level traversable=] has a simulated gamepad map which is an [=ordered map=] of [=version 4 UUIDs=] to [=simulated gamepads=]. + A simulated gamepad is a software-defined [=gamepad=] that behaves like a physical gamepad and has [=input controls=], [=output controls=], and a [=gamepad identifier string=] +

    +

    + A [=simulated gamepad=] is not a physical device and does not have an [=input control layout=]. + If a [=simulated gamepad=] has device identifiers that match a [=gamepad=] with a known [=input control layout=], the [=user agent=] SHOULD process inputs on the [=simulated gamepad=] as if it had the same [=input control layout=]. +

    +
    +

    + The emulation module +

    +
    +

    + Types +

    +
    +
    + The emulation.GamepadVendorProduct Type +
    +
    +              emulation.GamepadVendorProduct = {
    +                vendor: uint,
    +                product: uint,
    +              }
    +            
    +
    +
    + vendor +
    +
    + is the 16-bit [=vendor identifier=]. +
    +
    + product +
    +
    + is the 16-bit [=product identifier=]. +
    +
    +
    +
    +
    + The emulation.GamepadVibrationEffectType Type +
    +
    +
    + "dual-rumble" +
    +
    + represents the {{GamepadHapticEffectType/"dual-rumble"}} {{GamepadHapticEffectType}}. +
    +
    + "trigger-rumble" +
    +
    + represents the {{GamepadHapticEffectType/"trigger-rumble"}} {{GamepadHapticEffectType}}. +
    +
    +
    +              emulation.GamepadVibrationEffectType = ("dual-rumble", "trigger-rumble")
    +            
    +
    +
    +
    + The emulation.SimulateGamepadParams Type +
    +
    +              emulation.SimulateGamepadParams = {
    +                type: "gamepad",
    +                ? name: text,
    +                ? vendorProduct: emulation.GamepadVendorProduct,
    +                context: browsingContext.BrowsingContext,
    +                axisCount: int,
    +                buttonCount: int,
    +                vibration: [* emulation.GamepadVibrationEffectType]
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"gamepad"`. +
    +
    + context +
    +
    + is the [=browsing context=]. +
    +
    + name +
    +
    + is the [=gamepad identifier string=], or `null` to simulate a device without a string identifier. +
    +
    + vendorProduct +
    +
    + is the [=vendor identifier=] and [=product identifier=], or `null` to simulate a device without these identifiers. +
    +
    + axisCount +
    +
    + is the length of the [=axis list=]. +
    +
    + buttonCount +
    +
    + is the length of the [=button list=]. +
    +
    + vibration +
    +
    + is the [=supported effect types=] for the [=vibration actuator=] +
    +
    +
    +
    +
    + The emulation.RemoveSimulatedGamepadParams Type +
    +
    +              emulation.RemoveSimulatedGamepadParams = {
    +                deviceId: text
    +              }
    +            
    +
    +
    + deviceId +
    +
    + is a random UUID identifying the [=simulated gamepad=]. +
    +
    +
    +
    +
    + The emulation.SimulatedDeviceEventParams Type +
    +
    +              emulation.SimulatedDeviceEventParams = {
    +                type: "gamepadVibration",
    +                deviceId: text,
    +                vibration: bool,
    +                strongMagnitude: (0.0..1.0),
    +                weakMagntiude: (0.0..1.0),
    +                leftTrigger: (0.0..1.0),
    +                rightTrigger: (0.0..1.0),
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"gamepadVibration"`. +
    +
    + deviceId +
    +
    + is a UUID identifying the [=simulated gamepad=]. +
    +
    + vibration +
    +
    + is `true` if the [=simulated gamepad=]'s [=vibration actuator=] is vibrating, or `false` otherwise. +
    +
    + strongMagnitude +
    +
    + is the intensity level for low-frequency vibration. +
    +
    + weakMagnitude +
    +
    + is the intensity level for high-frequency vibration. +
    +
    + leftTrigger +
    +
    + is the intensity level for vibration localized to the bottom left front button. +
    +
    + rightTrigger +
    +
    + is the intensity level for vibration localized to the bottom right front button. +
    +
    +
    +
    +
    +

    + Commands +

    +
    +
    + The emulation.simulateDevice Command +
    +
    +              emulation.SimulateDevice = {
    +                method: "emulation.simulateDevice",
    +                params: emulation.SimulateGamepadParams,
    +              }
    +              Returns: deviceId: text
    +            
    +

    + The [=remote end steps=] with command parameters |params| are: +

    +
      +
    1. + Let |gamepad| be a new [=simulated gamepad=] with the attributes described by |params|: +
        +
      • + |gamepad|'s [=axis list=] is a [=list=] of length |params|.|axisCount|. +
      • +
      • + |gamepad|'s [=button list=] is a [=list=] of length |params|.|buttonCount|. +
      • +
      • + If |params.vibration| [=list/is empty=], |gamepad| has no [=vibration actuator=]. + Otherwise, it has a [=vibration actuator=] with the [=supported effect types=] listed in |params|.|vibration|. +
      • +
      +
    2. +
    3. + Let |simulatedGamepads| be the [=simulated gamepad map=]. +
    4. +
    5. + Let |deviceId:string| be the result of calling [=generate a random UUID=]. +
    6. +
    7. + [=map/Set=] |simulatedGamepads|[|deviceId|] to |gamepad|. +
    8. +
    9. + Run the steps [=when a gamepad becomes available on the system=] for |gamepad|. +
    10. +
    11. + Return |deviceId|. +
    12. +
    +
    +
    +
    + The emulation.removeSimulatedDevice Command +
    +
    +              emulation.RemoveSimulatedDevice = {
    +                method: "emulation.removeSimulatedDevice",
    +                params: emulation.RemoveSimulatedGamepadParams,
    +              }
    +              Returns: void
    +            
    +

    + The [=remote end steps=] with command parameters |params| are: +

    +
      +
    1. + Let |simulatedGamepads| be the [=simulated gamepad map=]. +
    2. +
    3. + If |simulatedGamepads|[|params|.|deviceId|] does not [=map/exist=], abort these steps. +
    4. +
    5. + Let |gamepad| be |simulatedGamepads|[|params|.|deviceId|]. +
    6. +
    7. + Run the steps [=when a gamepad becomes unavailable on the system=] with |gamepad|. +
    8. +
    9. + [=map/Remove=] |simulatedGamepads|[|params|.|deviceId|]. +
    10. +
    +
    +
    +
    +

    + Events +

    +
    +
    + The emulation.simulatedDeviceEvent Event +
    +
    +              emulation.SimulatedDeviceEvent = {
    +                method: "emulation.removeSimulatedDevice",
    +                params: emulation.SimulatedDeviceEventParams,
    +              }
    +            
    +

    + To get the identifier for a simulated gamepad |gamepad|: +

    +
      +
    1. + Let |simulatedGamepads| be the [=simulated gamepad map=]. +
    2. +
    3. + [=map/For each=] |key| → |value| of |simulatedGamepads|: +
        +
      1. + If |value| is |gamepad|, return |key|. +
      2. +
      +
    4. +
    5. + Return `null`. +
    6. +
    +

    + To vibrate a simulated gamepad |gamepad| given a [=navigable=] |navigable| and {{GamepadEffectParameters}} |effectParams|: +

    +
      +
    1. + Let |deviceId:string| be [=the identifier for a simulated gamepad=] |gamepad|. +
    2. +
    3. + If |deviceId| is `null`, abort these steps. +
    4. +
    5. + Let |navigableId| be |navigable|'s [=navigable id=]. +
    6. +
    7. + Let |eventParams| be a [=map=] matching the `emulation.SimulatedDeviceEventParameters` production with the `deviceId` field set to |deviceId|. +
    8. +
    9. + Let |vibration| be `false`. +
    10. +
    11. + Let |channels| be the [=list=] « `"strongMagnitude"`, `"weakMagnitude"`, `"leftTrigger"`, `"rightTrigger"` ». +
    12. +
    13. + [=list/For each=] |channel| of |channels|: +
        +
      1. + If |effectParams|[|channel|] [=map/exists=]: +
          +
        1. + If |effectParams|[|channel|] is greater than 0.0, set |vibration| to `true`. +
        2. +
        3. + [=map/Set=] |eventParams|[|channel|] to |effectParams|[|channel|]. +
        4. +
        +
      2. +
      +
    14. +
    15. + [=map/Set=] |eventParams|[`"vibration"`] to |vibration|. +
    16. +
    17. + Let |body| be a [=map=] matching the `emulation.SimulatedDeviceEvent` production with the `params` field set to |eventParams|. +
    18. +
    19. + Let |relatedNavigables| be a [=set=] containing |navigable|. +
    20. +
    21. + [=set/For each=] |session| in the [=set of sessions for which an event is enabled=] given `"emulation.simulatedDeviceEvent"` and |relatedNavigables|: +
        +
      1. + [=Emit an event=] with |session| and |body|. +
      2. +
      +
    22. +
    +

    + To stop vibration for a simulated gamepad |gamepad| given a [=navigable=] |navigable|: +

    +
      +
    1. + Let |deviceId| be [=the identifier for a simulated gamepad=] |gamepad|. +
    2. +
    3. + If |deviceId| is `null`, abort these steps. +
    4. +
    5. + Let |navigableId| be |navigable|'s [=navigable id=]. +
    6. +
    7. + Let |eventParams| be a [=map=] matching the `emulation.SimulatedDeviceEventParameters` production with the `deviceId` field set to |deviceId| and the `vibration` field set to `false`. +
    8. +
    9. + Let |body| be a [=map=] matching the `emulation.SimulatedDeviceEvent` production with the `params` field set to |eventParams|. +
    10. +
    11. + Let |relatedNavigables| be a [=set=] containing |navigable|. +
    12. +
    13. + [=set/For each=] |session| in the [=set of sessions for which an event is enabled=] given `"emulation.simulatedDeviceEvent"` and |relatedNavigables|: +
        +
      1. + [=Emit an event=] with |session| and |body|. +
      2. +
      +
    14. +
    +
    +
    +
    +
    +

    + The input module +

    +
    +

    + Types +

    +
    +
    + The input.GamepadBounds Type +
    +
    +              input.GamepadBounds = {
    +                min: float64,
    +                max: float64,
    +              }
    +            
    +
    +
    + min +
    +
    + is the [=logical minimum=] for an [=input value=]. +
    +
    + max +
    +
    + is the [=logical maximum=] for an [=input value=]. +
    +
    +
    +
    +
    + The input.GamepadTouchBounds Type +
    +
    +              input.GamepadTouchBounds = {
    +                x: emulation.GamepadBounds,
    +                y: emulation.GamepadBounds,
    +              }
    +            
    +
    +
    + x +
    +
    + is the [=logical minimum=] and [=logical maximum=] for the [=touch x coordinate=]. +
    +
    + y +
    +
    + is the [=logical minimum=] and [=logical maximum=] for the [=touch y coordinate=]. +
    +
    +
    +
    +
    + The input.GamepadTouchValue Type +
    +
    +              input.GamepadTouchValue = {
    +                x: float64,
    +                y: float64,
    +                ? bounds: input.GamepadTouchBounds,
    +              }
    +            
    +
    +
    + x +
    +
    + is the [=logical value=] for the [=touch x coordinate=]. +
    +
    + y +
    +
    + is the [=logical value=] for the [=touch y coordinate=]. +
    +
    + bounds +
    +
    + is the logical bounds for the [=touch x coordinate=] and [=touch y coordinate=], or `null` to skip normalization and simulate no dimension values for this [=touch surface=]. +
    +
    +
    +
    +
    +

    + Actions +

    +

    + A gamepad input source is an [=input source=] that is associated with a [=gamepad=]-like device. +

    +

    + A [=gamepad input source=] has the following items: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Item + + Non-normative Description + + Default Value +
    + name + + An optional [=string=] identifying the style or model of gamepad. + +
    + vendorProduct + + An optional `emulation.GamepadVendorProduct` containing the vendor and product identifiers. + +
    + axisCount + + The number of [=axis=] inputs. + +
    + buttonCount + + The number of [=button=] inputs. + +
    + vibration + + A [=set=] of `emulation.GamepadVibrationEffectType` containing supported vibration efffect types. + + Empty [=set=] +
    + pendingAxisInputs + + A [=map=] of [=axis=] indices to updated [=axis=] [=input values=]. + + Empty [=map=] +
    + pendingButtonInputs + + A [=map=] of [=button=] indices to updated [=button=] [=input values=]. + + Empty [=map=] +
    + activeTouches + + A [=list=] containing all the [=touch points=] on the [=active touch point list=] for each [=touch surface=]. + + Empty [=list=] +
    +

    + A [=gamepad input source=] supports the same [=pause=] action as a [=null input source=] plus the following actions: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Actiom + + Non-normative Description +
    + gamepadAxisInput + + Used to indicate that the [=input value=] for an [=axis=] has updated. +
    + gamepadButtonInput + + Used to indicate that the [=input values=] for a [=button=] have updated. +
    + gamepadTouchStart + + Used to indicate that there is a new [=touch point=] on a [=touch surface=]. +
    + gamepadTouchMove + + Used to indicate that an active [=touch point=] has updated coordinates. +
    + gamepadTouchEnd + + Used to indicate that a [=touch point=] is no longer active. +
    + gamepadFlushAction + + Used to indicate that the [=gamepad=] has updated [=input values=]. +
    +

    + To create a gamepad input source object given `emulation.SimulateGamepadParams` |params|, return a new [=gamepad input source=] with: +

    +
      +
    • + `name` set to |params|.|name|, +
    • +
    • + `vendorProduct` set to |params|.|vendorProduct|, +
    • +
    • + `axisCount` set to |params|.|axisCount|, +
    • +
    • + `buttonCount` set to |params|.|buttonCount|, and +
    • +
    • + `vibration` set to |params|.|vibration|. +
    • +
    +
    +            input.GamepadInputCommonProperties = (
    +              value: float64,
    +              ? bounds: emulation.GamepadBounds,
    +            )
    +          
    +
    +
    + value +
    +
    + is the [=logical value=] for an [=input value=]. +
    +
    + bounds +
    +
    + is the logical bounds for the [=input value=], or `null` to skip normalization. +
    +
    +
    +            input.GamepadTouchCommonProperties = (
    +              touchId: text,
    +            )
    +          
    +
    +
    + touchId +
    +
    + is the identifier for a simulated [=touch point=]. +
    +
    +
    +            input.GamepadSourceAction = (
    +              input.PauseAction /
    +              input.GamepadAxisInput /
    +              input.GamepadButtonInput /
    +              input.GamepadTouchStartAction /
    +              input.GamepadTouchMoveAction /
    +              input.GamepadTouchEndAction /
    +              input.GamepadFlushAction
    +            )
    +
    +            input.GamepadSourceActions = {
    +              type: "gamepad",
    +              deviceId: text,
    +              actions: [* input.GamepadSourceAction],
    +            }
    +          
    +
    +
    + type +
    +
    + must be `"gamepad"`. +
    +
    + deviceId +
    +
    + is a UUID string identifying a [=simulated gamepad=]. +
    +
    + actions +
    +
    + is a [=list=] of actions representing the [=simulated gamepad=]'s updated [=input values=]. +
    +
    +
    +
    + The input.GamepadAxisInput Action +
    +
    +              input.GamepadAxisInput = {
    +                type: "axis",
    +                axisIndex: uint,
    +                input.GamepadInputCommonProperties,
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"axis"`. +
    +
    + axisIndex +
    +
    + is the index of the updated [=axis=] in the [=axis list=]. +
    +
    +
    +
    +
    + The input.GamepadButtonInput Action +
    +
    +              input.GamepadButtonInput = {
    +                type: "button",
    +                buttonIndex: uint,
    +                input.GamepadInputValueCommonProperties,
    +                ? pressed: bool,
    +                ? touched: bool,
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"button"`. +
    +
    + buttonIndex +
    +
    + is the index of the updated [=button=] in the [=button list=]. +
    +
    +
    +
    +
    + The input.GamepadTouchStartAction Action +
    +
    +              input.GamepadTouchStartAction = {
    +                type: "touchStart",
    +                surfaceId: uint,
    +                input.GamepadTouchCommonProperties,
    +                input.GamepadTouchValue,
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"touchStart"`. +
    +
    + surfaceId +
    +
    + is the {{GamepadTouch/surfaceId}} of the [=touch surface=] containing the simulated [=touch point=]. +
    +
    +
    +
    +
    + The input.GamepadTouchMoveAction Action +
    +
    +              input.GamepadTouchMoveAction = {
    +                type: "touchMove",
    +                input.GamepadTouchCommonProperties,
    +                input.GamepadTouchValue,
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"touchMove"`. +
    +
    +
    +
    +
    + The input.GamepadTouchEndAction Action +
    +
    +              input.GamepadTouchEndAction = {
    +                type: "touchEnd",
    +                input.GamepadTouchCommonProperties,
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"touchEnd"`. +
    +
    +
    +
    +
    + The input.GamepadFlushAction Action +
    +
    +              input.GamepadFlushAction = {
    +                type: "flush",
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"flush"`. +
    +
    +
    +
    +
    +
    From 0d8f530dc9f1a927d4e6ce7453a16103ef985a8b Mon Sep 17 00:00:00 2001 From: Matt Reynolds Date: Thu, 10 Jul 2025 14:58:20 -0700 Subject: [PATCH 5/7] Align with Gamepad API testing doc Update webdriver CDDL type definitions. Move all bounds information into SimulateGamepadParams. Remove vendor/product/name parameters. Remove "flush" action and move its functionality to "pause". Add steps for processing and dispatching actions. --- index.html | 1164 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 851 insertions(+), 313 deletions(-) diff --git a/index.html b/index.html index 9864e29..390a232 100644 --- a/index.html +++ b/index.html @@ -65,11 +65,11 @@ implementationReportURI: "https://wpt.fyi/results/gamepad", caniuse: "gamepad", - xref: ["HTML", "DOM", "PERMISSIONS-POLICY", "HR-TIME", "Infra", "geometry-1", "WebDriver", "WebDriver-BiDi"], + xref: ["ecmascript", "HTML", "DOM", "PERMISSIONS-POLICY", "HR-TIME", "Infra", "geometry-1", "webcrypto", "WebDriver", "WebDriver-BiDi", "RFC4122"], }; - +

    The Gamepad specification defines a low-level interface that represents @@ -741,11 +741,21 @@

  • Set |gamepad|.{{Gamepad/[[timestamp]]}} to |now|.
  • -
  • Run the steps to [=map and normalize axes=] for |gamepad|. -
  • -
  • Run the steps to [=map and normalize buttons=] for |gamepad|. -
  • -
  • Run the steps to [=record touches=] for |gamepad|. +
  • +

    + If the [=gamepad=] represented by |gamepad| is a [=simulated gamepad=], run the steps to [=update simulated gamepad state=] for |gamepad|. +

    +

    + Otherwise: +

    +
      +
    1. Run the steps to [=map and normalize axes=] for |gamepad|. +
    2. +
    3. Run the steps to [=map and normalize buttons=] for |gamepad|. +
    4. +
    5. Run the steps to [=record touches=] for |gamepad|. +
    6. +
  • Let |navigator:Navigator| be |gamepad|'s [=relevant global object=]'s {{Navigator}} object. @@ -785,6 +795,16 @@

  • +

    + To normalize a logical axis value given |value|, |minimum|, and |maximum|: +

    +
      +
    1. + Return 2 (|value| − |minimum|) / (|maximum| − |minimum|) − 1. +
    2. +
    3. +
    4. +

    To map and normalize axes for |gamepad:Gamepad|, run the following steps: @@ -812,8 +832,7 @@

  • Let |logicalMaximum:unsigned long| be |gamepad|.{{Gamepad/[[axisMaximums]]}}[|rawAxisIndex|].
  • -
  • Let |normalizedValue:double| be 2 (|logicalValue| − - |logicalMinimum|) / (|logicalMaximum| − |logicalMinimum|) − 1. +
  • Let |normalizedValue:double| be the result of [=normalize a logical axis value=] with |logicalValue|, |logicalMinimum|, and |logicalMaximum|.
  • Set |gamepad|.{{Gamepad/[[axes]]}}[|axisIndex|] to be |normalizedValue|. @@ -821,6 +840,14 @@

  • +

    + To normalize a logical button value given |value|, |minimum|, and |maximum|: +

    +
      +
    1. + Return (|logicalValue| − |logicalMinimum|) / (|logicalMaximum| − |logicalMinimum|). +
    2. +

    To map and normalize buttons for |gamepad:Gamepad|, run the following steps: @@ -848,8 +875,7 @@

  • Let |logicalMaximum:unsigned long| be |gamepad|.{{Gamepad/[[buttonMaximums]]}}[|rawButtonIndex|].
  • -
  • Let |normalizedValue:double| be (|logicalValue| − - |logicalMinimum|) / (|logicalMaximum| − |logicalMinimum|). +
  • Let |normalizedValue:double| be the result of [=normalize a logical button value=] with |logicalValue|, |logicalMinimum|, and |logicalMaximum|.
  • Let |button:GamepadButton| be |gamepad|.{{Gamepad/[[buttons]]}}[|mappedIndex|]. @@ -1515,7 +1541,7 @@

    {{GamepadEffectParameters}} |params:GamepadEffectParameters |, are:

      -
    1. If |params:GamepadEffectParameters| does not describe a [=valid +
    2. If |params:GamepadEffectParameters| does not describe a [=valid effect=] of type |type:GamepadHapticEffectType|, return [=a promise rejected with=] a {{TypeError}}.
    3. @@ -2617,8 +2643,10 @@

      It is OPTIONAL for a [=user agent=] to support them.

      - Each [=top-level traversable=] has a simulated gamepad map which is an [=ordered map=] of [=version 4 UUIDs=] to [=simulated gamepads=]. - A simulated gamepad is a software-defined [=gamepad=] that behaves like a physical gamepad and has [=input controls=], [=output controls=], and a [=gamepad identifier string=] + Each [=top-level traversable=] has a simulated gamepad map which is an [=ordered map=] of [=version 4 UUIDs=] to [=gamepad input sources=]. +

      +

      + A simulated gamepad is a software-defined [=gamepad=] that behaves like a physical gamepad and has [=input controls=], [=output controls=], and a [=gamepad identifier string=].

      A [=simulated gamepad=] is not a physical device and does not have an [=input control layout=]. @@ -2634,26 +2662,51 @@

      - The emulation.GamepadVendorProduct Type + The emulation.GamepadBounds Type +
      +
      +              emulation.GamepadBounds = {
      +                max: float64,
      +                ? min: float64,
      +              }
      +            
      +
      +
      + max +
      +
      + is the [=logical maximum=] for an [=input value=]. +
      +
      + min +
      +
      + is the [=logical minimum=] for an [=input value=]. +
      +
      +
      +
      +
      + The emulation.SurfaceBounds Type
      -              emulation.GamepadVendorProduct = {
      -                vendor: uint,
      -                product: uint,
      +              emulation.SurfaceBounds = {
      +                x: emulation.GamepadBounds,
      +                y: emulation.GamepadBounds,
                     }
                   
      - vendor + x
      - is the 16-bit [=vendor identifier=]. + is the logical bounds for the [=touch x coordinate=].
      - product + y
      - is the 16-bit [=product identifier=]. + is the logical bounds for the [=touch y coordinate=].
      @@ -2686,12 +2739,11 @@
                     emulation.SimulateGamepadParams = {
                       type: "gamepad",
      -                ? name: text,
      -                ? vendorProduct: emulation.GamepadVendorProduct,
                       context: browsingContext.BrowsingContext,
      -                axisCount: int,
      -                buttonCount: int,
      -                vibration: [* emulation.GamepadVibrationEffectType]
      +                ? axes: [* emulation.GamepadBounds],
      +                ? buttons: [* emulation.GamepadBounds],
      +                ? surfaces: [* emulation.SurfaceBounds],
      +                ? vibration: [* emulation.GamepadVibrationEffectType]
                     }
                   
      @@ -2708,43 +2760,37 @@
      is the [=browsing context=].
      - name -
      -
      - is the [=gamepad identifier string=], or `null` to simulate a device without a string identifier. -
      -
      - vendorProduct + axes
      - is the [=vendor identifier=] and [=product identifier=], or `null` to simulate a device without these identifiers. + is the logical bounds for each [=axis=].
      - axisCount + buttons
      - is the length of the [=axis list=]. + is the logical bounds for each [=button=].
      - buttonCount + surfaces
      - is the length of the [=button list=]. + is the logical bounds for each [=touch surface=].
      vibration
      - is the [=supported effect types=] for the [=vibration actuator=] + is the [=supported effect types=] for the [=vibration actuator=].

  • - The emulation.RemoveSimulatedGamepadParams Type + The emulation.RemoveSimulatedDeviceParams Type
    -              emulation.RemoveSimulatedGamepadParams = {
    +              emulation.RemoveSimulatedDeviceParams = {
                     deviceId: text
                   }
                 
    @@ -2753,7 +2799,7 @@
    deviceId
    - is a random UUID identifying the [=simulated gamepad=]. + is a random [=version 4 UUID=] identifying the [=simulated gamepad=].
    @@ -2783,7 +2829,7 @@
    deviceId
    - is a UUID identifying the [=simulated gamepad=]. + is a [=version 4 UUID=] identifying the [=simulated gamepad=].
    vibration @@ -2838,19 +2884,7 @@

    1. - Let |gamepad| be a new [=simulated gamepad=] with the attributes described by |params|: -
        -
      • - |gamepad|'s [=axis list=] is a [=list=] of length |params|.|axisCount|. -
      • -
      • - |gamepad|'s [=button list=] is a [=list=] of length |params|.|buttonCount|. -
      • -
      • - If |params.vibration| [=list/is empty=], |gamepad| has no [=vibration actuator=]. - Otherwise, it has a [=vibration actuator=] with the [=supported effect types=] listed in |params|.|vibration|. -
      • -
      + Let |source| be the result of [=create a gamepad input source=] with |params|.
    2. Let |simulatedGamepads| be the [=simulated gamepad map=]. @@ -2859,7 +2893,7 @@
      Let |deviceId:string| be the result of calling [=generate a random UUID=].
    3. - [=map/Set=] |simulatedGamepads|[|deviceId|] to |gamepad|. + [=map/Set=] |simulatedGamepads|[|deviceId|] to |source|.
    4. Run the steps [=when a gamepad becomes available on the system=] for |gamepad|. @@ -2876,7 +2910,7 @@
                     emulation.RemoveSimulatedDevice = {
                       method: "emulation.removeSimulatedDevice",
      -                params: emulation.RemoveSimulatedGamepadParams,
      +                params: emulation.RemoveSimulatedDeviceParams,
                     }
                     Returns: void
                   
      @@ -2902,7 +2936,7 @@
    -
    +

    Events

    @@ -3029,96 +3063,9 @@

    The input module

    -
    -

    - Types -

    -
    -
    - The input.GamepadBounds Type -
    -
    -              input.GamepadBounds = {
    -                min: float64,
    -                max: float64,
    -              }
    -            
    -
    -
    - min -
    -
    - is the [=logical minimum=] for an [=input value=]. -
    -
    - max -
    -
    - is the [=logical maximum=] for an [=input value=]. -
    -
    -
    -
    -
    - The input.GamepadTouchBounds Type -
    -
    -              input.GamepadTouchBounds = {
    -                x: emulation.GamepadBounds,
    -                y: emulation.GamepadBounds,
    -              }
    -            
    -
    -
    - x -
    -
    - is the [=logical minimum=] and [=logical maximum=] for the [=touch x coordinate=]. -
    -
    - y -
    -
    - is the [=logical minimum=] and [=logical maximum=] for the [=touch y coordinate=]. -
    -
    -
    -
    -
    - The input.GamepadTouchValue Type -
    -
    -              input.GamepadTouchValue = {
    -                x: float64,
    -                y: float64,
    -                ? bounds: input.GamepadTouchBounds,
    -              }
    -            
    -
    -
    - x -
    -
    - is the [=logical value=] for the [=touch x coordinate=]. -
    -
    - y -
    -
    - is the [=logical value=] for the [=touch y coordinate=]. -
    -
    - bounds -
    -
    - is the logical bounds for the [=touch x coordinate=] and [=touch y coordinate=], or `null` to skip normalization and simulate no dimension values for this [=touch surface=]. -
    -
    -
    -
    -
    +

    - Actions + Gamepad Input Source

    A gamepad input source is an [=input source=] that is associated with a [=gamepad=]-like device. @@ -3140,40 +3087,30 @@

    - name - - - An optional [=string=] identifying the style or model of gamepad. - - - - - - - vendorProduct + axes - An optional `emulation.GamepadVendorProduct` containing the vendor and product identifiers. + The logical bounds for each [=axis=] input. - axisCount + buttons - The number of [=axis=] inputs. + The logical bounds for each [=button=] input. - buttonCount + surfaces - The number of [=button=] inputs. + The logical bounds for each [=touch surface=]. @@ -3229,7 +3166,7 @@

    - - - -
    - Actiom + Action Non-normative Description @@ -3237,7 +3174,7 @@

    - gamepadAxisInput + GamepadAxisInput Used to indicate that the [=input value=] for an [=axis=] has updated. @@ -3245,7 +3182,7 @@

    - gamepadButtonInput + GamepadButtonInput Used to indicate that the [=input values=] for a [=button=] have updated. @@ -3253,7 +3190,7 @@

    - gamepadTouchStart + GamepadTouchStartAction Used to indicate that there is a new [=touch point=] on a [=touch surface=]. @@ -3261,7 +3198,7 @@

    - gamepadTouchMove + GamepadTouchMoveAction Used to indicate that an active [=touch point=] has updated coordinates. @@ -3269,148 +3206,352 @@

    - gamepadTouchEnd + GamepadTouchEndAction Used to indicate that a [=touch point=] is no longer active.
    - gamepadFlushAction - - Used to indicate that the [=gamepad=] has updated [=input values=]. -

    - To create a gamepad input source object given `emulation.SimulateGamepadParams` |params|, return a new [=gamepad input source=] with: + To create a gamepad input source object given |params|, return a new [=gamepad input source=] with:

    • - `name` set to |params|.|name|, + `axes` set to |params|.axes,
    • - `vendorProduct` set to |params|.|vendorProduct|, + `buttons` set to |params|.buttons,
    • - `axisCount` set to |params|.|axisCount|, + `surfaces` set to |params|.surfaces, and
    • - `buttonCount` set to |params|.|buttonCount|, and + `vibration` set to |params|.vibration.
    • +
    +

    +
    +

    + Actions +

    +

    + To process a gamepad action given |id| and |action item|: +

    +
    1. - `vibration` set to |params|.|vibration|. + Let |subtype| be the result of getting the property named "type" from |action item|.
    2. - -
      -            input.GamepadInputCommonProperties = (
      -              value: float64,
      -              ? bounds: emulation.GamepadBounds,
      -            )
      -          
      -
      -
      - value -
      -
      - is the [=logical value=] for an [=input value=]. -
      -
      - bounds -
      -
      - is the logical bounds for the [=input value=], or `null` to skip normalization. -
      -
      -
      -            input.GamepadTouchCommonProperties = (
      -              touchId: text,
      -            )
      -          
      -
      -
      - touchId -
      -
      - is the identifier for a simulated [=touch point=]. -
      -
      -
      -            input.GamepadSourceAction = (
      -              input.PauseAction /
      -              input.GamepadAxisInput /
      -              input.GamepadButtonInput /
      -              input.GamepadTouchStartAction /
      -              input.GamepadTouchMoveAction /
      -              input.GamepadTouchEndAction /
      -              input.GamepadFlushAction
      -            )
      -
      -            input.GamepadSourceActions = {
      -              type: "gamepad",
      -              deviceId: text,
      -              actions: [* input.GamepadSourceAction],
      -            }
      -          
      -
      -
      - type -
      -
      - must be `"gamepad"`. -
      -
      - deviceId -
      -
      - is a UUID string identifying a [=simulated gamepad=]. -
      -
      - actions -
      -
      - is a [=list=] of actions representing the [=simulated gamepad=]'s updated [=input values=]. -
      -
      -
      -
      - The input.GamepadAxisInput Action -
      -
      -              input.GamepadAxisInput = {
      -                type: "axis",
      -                axisIndex: uint,
      -                input.GamepadInputCommonProperties,
      -              }
      -            
      -
      -
      - type -
      -
      - must be `"axis"`. -
      -
      - axisIndex -
      -
      - is the index of the updated [=axis=] in the [=axis list=]. -
      -
      -
      -
      -
      - The input.GamepadButtonInput Action -
      -
      -              input.GamepadButtonInput = {
      -                type: "button",
      -                buttonIndex: uint,
      -                input.GamepadInputValueCommonProperties,
      -                ? pressed: bool,
      -                ? touched: bool,
      +            
    3. + If |subtype| is not one of the values `"axis"`, `"button"`, `"touchStart"`, `"touchMove"`, `"touchEnd"`, or `"pause"`, return an [=error=] with [=error code=] [=invalid argument=]. +
    4. +
    5. + Let |action| be an [=action object=] constructed with arguments |id|, `"gamepad"`, and |subtype|. +
    6. +
    7. + If |subtype| is `"pause"`, let |result| be the result of [=trying=] to [=process a pause action=] with arguments |action item| and |action|, and return |result|. +
    8. +
    9. + If |subtype| is `"axis"`, let |result| be the result of [=trying=] to [=process a gamepad axis input action=] with arguments |action item| and |action|, and return |result|. +
    10. +
    11. + If |subtype| is `"button"`, let |result| be the result of [=trying=] to [=process a gamepad button input action=] with arguments |action item| and |action|, and return |result|. +
    12. +
    13. + If |subtype| is `"touchStart"`, let |result| be the result of [=trying=] to [=process a gamepad touch start action=] with arguments |action item| and |action|, and return |result|. +
    14. +
    15. + If |subtype| is `"touchMove"`, let |result| be the result of [=trying=] to [=process a gamepad touch move action=] with arguments |action item| and |action|, and return |result|. +
    16. +
    17. + If |subtype| is `"touchEnd"`, let |result| be the result of [=trying=] to [=process a gamepad touch end action=] with arguments |action item| and |action|, and return |result|. +
    18. +
    19. + Return [=success=] with data |action|. +
    20. +
    +

    + To process the logical input value given |action item| and |action|: +

    +
      +
    1. + Let |value| be the result of getting the property named `"value"` from |action item|. +
    2. +
    3. + If |value| is not a {{Number}}, return [=error=] with [=error code=] [=invalid argument=]. +
    4. +
    5. + Set the `value` property of |action| to |value|. +
    6. +
    +

    + To process a gamepad axis input action given |action item| and |action|: +

    +
      +
    1. + Let |axisIndex| be the result of getting the property named `"axisIndex"` from |action item|. +
    2. +
    3. + If |axisIndex| is not an integer greater than or equal to 0, return [=error=] with [=error code=] [=invalid argument=]. +
    4. +
    5. + Set the `axisIndex` property of |action| to |axisIndex|. +
    6. +
    7. + [=Process the logical input value=] with |action item| and |action|. +
    8. +
    9. + Return [=success=] with data |action|. +
    10. +
    +

    + To process a gamepad button input action given |action item| and |action|: +

    +
      +
    1. + Let |buttonIndex| be the result of getting the property named `"buttonIndex"` from |action item|. +
    2. +
    3. + If |buttonIndex| is not an integer greater than or equal to 0, return [=error=] with [=error code=] [=invalid argument=]. +
    4. +
    5. + Set the `buttonIndex` property of |action| to |buttonIndex|. +
    6. +
    7. + [=Process the logical input value=] with |action item| and |action|. +
    8. +
    9. + Let |pressed| be the result of getting the property named `"pressed"` from |action item|. +
    10. +
    11. + If |pressed| is not a {{Boolean}} or `undefined`, return [=error=] with [=error code=] [=invalid argument=]. +
    12. +
    13. + Set the `pressed` property of |action| to |pressed|. +
    14. +
    15. + Let |touched| be the result of getting the property named `"touched"` from |action item|. +
    16. +
    17. + If |touched| is not a {{Boolean}} or `undefined`, return [=error=] with [=error code=] [=invalid argument=]. +
    18. +
    19. + Set the `touched` property of |action| to |touched|. +
    20. +
    21. + Return [=success=] with data |action|. +
    22. +
    +

    + To process touch id given |action item| and |action|: +

    +
      +
    1. + Let |touchId| be the result of getting the property named `"touchId"` from |action item|. +
    2. +
    3. + If |touchId| is not a {{String}}, return [=error=] with [=error code=] [=invalid argument=]. +
    4. +
    5. + Set the `touchId` property of |action| to |touchId|. +
    6. +
    +

    + To process touch values given |action item| and |action|: +

    +
      +
    1. + Let |x| be the result of getting the property named `"x"` from |action item|. +
    2. +
    3. + If |x| is not a {{Number}}, return [=error=] with [=error code=] [=invalid argument=]. +
    4. +
    5. + Set the `x` property of |action| to |x|. +
    6. +
    7. + Let |y| be the result of getting the property named `"y"` from |action item|. +
    8. +
    9. + If |y| is not a {{Number}}, return [=error=] with [=error code=] [=invalid argument=]. +
    10. +
    11. + Set the `y` property of |action| to |y|. +
    12. +
    +

    + To process a gamepad touch start action given |action item| and |action|: +

    +
      +
    1. + Let |surfaceId| be the result of getting the property named `"surfaceId"` from |action item|. +
    2. +
    3. + If |surfaceId| is not a {{Number}} greater than or equal to 0, return [=error=] with [=error code=] [=invalid argument=]. +
    4. +
    5. + Set the `surfaceId` property of |action| to |surfaceId|. +
    6. +
    7. + [=Process touch id=] given |action item| and |action|. +
    8. +
    9. + [=Process touch values=] with |action item| and |action|. +
    10. +
    11. + Return [=success=] with data |action|. +
    12. +
    +

    + To process a gamepad touch move action given |action item| and |action|: +

    +
      +
    1. + [=Process touch id=] given |action item| and |action|. +
    2. +
    3. + [=Process touch values=] with |action item| and |action|. +
    4. +
    5. + Return [=success=] with data |action|. +
    6. +
    +

    + To process a gamepad touch end action given |action item| and |action|: +

    +
      +
    1. + [=Process touch id=] given |action item| and |action|. +
    2. +
    3. + Return [=success=] with data |action|. +
    4. +
    +
    +            input.GamepadValueProperties = (
    +              value: float64,
    +            )
    +          
    +
    +
    + value +
    +
    + is the [=logical value=] for an [=input value=]. +
    +
    +
    +            input.GamepadTouchCommonProperties = (
    +              touchId: text,
    +            )
    +          
    +
    +
    + touchId +
    +
    + is the identifier for a simulated [=touch point=]. +
    +
    +
    +            input.GamepadTouchValueProperties = (
    +              x: float64,
    +              y: float64,
    +            )
    +          
    +
    +
    + x +
    +
    + is the [=logical value=] for the [=touch x coordinate=]. +
    +
    + y +
    +
    + is the [=logical value=] for the [=touch y coordinate=]. +
    +
    +
    +            input.GamepadSourceAction = (
    +              input.PauseAction /
    +              input.GamepadAxisInput /
    +              input.GamepadButtonInput /
    +              input.GamepadTouchStartAction /
    +              input.GamepadTouchMoveAction /
    +              input.GamepadTouchEndAction
    +            )
    +
    +            input.GamepadSourceActions = {
    +              type: "gamepad",
    +              deviceId: text,
    +              actions: [* input.GamepadSourceAction],
    +            }
    +          
    +
    +
    + type +
    +
    + must be `"gamepad"`. +
    +
    + deviceId +
    +
    + is a [=version 4 UUID=] identifying a [=simulated gamepad=]. +
    +
    + actions +
    +
    + is a [=list=] of actions representing the [=simulated gamepad=]'s updated [=input values=]. +
    +
    +
    +
    + The input.GamepadAxisInput Action +
    +
    +              input.GamepadAxisInput = {
    +                type: "axis",
    +                axisIndex: uint,
    +                value: float64,
    +              }
    +            
    +
    +
    + type +
    +
    + must be `"axis"`. +
    +
    + axisIndex +
    +
    + is the index of the updated [=axis=] in the [=axis list=]. +
    +
    + value +
    +
    + is the updated [=logical value=]. +
    +
    +
    +
    +
    + The input.GamepadButtonInput Action +
    +
    +              input.GamepadButtonInput = {
    +                type: "button",
    +                buttonIndex: uint,
    +                value: float64,
    +                ? pressed: bool,
    +                ? touched: bool,
                   }
                 
    @@ -3426,6 +3567,12 @@
    is the index of the updated [=button=] in the [=button list=].
    +
    + value +
    +
    + is the updated [=logical value=]. +
    @@ -3437,7 +3584,7 @@
    type: "touchStart", surfaceId: uint, input.GamepadTouchCommonProperties, - input.GamepadTouchValue, + input.GamepadTouchValueProperties, }
    @@ -3463,7 +3610,7 @@
    input.GamepadTouchMoveAction = { type: "touchMove", input.GamepadTouchCommonProperties, - input.GamepadTouchValue, + input.GamepadTouchValueProperties, }
    @@ -3494,24 +3641,415 @@
    -
    -
    - The input.GamepadFlushAction Action -
    -
    -              input.GamepadFlushAction = {
    -                type: "flush",
    -              }
    -            
    -
    -
    - type -
    -
    - must be `"flush"`. -
    -
    -
    +

    + Extend the dispatch action algorithm table in [=dispatch tick actions=] with the following table: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + source type + + subtype + + Dispatch action algorithm +
    + `"gamepad"` + + `"axis"` + + [=Dispatch a gamepad axis action=] +
    + `"gamepad"` + + `"button"` + + [=Dispatch a gamepad button action=] +
    + `"gamepad"` + + `"touchStart"` + + [=Dispatch a gamepad touch start action=] +
    + `"gamepad"` + + `"touchMove"` + + [=Dispatch a gamepad touch move action=] +
    + `"gamepad"` + + `"touchEnd"` + + [=Dispatch a gamepad touch end action=] +
    + `"gamepad"` + + `"pause"` + + [=Dispatch a gamepad pause action=] +
    +

    + To normalize a simulated input value given |logical value| and |bounds|: +

    +
      +
    1. + Let |logical minimum| be equal to |bounds|'s `min` property. +
    2. +
    3. + If |logical minimum| is `undefined`, set |logical minimum| to 0. +
    4. +
    5. + Let |logical maximum| be equal to |bounds|'s `max` property. +
    6. +
    7. + Return the result of [=normalize a logical axis value=] with |logical value|, |logical minimum|, and |logical maximum|. +
    8. +
    +

    + To dispatch a gamepad axis action given |action object|, |source|, |global key state|, |tick duration|, |browsing context|, and |actions options|: +

    +
      +
    1. + Let |device id| be equal to |action object|'s `deviceId` property. +
    2. +
    3. + Let |axis index| be equal to |action object|'s `axisIndex` property. +
    4. +
    5. + Let |logical value| be equal to |action object|'s `value` property. +
    6. +
    7. + Let |axes| be equal to |source|'s axes. +
    8. +
    9. + Let |bounds| be equal to |axes|[|axis index|]. +
    10. +
    11. + If |bounds| is `undefined`, return [=success=] with data `null`. +
    12. +
    13. + Let |simulated gamepads| be the [=simulated gamepad map=]. +
    14. +
    15. + If |simulated gamepads|[|device id|] does not [=map/exist=], abort these steps. +
    16. +
    17. + Let |pending axis inputs| be |source|'s pendingAxisInputs. +
    18. +
    19. + Set |pending axis inputs|[|axis index|] to the result of [=normalize a simulated input value=] given |logical value| and |bounds|. +
    20. +
    21. + Return [=success=] with data `null`. +
    22. +
    +

    + To dispatch a gamepad button action given |action object|, |source|, |global key state|, |tick duration|, |browsing context|, and |actions options|: +

    +
      +
    1. + Let |device id| be equal to |action object|'s `deviceId` property. +
    2. +
    3. + Let |button index| be equal to |action object|'s `buttonIndex` property. +
    4. +
    5. + Let |logical value| be equal to |action object|'s `value` property. +
    6. +
    7. + Let |pressed| be equal to |action object|'s `pressed` property. +
    8. +
    9. + Let |touched| be equal to |action object|'s `touched` property. +
    10. +
    11. + Let |buttons| be equal to |source|'s buttons. +
    12. +
    13. + Let |bounds| be equal to |buttons|[|button index|]. +
    14. +
    15. + If |bounds| is `undefined`, return [=success=] with data `null`. +
    16. +
    17. + Let |pending button inputs| be |source|'s pendingButtonInputs. +
    18. +
    19. + Set |pending button inputs|[|button index|].value to the result of [=normalize a simulated input value=] given |logical value| and |bounds|. +
    20. +
    21. + Set |pending button inputs|[|button index|].value to |pressed|. +
    22. +
    23. + Set |pending button inputs|[|button index|].value to |touched|. +
    24. +
    25. + Return [=success=] with data `null`. +
    26. +
    +

    + To compute the surface dimension given |bounds|: +

    +
      +
    1. + Let |logical minimum| be equal to |bounds|'s `min` property. +
    2. +
    3. + If |logical minimum| is `undefined`, set |logical minimum| to 0. +
    4. +
    5. + Let |logical maximum| be equal to |bounds|'s `max` property. +
    6. +
    7. + Return |logical maximum| - |logical minimum|. +
    8. +
    +

    + To dispatch a gamepad touch start action given |action object|, |source|, |global key state|, |tick duration|, |browsing context|, and |actions options|: +

    +
      +
    1. + Let |device id| be equal to |action object|'s `deviceId` property. +
    2. +
    3. + Let |surface id| be equal to |action object|'s `surfaceId` property. +
    4. +
    5. + Let |touch id| be equal to |action object|'s `touchId` property. +
    6. +
    7. + Let |x logical value| be equal to |action object|'s `x` property. +
    8. +
    9. + Let |y logical value| be equal to |action object|'s `y` property. +
    10. +
    11. + Let |surfaces| be |source|'s surfaces. +
    12. +
    13. + Let |bounds| be |surfaces|[|surface id|]. +
    14. +
    15. + If |bounds| is `undefined`, return [=success=] with data `null`. +
    16. +
    17. + Let |x bounds| be equal to |bounds|'s `x` property. +
    18. +
    19. + Let |y bounds| be equal to |bounds|'s `y` property. +
    20. +
    21. + Let |touch| be a new {{Object}}. +
    22. +
    23. + Set |touch|.surfaceId to |surface id|. +
    24. +
    25. + Set |touch|.touchId to |touch id|. +
    26. +
    27. + Set |touch|.x to the result of [=normalize a simulated input value=] given |x logical value| and |x bounds|. +
    28. +
    29. + Set |touch|.y to the result of [=normalize a simulated input value=] given |y logical value| and |y bounds|. +
    30. +
    31. + Set |touch|.width to the result of [=compute the surface dimension=] given |x bounds|. +
    32. +
    33. + Set |touch|.height to the result of [=compute the surface dimension=] given |y bounds|. +
    34. +
    35. + Let |active touches| be |source|'s activeTouches. +
    36. +
    37. + [=list/Append=] |touch| to |active touches|. +
    38. +
    39. + Return [=success=] with data `null`. +
    40. +
    +

    + To find the active touch given |source| and |touch id|: +

    +
      +
    1. + Let |activeTouches| be |source|'s `activeTouches` property. +
    2. +
    3. + [=list/For each=] |touch| in |activeTouches|: +
        +
      1. + If |touch|'s `touchId` property is equal to |touch id|, return |touch|. +
      2. +
      +
    4. +
    5. + Return `null`. +
    6. +
    +

    + To dispatch a gamepad touch move action given |action object|, |source|, |global key state|, |tick duration|, |browsing context|, and |actions options|: +

    +
      +
    1. + Let |device id| be equal to |action object|'s `deviceId` property. +
    2. +
    3. + Let |touch id| be equal to |action object|'s `touchId` property. +
    4. +
    5. + Let |x logical value| be equal to |action object|'s `x` property. +
    6. +
    7. + Let |y logical value| be equal to |action object|'s `y` property. +
    8. +
    9. + Let |touch| be the result of [=find the active touch=] given |source| and |touch id|. +
    10. +
    11. + If |touch| is `null`, return [=success=] with data `null`. +
    12. +
    13. + Let |surfaces| be |source|'s surfaces. +
    14. +
    15. + Let |bounds| be |surfaces|[|touch|.surfaceId]. +
    16. +
    17. + If |bounds| is `undefined`, return [=success=] with data `null`. +
    18. +
    19. + Let |x bounds| be equal to |bounds|'s `x` property. +
    20. +
    21. + Let |y bounds| be equal to |bounds|'s `y` property. +
    22. +
    23. + Set |touch|.x to the result of [=normalize a simulated input value=] given |x logical value| and |x bounds|. +
    24. +
    25. + Set |touch|.y to the result of [=normalize a simulated input value=] given |y logical value| and |y bounds|. +
    26. +
    27. + Set |touch|.width to the result of [=compute the surface dimension=] given |x bounds|. +
    28. +
    29. + Set |touch|.height to the result of [=compute the surface dimension=] given |y bounds|. +
    30. +
    31. + Return [=success=] with data `null`. +
    32. +
    +

    + To dispatch a gamepad touch end action given |action object|, |source|, |global key state|, |tick duration|, |browsing context|, and |actions options|: +

    +
      +
    1. + Let |device id| be equal to |action object|'s `deviceId` property. +
    2. +
    3. + Let |touch id| be equal to |action object|'s `touchId` property. +
    4. +
    5. + Let |active touches| be |source|'s activeTouches. +
    6. +
    7. + [=list/Remove=] all items with `touchId` property equal to |touch id| from |active touches|. +
    8. +
    9. + Return [=success=] with data `null`. +
    10. +
    +

    + To dispatch a gamepad pause action given |action object|, |source|, |global key state|, |tick duration|, |browsing context|, and |actions options|: +

    +
      +
    1. + Let |device id| be equal to |action object|'s `deviceId` property. +
    2. +
    3. + Run the steps for when the system [=receives new button or axis input values=] with |gamepad|. +
    4. +
    5. + Return [=success=] with data `null`. +
    6. +
    +

    + To update simulated gamepad state given |gamepad|: +

    +
      +
    1. + Let |source| be the [=gamepad input source=] for |gamepad|. +
    2. +
    3. + [=map/For each=] |index| → |value| of |source|.pendingAxisInputs, set |gamepad|.{{Gamepad/[[axes]]}}[|index|] to |value|. +
    4. +
    5. + [=map/For each=] |index| → |value| of |source|.pendingButtonInputs, set |gamepad|.{{Gamepad/[[buttons]]}}[|index|] to |value|. +
    6. +
    7. + [=list/Empty=] |gamepad|.{{Gamepad/[[touches]]}}. +
    8. +
    9. +

      + [=list/For each=] |touch| of |source|.activeTouches: +

      +
        +
      1. + Let |position| be a [=new=] {{DOMPointReadOnly}} with {{DOMPointReadOnly/x}} initialized to |touch|.x and {{DOMPointReadOnly/y}} initialized to |touch|.y. +
      2. +
      3. +

        + If |touch|.width and |touch|.height are not `undefined`, let |surfaceDimensions| be a new {{DOMRectReadOnly}} with {{DOMRectReadOnly/width}} initialized to |touch|.width and {{DOMRectReadOnly/height}} initialized to |touch|.height. +

        +

        + Otherwise, let |surfaceDimensions| be `null`. +

        +
      4. + Let |gamepadTouch| be a [=new=] {{GamepadTouch}} with its {{GamepadTouch/touchId}} set to |touch|.touchId, its {{GamepadTouch/surfaceId}} set to |touch|.surfaceId, its {{GamepadTouch/position}} set to |position|, and its {{GamepadTouch/surfaceDimensions}} set to |surfaceDimensions|. +
      5. +
      6. + [=list/Append=] |gamepadTouch| to |gamepad|.{{Gamepad/[[touches]]}}. +
      7. +
      +
    10. +
    From 1e5e7709279ea99c36a5cd7e6d20cdf2674678a2 Mon Sep 17 00:00:00 2001 From: Matt Reynolds Date: Thu, 11 Sep 2025 15:36:42 -0700 Subject: [PATCH 6/7] Update index.html MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcos Cáceres --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 390a232..f6b1b6c 100644 --- a/index.html +++ b/index.html @@ -2889,7 +2889,7 @@
  • Let |simulatedGamepads| be the [=simulated gamepad map=].
  • -
  • +
  • Let |deviceId:string| be the result of calling [=generate a random UUID=].
  • From 02c8a135eb766c8354345032d2b989ab445f4509 Mon Sep 17 00:00:00 2001 From: Matt Reynolds Date: Thu, 9 Oct 2025 14:06:32 -0700 Subject: [PATCH 7/7] Update index.html Co-authored-by: Maksim Sadym <69349599+sadym-chromium@users.noreply.github.com> --- index.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/index.html b/index.html index f6b1b6c..d545129 100644 --- a/index.html +++ b/index.html @@ -802,8 +802,6 @@

  • Return 2 (|value| − |minimum|) / (|maximum| − |minimum|) − 1.
  • -
  • -
  • To map and normalize axes for |gamepad:Gamepad|, run the