- From: Florian Bösch <pyalot@gmail.com>
- Date: Sat, 4 Aug 2012 19:10:43 +0200
- To: Glenn Maynard <glenn@zewt.org>
- Cc: Scott Graham <scottmg@chromium.org>, Rick Waldron <waldron.rick@gmail.com>, olli@pettay.fi, Webapps WG <public-webapps@w3.org>, Ted Mielczarek <ted@mielczarek.org>
- Message-ID: <CAOK8ODiWV0BMZiHe5UhSFFg5M3LuoTD_vYiDx3pp0kvhEixXXQ@mail.gmail.com>
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