Re: GamepadObserver (ie. MutationObserver + Gamepad)

Here are some piecemeal thoughts on the subject of gamepads and the
"gamepad" spec.  I havn't closely followed earlier discussions (and there
don't seem to have been any in a while), so much of this may have been
covered before.

- It should be possible to tell what's changed, not just the current state
of the device.  Needing to compare each piece of input to the previous
state is cumbersome.

- Native deadzone handling (by the OS or internally to the device) is the
only way to correctly handle deadzones when you don't have intimate
knowledge of the hardware.  It should be explicitly (if non-normatively)
noted that native deadzone handling should be used when available.

- It's very important that it's possible to receive gamepad data without
polling.  We don't need more web pages running setTimeout(0) loops as fast
as browsers will let them, which is what it encourages.  Not all pages are
based on a requestAnimationFrame loop.

- An API that can only return the current state loses button presses if
they're released too quickly.  It's common to press a button while the UI
thread is held up for one reason or another--and you also can't assume that
users can't press and release a button in under 16ms (they can).

- APIs like that also lose the *order* of button presses, when they're
pressed too quickly.  (I've encountered this problem in my own experience;
it's definitely possible--it's not even particularly hard--for a user to
press two buttons in a specific order in under 16ms.)

I'd suggest a halfway point between polling and events: a function to
retrieve a list of device changes since the last call, and an event fired
on the object the first time a new change is made.  For example,

var gamepad = window.openGamepad(0);
gamepad.addEventListener("input", function(e) {
    var changes = gamepad.readChanges();
}, false);

with changes being an array of objects, each object describing a
timestamped change of state, eg:

changes = [
    {
        button: 0,
        state: 1.0,
        lastState: 0.85,
        timestamp: 1336102719319
    }
]

This allows using polling if your application is based on
requestAnimationFrame, or events if you want to be told when there's
something to read.  There isn't an excess of events dispatched, because the
event is only dispatched once per call to readChanges; if you only read
changes once in a while you'll only receive the one event.  It also solves
all of the above problems with a most-recent-state-only interface.

The timestamp should be as accurate as possible to when the event actually
happened, in the clock used by Date.now(), so you can tell how long ago the
event happened.  Accurate timestamps are important for games that require
fine-grained timing; 2D fighters and rhythm games can make use of this, for
example (they may render at 60 FPS but perform game logic at a much higher
rate).

Finally, some considerations other than the basic API:

Any serious gamepad API must not ignore the realities of the most common
joystick layouts, most importantly the 360 controller (far and away the
most common PC gamepad today).  The API needs to give recommended mappings
from buttons and axes to the parts of those real-world controllers, so
users don't have to configure devices manually.  This is absolutely
critical; every native PC game that supports gamepads now "just works" for
the 360 controller, requiring no configuration.  (For years joystick APIs
on PCs tried to pretend that joysticks could be boiled down to a bunch of
abstract axes and buttons.  The user experience that results in is abysmal.)

If the gamepad model is known, it should also be explicitly exposed, so
applications can show help texts which match the actual buttons on the
gamepad (with a registry somewhere--which could just be a wiki
page--describing the string to product mappings).  Every native PC game
also now does this, finally catching up to what console games have done for
decades.  If a web API for gamepads doesn't do this, it'll be years behind
everything else.

Additionally, a more involved system of input profiles would be needed for
practical forward-compatibility, eg. so applications can say "this is a
list of device types I understand" and UAs can expose the device as the
nearest match.  This allows old applications to work better with devices
they don't know about, without requiring the user to manually bind buttons
and axes.  I can't stress how important it is to not require the user to
configure every game manually; it's simply no longer acceptable.

-- 
Glenn Maynard

Received on Friday, 4 May 2012 04:14:33 UTC