UNRELEASED: Not currently ready for use.

A cross-platform Dart API for virtual and physical gamepad access in Dart.


  drivers/       | Libraries to initialize before using in a game
    browser.dart | Drivers that must be used within the browser
    flutter.dart | Drivers that must be used within Flutter[1]
    virtual.dart | Drivers that have no dependencies on a platform
  src/           | Internals. Should not be imported
  gamepad.dart   | Generic interfaces for use to build a game

[1]:, runs compiled Dart on Android/iOS


Loosely based on the W3C Gamepad API which is supported, but also with support for a combination of virtual gamepads (i.e. presents itself in the UI), for device features like accelerometers, and even for completely custom implementations (could be VR, remote, or something else).

There are a few concepts that should be understood when using the API below:

  • Gamepad: Frontend API that developers are expected to code against
  • Driver: Backend API that in turn is used by the package to produce gamepads
  • VirtualDriver: A synthetic backend that is implemented at runtime


One of the benefits of this library is that new gamepads can be created at runtime; this can be used to drive end-to-end testing of your application or even to create gamepads within the UI itself, or perhaps even controlled remotely by another device. The following is provided to help:

  • VirtualAxes: Can simulate multi-directional sticks
    • Directional: A mixin that provides simple directional support
  • VirtualButton: Can simulate a toggleable or pressable button
    • Toggle: A mixin that reports the button pressed until it is pressed again

An example of creating a virtual driver based on the W and S keys:

import 'dart:async';
import 'dart:html';

import 'package:gamepad/drivers/virtual.dart';

class WasdVirtualDriver extends VirtualDriver implements HasAxesSupport {
  Axes createAxes() => new WasdVirtualAxes(); 

class WasdVirtualAxes extends VirtualAxes<Element> with TriggerDirection {
  StreamSubscription _listener;

  Future<Null> activate(Element context) async {
    _listener = element.onKeyDown.listen((event) {
      if (event.key == 'W') {
      } else if (event.key =='S') {

  Future<Null> deactivate() async {
    await _listener.cancel();