The Gamepad API works in Chrome but not in Firefox?

Greetings!

  1. I hope this is in the correct forum. If not, please move it.
  2. I know the problem is in my code, as normal “test” code works correctly.

My system:
I have a HP laptop running Windows 10 64 bit.
I am also running the very latest-and-greatest version of Firefox / FireFox dev edition as of this instant date.
I am using a Saitek X52 HOTAS joystick plugged into a USB port on my laptop.

What I’m Doing:

I am working on a project where I will be using a joystick to remote-control a robot via WiFi.  I know it’s doable, as I can remotely control this robot other ways.

I have spent the last week researching the gamepad API, reading the doc’s, doing the exercises, burning brown rice and sacrificing small rodents to the Computer Gods - all to no avail.

Note that there is no display requirement - nothing is going to be written to the display as it is a forward view using the robot’s camera.  All I want to do is capture certain axis and button states in real-time and communicate them to the robot so that I can swivel the head and/or move the robot in a particular direction.

Issue:

To experiment with the Gamepad API, (and learn my way around it), I put together some simple, throw-away code to experiment with polling the joystick and grabbing values.

I am going to in-line some code.  All it is supposed to do is capture a particular instant of the status of the joystick.  Essentially, it waits for me to tap the joystick or a button, displays some meaningless, (unused as yet), data on the screen, and then writes a lot of data to the web console so I can follow along.  It’s a one-shot deal - the data is captured at the time the event is fired.  I actually read it twice, once when the “connected” event is fired and the next time when I run the “navigator.getGamepad()” calls to capture the data.  Data is successfully captured each time - that is, it appears to work, but the data is meaningless. (see below)

Viz:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">

    <title>Joystick Event Test File</title>

  </head>

  <body>

    <div class="container">
        <div class="robot">
            Joystick Test File - Second Try
            <ul>
                <li id="state">State: Stop</li>
                <li id="angle_deg">Angle Degrees: 1.00°</li>
                <li id="angle_dir">Angle Direction: none</li>
                <li id="force">Joystick Force: 1.00</li>
                <li id="status">Joystick Status: Not Set</li>
                <li id="index">Joystick Index: 1.00</li>
                <li id="id">Joystick ID: Not Set</li>
                <li id="num_buttons">Number of Joystick Buttons: 1.00</li>
                <li id="num_axes">Number of Joystick Axes: 1.00</li>
                <li id="axis0">Value of Axis 1: 1.00</li>
                <li id="axis1">Value of Axis 1: 1.00</li>
                <li id="axis2">Value of Axis 2: 1.00</li>
                <li id="axis3">Value of Axis 3: 1.00</li>
                <li id="axis4">Value of Axis 4: 1.00</li>
            </ul>
        </div>
    </div>

    <p id="demo"></p>

<script>
// All the Javascript stuff goes here
//
var joystick_data

window.addEventListener("gamepadconnected", (event) => {
  joystick_data = event.gamepad;
    console.log("A gamepad was connected:");
    console.log("joystick_data");
    console.log(joystick_data);
    console.log("joystick.data.id");
    console.log(joystick_data.id);
    console.log("joystick_data.buttons");
    console.log(joystick_data.buttons);
    console.log("joystick_data.buttons - joystick_data.buttons[23]");
    console.log(joystick_data.buttons, " - ", joystick_data.buttons[23]);
    get_gamepad_data();
});

window.addEventListener("gamepaddisconnected", (event) => {
  console.log("A gamepad was disconnected:");
  console.log(event.gamepad);
});


