google-chromefirefoxgamepadxbox-onegamepad-api

Listen for gamepad button events with xbox one controller


I'd like to listen for button press events on an xbox one controller, but seems that many solutions to this are experimental and under development. Most examples I've found showing how to receive input from a gamepad use a polling method to repeatedly check the gamepad for events, but for my application it is crucial that I can record the exact timing of the button press, and I don't want to miss button presses in between scanning the game pad.

I can use either Firefox or Chrome but I haven't gotten the following solutions to work in either browser yet:

Firefox: According to this page https://www.chromestatus.com/feature/5989275208253440#, "gamepad button and axis events are implemented in Firefox behind the flag dom.gamepad.non_standard_events.enabled". I have enabled this in Firefox but listening to state change events (as described at https://www.smashingmagazine.com/2015/11/gamepad-api-in-web-games/) still has no effect.

Chrome: This github page https://github.com/MozillaReality/gamepad-plus/blob/master/README.md looks like it can extend the Gamepad API so I can also listen for button press events in Chrome, but when I try to compile the JavaScript as a standalone module using npm run build I get the error node_modules_missing and the build fails.

I'd appreciate advice on how to enable .addEventListener('gamepadbuttondown'... to work in either of these browsers.


Solution

  • Thanks to a codepen example by Christopher Van Wiemeersch at https://codepen.io/cvan/pen/aOzgGE I have found a solution in Firefox.

    First I opened a Firefox browser (version 73.0.1) and entered about:config in the URL. Then I toggled dom.gamepad.non_standard_events.enabled to true.

    Then I used the following functions/listeners from Christopher's codepen:

    var gamepadConnected = function (e) {
      console.log('Gamepad connected at index %d: %s. %d buttons, %d axes.',
        e.gamepad.index, e.gamepad.id, e.gamepad.buttons.length, e.gamepad.axes.length);
    };
    
    var gamepadDisconnected = function (e) {
      console.log('Gamepad removed at index %d: %s.', e.gamepad.index, e.gamepad.id);
    };
    
    
    var gamepadButtonDown = function (e) {
      console.log('Gamepad button down at index %d: %s. Button: %d.',
        e.gamepad.index, e.gamepad.id, e.button);
    };
    
    var gamepadButtonUp = function (e) {
      console.log('Gamepad button up at index %d: %s. Button: %d.',
        e.gamepad.index, e.gamepad.id, e.button);
    };
    window.addEventListener('gamepadconnected', gamepadConnected);
    window.addEventListener('gamepaddisconnected', gamepadDisconnected);
    
    window.addEventListener('gamepadbuttondown', gamepadButtonDown);
    window.addEventListener('gamepadbuttonup', gamepadButtonUp);
    

    Then when a button is pressed I record the timestamp using var timestamp = new Date().getTime().