<p>
  Use the button below to connect/disconnect the virtual gamepad, then click on the buttons and axes to simulate working with the gamepad. Info messages will be displayed on screen and in the console.
</p>
<p>
  <button onclick="handleButtonClick(this)">Connect</button>
  <button onclick="document.querySelector('#events').innerHTML = '';">Clear log</button>
</p>
<p id="events">
</p>
p, button {
  max-width: 50ch;
  font-family: Roboto, Arial, sans-serif;
  font-size: 1.125rem;
  line-height: 1.5em;
}

button {
  color: white;
  background: #369;
  border: 0;
  padding: 0.5rem 1rem;
}

button:hover {
  background: #136;
}

#amdfc-controller {
  position: fixed !important;
  bottom: 1vmin;
  right: 1vmin;
  max-width: 350px;
  width: 40vw;
}
function handleButtonClick(button) {
  if (button.textContent === "Disconnect") {
    gamepadSimulator.disconnect();
    button.textContent = "Connect";
  } else {
    gamepadSimulator.connect();
    button.textContent = "Disconnect";
  }
}

/*****/
const gamepads = {};

function readValues() {
  const cgs = navigator.getGamepads();
  const indexes = Object.keys(gamepads);
  for (let x = 0; x < indexes.length; x++) {
    const buttons = cgs[indexes[x]].buttons;
    const axes = cgs[indexes[x]].axes;
    for (let y = 0; y < buttons.length; y++) {
      if (buttons[y].pressed) {
        console.log(`button ${y} pressed.`);
        document.querySelector("#events")
                .insertAdjacentHTML('afterbegin', `<div>Button ${y} pressed.</div>`);
      }
    }
    for (let y = 0; y < axes.length; y++) {
      if (axes[y] != 0) {
        const axe = Math.floor(y / 2);
        const dir = y % 2;
        let move = "up"
        if (dir === 0 && axes[y] == 1) {
          move = "right";
        } else if (dir === 0 && axes[y] == -1) {
          move = "left";
        } else if (dir === 1 && axes[y] == 1) {
          move = "down";
        }
        console.log(`axe ${axe} moved ${move}.`);
        document.querySelector("#events")
                .insertAdjacentHTML('afterbegin', `<div>Axe ${axe} moved ${move}.</div>`);
      }
    }
  }
  
  if (indexes.length > 0) {
    window.requestAnimationFrame(readValues);
  }
}

window.addEventListener("gamepadconnected", function(e) {
  console.log(`Gamepad connected: ${e.gamepad.id}`);
  document.querySelector("#events")
          .insertAdjacentHTML('afterbegin', '<div><b>Gamepad connected.</b></div>');
  gamepads[e.gamepad.index] = true;
  readValues();
});

window.addEventListener("gamepaddisconnected", function(e) {
  console.log(`Gamepad disconnected: ${e.gamepad.id}`);
  document.querySelector("#events")
          .insertAdjacentHTML('afterbegin', '<div><b>Gamepad disconnected.</b></div>');
  delete gamepads[e.gamepad.index];
});

gamepadSimulator.create();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://codepen.io/alvaromontoro/pen/gOPEWyq