Question3r
Question3r

Reputation: 3772

listen for gamepad connection and input

I would like to provide gamepad support for my web application. This application is a socket client (using socket.io) and it should also being able to deal with gamepad input.

So when plugging in a gamepad via USB or Bluetooth I would like to fire an event, same for input. I was hoping that the Gamepad API would solve it. Unfortunately it didn't.

I created this example

$(document).ready(() => {
  window.addEventListener("gamepadconnected", e => {
    console.log("connected gamepad");
  });

  window.addEventListener("gamepaddisconnected", e => {
    console.log("disconnected gamepad");
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

I plug in my XBox360 controller but unfortunately no event was fired. Am I missing something?

I use Chrome Version 76.0.3809.132 (Official Build) on Manjaro Linux (64-bit)

When running navigator.getGamepads() in the console I get this result GamepadList {0: null, 1: null, 2: null, 3: null, length: 4}

And btw. of course my controller is working on other applications e.g. games :)


Update

I installed Firefox 68.0.1 (64-bit) and it worked... but Chromium seems to struggle

Upvotes: 9

Views: 2004

Answers (1)

svidgen
svidgen

Reputation: 14292

TLDR

  1. Refresh gamepad status in a loop and build your own events.
  2. Remind players to press button on their gamepad to get started.

I wrote a little experiment with the Gamepad API, which I have running on thepointless.com. The full source is available on Github.

Essentially, my experiment does the following in a loop and just prints the output to the screen:

JSON.stringify(
    [...navigator.getGamepads()]
    .filter(p => p)
    .map(pad => ({
        index: pad.index,
        id: pad.id,
        mapping: pad.mapping,
        axes: pad.axes,
        buttons: [...pad.buttons].map(b => ({
            pressed: b.pressed,
            touched: b.touched,
            value: b.value
        })),
        vibrationActuator: pad.vibrationActuator
    })),
    null,
    2
);

In my writeup, I've noted a few things that I anticipate will be generally helpful for working with the API. But, of more relevance to the OP:

  1. The event listeners are a little unreliable.
  2. Gamepads are not accessible via navigator.getGamepads() until a gamepad button is pressed.
  3. The gamepad objects returned by navigator.getGamepads() are not "live"; you actually need to re-fetch them to gate latest axis and button status.

For those reasons, and particularly because you always need to query navigator.getGamepads() to refresh button/axes statuses anyway, any serious work I do with the API will always re-query for gamepads in my game loop, then check statuses, and instruct users to press a gamepad button if gamepads can't be found. If I need "events", I'll build out my own.

I would suggest others do that same.

Upvotes: 1

Related Questions