# Virtual Gamepad in JavaScript

This past week, there was a first for me. I did something I've never done before: I ran a workshop as part of a conference. The [CodeLand:Distributed](https://codelandconf.com/) conference.

It was titled "Rocking the Gamepad API", and we developed a [Rock Band-styled game in HTML and JavaScript](https://dev.to/alvaromontoro/develop-a-rock-band-game-with-html-and-javascript-in-10-minutes-26kc) that could be controlled with the PlayStation drumkit connected to the computer. Then in separate groups, the attendees could develop their own game/app using the [Gamepad API](https://w3c.github.io/gamepad/).

I had different game controllers that I could use during the presentation, but what happened if the people attending the workshop didn't have one? What if they couldn't complete the tasks because they missed a gamepad?

![Picture of controllers for NES, SNES, Nintendo64, PlayStation 2, PlayStation 3, drumset, and DDR mat](https://cdn.hashnode.com/res/hashnode/image/upload/v1639764949237/0zC4k9iEK.png)

Different gamepads ready for the workshop... I ended up only using one (or two).

With that in mind, I created a soft Gamepad Simulator. A small JavaScript snippet that generates an on-screen controller that triggers and behaves just like a physical gamepad connected to the browser:

*   It triggers the `gamepadconnected` and `gamepaddisconnected` events.
*   It generates a gamepad object with all the standard properties.
*   It updates the values of the gamepad object when the user interacts with the virtual gamepad.

Here is a demo of the Gamepad Simulator at work:

<iframe height="600" src="https://codepen.io/alvaromontoro/embed/zYreVrp?height=600&amp;default-tab=result&amp;embed-version=2" style="width:100%"></iframe>

It may be a basic thing at the moment, but **it could be helpful for people that want to try and develop with the Gamepad API but don't have a physical gamepad available** for any reason.

...which was the case in the presentation.

How it works
------------

The initial code is fairly simple. It can be found on this [Codepen](https://codepen.io/alvaromontoro/pen/gOPEWyq) –although this [demo](https://codepen.io/alvaromontoro/pen/zYreVrp) maybe better to appreciate the behavior–, and [the project continues on GitHub](https://github.com/alvaromontoro/gamepad-simulator).

The module creates an object named `gamepadSimulator` that has 4 methods:

### `create()`

This method sets the whole environment in place to use the gamepad:

*   It generates an SVG picture of a generic-looking gamepad and places it on the screen.
*   It adds an id to the image so it can be styled and customized.
*   It generates fake information for a standard 17-button gamepad.
*   It associates all the events to the buttons and axes, so the information of the gamepad is updated upon user action.
*   It replaces the `navigator.getGamepad()` with its own method that will return the fake gamepad.

![Gamepad with buttons 0-16 and 2 axes](https://cdn.hashnode.com/res/hashnode/image/upload/v1639764951125/0btAfYxes.png)

Screenshot of the virtual keyboard on a web page

It is necessary to call this function at first... which may seem unnecessary; why not directly run all these actions when importing the module?

We could do that, but the idea is to expand the module in the future and allow for some customization of the gamepad (which would require this `create()` method.

### `connect()`

This method will trigger the `gamepadconnected` event with the gamepad information generated in the `create()` function.

To do so, we make use of the [Event interface](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event) to create a custom event of the type `gamepadconnected`, and then [we dispatch it with `dispatchEvent`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent):  

    const event = new Event("gamepadconnected");
    // update fakecontroller initial information
    event.gamepad = gamepadSimulator.fakeController;
    window.dispatchEvent(event);
    

The dispatched event will be treated as the regular event triggered after connecting a gamepad to the browser.

### `disconnect()`

This method will trigger the `gamepaddisconnected` event with the current information from the gamepad generated in the `create()` function. It is created and dispatched/triggered in the same way as the `gamepadconnected` event described in the previous section.

It is important to call this function after completing the tests. Otherwise, the gamepad won't be disconnected and the app –not the module– may keep running affecting performance.

### `destroy()`

This method performs necessary clean-up after the gamepad has been used:

*   Calls the `disconnect()` method (just in case).
*   Removes the gamepad image from the screen.
*   Reinstantiates the original `navigator.getGamepad()` function.

What's next?
------------

As of right now, the code and functionality are fairly basic. They get the job done, but they lack many options and customizations.

I would like to improve some things like:

*   Allowing for diagonal moves of the axes (and different intensities).
*   Adding options to generate non-standard gamepads.
*   Adding customization so users could create a gamepad that fits their needs (e.g. number of buttons, number of axes, etc.)
*   Having different gamepad faces and not just the generic one.
*   Making it easier to export/import the project.

As I mentioned above, the [project is on GitHub](https://github.com/alvaromontoro/gamepad-simulator) (and at a really early stage), so any suggestion/recommendation/help will be welcomed.
