xarvh/elm-gamepad

Elm Library for gamepads and game controllers


License
BSD-3-Clause
Install
elm-package install xarvh/elm-gamepad 1.1.0

Documentation

Elm Gamepad Travis build Status

This library provides an interface to the Navigator.getGamepads() Web API, and the tools to remap gamepads and game controllers.

Since pure Elm cannot access navigator.getGamepads(), in order to use the library you will need to manually add a port; you can use the one provided in port/.

import Gamepad exposing (Gamepad)
import GamepadPort
import Time exposing (Time)


type alias PlayerControl =
    { playerId : Int
    , isFiring : Bool
    , speed : Float
    }


type alias Model =
    { gamepadDatabase : Gamepad.Database
    , playerControls : List PlayerControl
    }


type Msg
    = OnGamepad ( Time, Gamepad.Blob )


gamepadToPlayerControl : Gamepad -> PlayerControl
gamepadToPlayerControl gamepad =
    { playerId = Gamepad.getIndex gamepad
    , isFiring = Gamepad.rightTriggerIsPressed gamepad
    , speed = Gamepad.leftX gamepad
    }


update : Msg -> Model -> Model
update msg model =
    case msg of
        OnGamepad ( timeSinceLastFrameUpdate, blob ) ->
            let
                gamepads =
                    Gamepad.getGamepads model.gamepadDatabase blob

                playerControls =
                    List.map gamepadToPlayerControl gamepads
            in
                { model | playerControls = playerControls }


subscriptions : Model -> Sub Msg
subscriptions model =
    GamepadPort.gamepad OnGamepad

Important!

Gamepad polling should be synchronised with the browser's animation frame.

If you are using elm-lang/animation-frame you should remove it, and instead use the Time provided by the gamepad port, which works like the value provided by AnimationFrame.diffs.

Adding ports

The ports required by elm-gamepad are no different than any other Elm port.

You can see how they are wired in in the example's index.html.

You can get ready-to-use port code from port/; you will need to:

  • Manually copy GamepadPort.elm in your Elm sources directory, so that you can import it as GamepadPort

  • Import gamepadPort.js in your app JavaScript:

<script type="text/javascript" src="gamepadPort.js"></script>
  • Register the port with the Elm app:
  var elmApp = Elm.Main.fullscreen();
  addGamepadPort(elmApp);

If you do not have another way to persist the gamepad database, you will want to add also the local storage port, the procedure is exactly the same.

What's the problem with Browsers+Gamepads?

The w3c spec defines a "Standard Gamepad" but the support for this standard mapping is sparse and ultimately unreliable.

More in general, the same hardware will be recognised differently depending on the operative system, installed driver, browser and even browser version.

For example under my Ubuntu, Firefox considers the trigger buttons of my Xbox360 gamepads as axes, while Chrome detects them as buttons.

Because of this, I don't think there is a way to create a reliable database of all game controllers.

The only reliable option is to let the user remap their controller. Remapping capabilities are also important to make a web application accessible.