function  get_gamepad_data() {
//  I copied the mess below from an example that supposedly accounts for both firefox and chrome.  Even without that, it still doesn't work properly.
//  I even tried making three copies of this statement and running them one after the other to see if it needed a couple of extra tries - no change.
  var js = (navigator.getGamepads && navigator.getGamepads()) || (navigator.webkitGetGamepads && navigator.webkitGetGamepads());
  console.log("\nthe 'navigator.getGamepads()' (js) value is:");
  console.log(js);
  // data from web-site
  console.log("js[0]");
  console.log(js[0]);
  // Steering:
  console.log("\njs[0].axes[0]");
  console.log(js[0].axes[0]);
  // Acceleration:
  console.log("js[0].axes[1]");
  console.log(js[0].axes[1]);
  // Breaking:
  console.log("js[0].axes[2]");
  console.log(js[0].axes[2]);
  // Buttons from 0 - 33:
  console.log("js[0].buttons");
  console.log(js[0].buttons);
return;
}
 </script>

How I run it:
A joystick is attached, I select the file containing the above code, “Open With” firefox dev edition, and as I try various things, I refresh the browser window - in essence taking a “snapshot” of the browser’s state at that point in time.

What happens:
There are ten axes returned and 34 buttons on my particular joystick, (a Saitek X52 HOTAS joystick - the only one I have), and I am assuming that, at least with respect to the first few axes and buttons, any one joystick is the same as any other.  (i.e. If I can read this joystick, I can read them all.)

Buttons 23, 24, and 25 are part of a rotary switch and, depending on position, one of the three is always “pressed”.  All the other buttons are regular buttons that you squeeze or press.  Likewise, there are ten axes, of which only six are fully implemented, and a seventh one is used as an “analog” button to record the position of a hat-switch. (why? I don’t know.)

Running in Firefox:
The gamepad object is returned, I can see it in the web console, (in FF Dev edition), I can expand the various objects contained within them, view values, and such.

The axis 0 and 1 values never change.  Axes 2 - 6 respond with changing values depending on where they’re set when I refresh the browser, the “hat switch” axis never changes

The button values never change, except for buttons 23, 24, and 25 which show “pressed” depending on the position of the rotary switch.

Note that the code waits for joystick activity to begin - as it is supposed to.  Pressing any button, or moving any joystick axis will kick off the “controller connected” event and get the ball rolling - but the joystick and/or button activity that triggered it is never captured.

In Chrome:
Each time I update the browser, I get values consistent with the values of the axes and buttons. - in other words, it works the way I think it should.

=====================

All the example code I’ve seen is extremely convoluted because the code is displaying the active data on the screen as buttons or animated axis positions - so finding the actual methods that read the data is very difficult.

The methods that I DO find always loop through all the possible values and display them individually.  In my case, I don’t care about the looping, or animation frames, or the rest of it - all I want to do is prove that I can accurately capture the state of the joystick at a particular instant in time.  Once I can do that, I will worry about the rest of it.

Please examine the code I have provided and - if possible - please explain to me what I am doing wrong.  Also, please explain in simple terms - all this JavaScript stuff is new to me and I am still struggling to understand it.

Thanks in advance for any help you can provide!

The docs had this note which might be relevant

Due to security policy, you have to interact with the controller first while the page is visible for the event to fire. If the API worked without any interaction from the user it could be used to fingerprint them without their knowledge.

1 Like

If you look at the message I posted, you will notice that I am interacting with the joystick to initiate communication.

Sorry, as you say.

On thing to try is this working demo: http://luser.github.io/gamepadtest/ - which works on my Sony PS4 gamepad on current FF on Windows 10. If that works then you know that your gamepad and version of FF are working correctly together. I found this linked at the end of https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API

1 Like

If you find bugs in the GamePad API support and you’re reasonably sure it’s not your code then feel free to file them in Bugzilla.

1 Like

I’m also trying the API, but it’s not working, I’m trying other APIs

1 Like

Similar problem but it’s not necessary Firefox bug
navigator.getGamepads() was returning an empty array. After restarting DS4Windows(or doing stop/start) it started working. After that the pad was not working in Chrome so it seems like depending which browser gets open first it will get control of the controller until DS4Windows restart. It looks like a bug in either DS4Windows or how a driver assigns pad control to a process. It seems to be too sticky and doesn’t switch to the current window and won’t lose “focus” even after closing the window.

This is a case for DS4Windows but my guess is there could be a similar issue with other controllers and they would require reconnecting to switch to a new process