4

I am polling Gamepad in js using a 250ms timer to switch between 4 different viewpoints. However this value is still too high to guarantee seeing every button press. I have noticed that if a button is depressed and released too quickly (i.e., < 250ms) then it gets missed.

I can't see any event triggers related to gamepad apart from controller connected and disconnected, and I am stuck with polling, and increasing the frequency.

Can anybody propose a method of guaranteeing a button press is detected, without increasing the polling frequency? If increasing the polling frequency is the only option, what would be considered optimal?

Ralf
  • 16,086
  • 4
  • 44
  • 68
  • 1
    May want to try asking over at [`Game Development`](https://gamedev.stackexchange.com/) SE for this – mhodges Jul 23 '18 at 04:29
  • 1
    @mhodges Stack Overflow is a perfectly acceptable location for this question. – Brad Jul 23 '18 at 04:30
  • See also: https://stackoverflow.com/questions/44743130/gamepad-api-button-events-not-firing – Brad Jul 23 '18 at 04:30
  • 2
    @Brad "What is the optimum polling frequency?" seems pretty opinionated and related to game development to me. I see no MCVE. I guess it's just a poorly written question. The title and the last 2 sentences seem to be going in different directions. One is asking about polling frequency, the other is asking about gamepad event detection. – mhodges Jul 23 '18 at 04:37
  • 1
    @mhodges If you read the question and interpret what's actually being asked, vs. looking at the title and taking it so literally, you'll see that the question essentially is, "how can I reliably detect gamepad button presses?" The question is about properly using a web API and is not specific to gaming. While I would certainly not discourage this question on a more specific site, it's not off-topic here at all. – Brad Jul 23 '18 at 04:53
  • The title could be "What is the optimum gamepad polling frequency for the Web Gamepad API" which is an interesting question worth answering. I agree that the general question is not good because the answer should be specific to the (somewhat limited) Web Gamepad API and its implementations. – nondebug Jul 23 '18 at 18:22

2 Answers2

2

You should poll at (at least) 60 Hz to ensure you capture new button/axis state at least once per animation frame. Most apps poll in the requestAnimationFrame loop but this isn't always the best solution because you can still miss button presses.

The optimal polling rate is determined by the browser's internal behavior. In Chrome for instance, the browser only fetches new gamepad state every 16 milliseconds (62.5 Hz), so if you poll at ~100 Hz then you will be sure to see every update. It's still possible to miss button presses if they occur between polling iterations, but there's nothing you can do about that. (Almost nothing: Chrome Dev and Canary builds have a chrome://flags#gamepad-polling-rate option you can use to test different internal polling rates.)

The internal polling rate is not defined by the spec, is not directly exposed to the page, and is subject to change. For instance, a browser could choose to coalesce gamepad input updates and align them to the requestAnimationFrame loop which would negate any benefits from polling more frequently. Be cautious when relying on implementation-specific behavior and test your assumptions.

On Firefox you can enable non-standard button and axis events which may let you detect when input updates occur outside your normal polling loop. AFAIK these events are only implemented on FF and are disabled by default, but could be useful for testing.

nondebug
  • 761
  • 3
  • 5
1

The Gamepad API indeed only supports polling, and your polling frequency is indeed too low.

Assuming you're trying to build a game, the gamepad responsiveness would ideally be as high as the game's frame rate. This would make sure that a button press would always be caught.

Javascript's requestAnimationFrame is intended for this very purpose.

If you take a look at neogeek's gamepad.js, you'll see it uses the API to poll the gamepad at every frame:

Gamepad.prototype._loop = function () {

    ...

    self._events.gamepad.forEach(function (gamepad, player) {    
        if (gamepad) { 
            Object.keys(gamepad).forEach(function (key) {   
                self._handleEvent(key, gamepad, player);   
            });    
        }    
    });

    ...

    self._requestAnimation = _requestAnimationFrame(self._loop.bind(self));
}
Kraylog
  • 7,383
  • 1
  • 24
  • 35
  • 1
    Even polling at each frame isn't always sufficient. It depends on your application and how important things like input latency are to you. It might make sense to process input more than once per frame drawn to the screen, for instance. In a fast-paced game this would allow you to detect very quick button presses that last less than the interval between frames. – nondebug Jul 23 '18 at 18:28
  • @nondebug First, you are correct. Polling at each frame isn't an absolute solution. However, you could argue that such a solution doesn't exist. It seems to me that assuming a decent 30 fps, it would be highly unlikely that a button would be pressed twice in one frame. I suppose it comes down to an estimate of how important it is to detect, and how high the frame rate is. – Kraylog Jul 24 '18 at 08:26