Skip to content

Event-Driven Gamepad Input API #1000

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

snehagarwal1
Copy link

The current Gamepad API relies on constant polling to detect input changes, which can introduce input latency and increase CPU usage. This proposal adopts a hybrid approach that combines event-driven input handling with frame-based state consolidation, reducing unnecessary polling while maintaining responsiveness.

Copy link
Author

@snehagarwal1 snehagarwal1 left a comment

Choose a reason for hiding this comment

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

Hi Gabriel,

Thank you for reviewing!
I have addressed your comments. I am currently iterating on the explainer and removing some content related to the threshold logic for the scope of this doc, so I have left out some comments on purpose.

Thanks


2) **Frame-Based Consolidated Event**:

This approach consolidates all state changes that occur within a single frame into one event, reducing the number of events fired and preventing event spam. This is especially important for analog inputs and buttons that may change frequently within a single frame.
Copy link
Author

Choose a reason for hiding this comment

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

Input frame refers to the cycle in which the browser collects input data, which could refresh at least once per animation frame


- Consolidate button state changes within a single event structure: Instead of firing a separate event for each button state change (pressed/released, touched, value), all these changes will be consolidated into one gamepadchange event per frame. This prevents event spam and improves the efficiency of event handling.

- This will also reduce CPU overhead, as the browser will fire fewer events overall, and game developers will get all necessary button information in a single event.
Copy link
Author

Choose a reason for hiding this comment

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

Yes, I’m aware that this is the current situation. This comment refers to firing frequent events (as the explainer also proposes) for button up/down, changes, and axis movements. Some users may prefer a single snapshot event to reduce the frequency of individual events being fired, which could help alleviate strain on the JavaScript main thread. There are events for individual button presses and axis changes, as well as the gamepadchange event, which captures the entire gamepad state within an input frame.

snehagarwal1 and others added 2 commits April 2, 2025 10:42
Co-authored-by: Gabriel Brito <80070607+gabrielsanbrito@users.noreply.github.com>
Co-authored-by: Gabriel Brito <80070607+gabrielsanbrito@users.noreply.github.com>
@SteveBeckerMSFT SteveBeckerMSFT self-requested a review April 2, 2025 22:07
@@ -0,0 +1,201 @@
# Gamepad Button and Axis Events
Copy link
Contributor

Choose a reason for hiding this comment

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

Please also update the root readme.md in MSEdgeExplainers to include this explainer in the active section.

https://github.com/MicrosoftEdge/MSEdgeExplainers?tab=readme-ov-file#active-explainers-

Copy link
Author

Choose a reason for hiding this comment

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

Open question:
Should we consider adding rawgamepadinputchanged.getCoalescedEvents() when { coalesce = false } ?
This would be similar in semantics and pattern to rawpointerupdate which is part of Pointer Events, see:

snehagarwal1 and others added 5 commits April 8, 2025 20:28
Co-authored-by: Gabriel Brito <80070607+gabrielsanbrito@users.noreply.github.com>
Co-authored-by: Gabriel Brito <80070607+gabrielsanbrito@users.noreply.github.com>
Co-authored-by: Gabriel Brito <80070607+gabrielsanbrito@users.noreply.github.com>

## User-Facing Problem

The Gamepad API lacks event-driven input handling, forcing applications to rely on continuous polling to query for changes in gamepad input. The continuous polling introduces input latency, as scripts cannot synchronize with new input fast enough. If the script increases the polling frequency to mitigate input latency, it increases CPU usage, impacting efficiency and battery life of the device.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure about the CPU usage argument for the event-based API. Generating a lot of events for raw input changes can also consume a lot of CPU. In particular, analog inputs like the sticks and triggers might generate a lot of events as their value change continuously.

Copy link
Contributor

Choose a reason for hiding this comment

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

I also think that we should refrain from mentioning these "hardware performance" points. Also the one in the paragraph below where we claim that it will improve battery usage.

@snehagarwal1 snehagarwal1 changed the title Gamepad Button and Axis Events Event-Driven Gamepad Input API Apr 11, 2025
```
#### Key Points:
- navigator.getGamepads() returns a snapshot of all connected gamepads.
- The polling loop is driven by `requestAnimationFrame`, typically around 60Hz (matching display refresh rate), which is much lower than the internal OS poll rate (eg., 250Hz). This mismatch can result in missed input updates, making the 60Hz rate insufficient for latency-critical applications like cloud gaming.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: multiple spaces.

Suggested change
- The polling loop is driven by `requestAnimationFrame`, typically around 60Hz (matching display refresh rate), which is much lower than the internal OS poll rate (eg., 250Hz). This mismatch can result in missed input updates, making the 60Hz rate insufficient for latency-critical applications like cloud gaming.
- The polling loop is driven by `requestAnimationFrame`, typically around 60Hz (matching display refresh rate), which is much lower than the internal OS poll rate (eg., 250Hz). This mismatch can result in missed input updates, making the 60Hz rate insufficient for latency-critical applications like cloud gaming.


## User-Facing Problem

The Gamepad API lacks event-driven input handling, forcing applications to rely on continuous polling to query for changes in gamepad input. The continuous polling introduces input latency, as scripts cannot synchronize with new input fast enough. If the script increases the polling frequency to mitigate input latency, it increases CPU usage, impacting efficiency and battery life of the device.
Copy link
Contributor

Choose a reason for hiding this comment

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

I also think that we should refrain from mentioning these "hardware performance" points. Also the one in the paragraph below where we claim that it will improve battery usage.

Copy link
Author

@snehagarwal1 snehagarwal1 left a comment

Choose a reason for hiding this comment

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

Thanks Gabriel,
Resolving the comments

```
[Exposed=Window, SecureContent]
interface RawGamepadInputChangeEvent : Event {
constructor(DOMString type, optional RawGamepadInputChangeEventInit eventInitDict = {});
Copy link
Contributor

Choose a reason for hiding this comment

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

I just realized that you didn't add a definition for RawGamepadInputChangeEventInit. We should add it too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants