Re: GamepadObserver (ie. MutationObserver + Gamepad)

On Sat, Aug 4, 2012 at 7:03 PM, Glenn Maynard <glenn@zewt.org> wrote:

> Here's a rough sketch of an API that provides clean forwards-compatibility
> for devices.  I think this also avoids all of the issues I talked about
> earlier: it gives a clean, easy to use event-based API that preserves
> ordering and timestamps; it can be used in both an event-based and polling
> way; it can retrieve both events and the current state; and most
> importantly it doesn't push things into a library, with all of the serious
> (and hopefully obvious to everyone on this list) problems that would cause.
>
> // Retrieve a representation of the device, with no actual access to
> inputs:
> var gamepad = getSomeInputDevice();
>
> // Get a list of supported layouts:
> console.log(gamepad.layouts);
> ["X360", "NES", "SNES", "raw"]
>
> // Get an interface, specifying which layout to use.
> var gamepadInput = gamepad.getLayout("X360");
>
> // Read the current state.
> var state = gamepadInput.getCurrentState();
> /* state == {
>     // These values are defined by the X360 layout.
>     leftThumbStickX: 0, leftThumbStickY: 0,
>     rightThumbStickX: 0.4, rightThumbStickY: 0.5,
>     up: true, right: false, down: false, left: false,
>     buttonX: false, buttonY: false, buttonA: false, buttonB: false,
>
>     // Inputs which have no representation in this layout are returned in
> raw form.
>     rawCompassAngle: 45,
> } */
>
> // Read the buffer of changes:
> var stateChanges = gamepadInput.read();
> /* stateChanges == [{
>     input: "rightThumbstickX", // These labels are equal to the object
> keys in "state" above.
>     value: 0.5,
>     lastValue: 0.4,
>      timestamp: 1336102719319,
> }, {
>     input: "rawCompassAngle",
>      value: 55,
>     lastValue: 45,
>     timestamp: 1336102721319,
> }] */
>
> function processInput(stateChanges)
> {
>     // Process inputs:
>     for(var i = 0; i < stateChanges.length; ++i)
>     {
>         var change = stateChanges[i];
>         var delta = change.lastValue - change.value;
>         switch(change.input)
>         {
>         case "left": console.log("Left button was " + change.value?
> "pushed":"released"); break;
>          case "leftThumbStickX":
>             console.log("Left stick X axis:" + change.value + " with a
> relative change of " + delta);
>             break;
>         }
>     }
>
>     // Update the game state.  This API allows us to process all inputs
> that happen simultaneously together,
>     // such as axis changes, and then only update the game state once for
> the whole batch.
>     processInputs();
> }
>
> // Receiving an event on change:
> gamepadInput.onchange = function(e) { processInput(gamepadInput.read());
> };
>
> Some points:
>
> - A browser may support many different layouts for the same device.  For
> example, an Xbox 360 controller can easily be used as an NES or SNES
> controller, so it can expose those profiles.
> - Raw inputs for any unmapped inputs are included for all profiles.  This
> allows games to make use of additional controls, without being forced to
> drop back to "raw" to access them at all.
> - If a profile is exposed at all, the inputs of the profile must be
> completely covered.
> - Layout may not always map 1:1 to raw inputs.  For example, the
> Playstation controller's D-pad is four buttons in a cross; layouts may map
> these four buttons down to two axes.
> - All data in getCurrentState is absolute, since it doesn't mutate the
> object.  Therefore, purely relative inputs, such as trackballs and
> (probably) steering wheels, are returned in an absolute, accumulated form.
> To get relative motion, subtract the value from the previous value.
>
> By the way, while I only included "NES" as an example, having a "baseline"
> layout like that (with a more generic name) is useful: tons of simple games
> use only a D-pad and a couple buttons.  This would give them get the widest
> input device support possible, by not having to request a profile with far
> more features than they need.
>
> I haven't tried to incorporate Florian's suggestion of using something
> like ArrayBuffer.  That could be supported later, eg. by providing a
> readIntoBuffer(buffer) next to read().  That's too complex to try to tackle
> all at once.

What happens if there is no supported profile?

Received on Saturday, 4 August 2012 17:11:12 UTC