Re: [Gamepad] Liveness of Gamepad objects
There's two aspects that should not be overlooked. 1. Some events only make sense in unison. For instance the input of a 2-axis knob. On many OS implementations, change events for each axis arrive separately in short succession. However to an application programmer, getting first the X axis change, and then the Y axis change may not make sense. A common result of doing this would be that instead of getting a diagonal movement, a stepped movement is displayed. The technique employed by many native application programmers to this kind of problem is to coalesce events they deem to belong together into one event. 2. Input - Output latency is a significant concern for input devices used to produce an output. One way to minimize the latency is called time warp in which most of the frames tasks that are not directly influenced by the input are completed. Then the program idles till nearly the end of the frame, polls the input (which should arrive fresh) and then completes the rest of the (ideally constant time) tasks just before the frame runs out.
Re: [Gamepad] Liveness of Gamepad objects
On 4/30/2014 12:21 AM, Glenn Maynard wrote: My original prototype provided the events mentioned above. The feedback I received was overwhelmingly in favor of a polling API instead[3]. I decided to go ahead with that (actually Scott beat me to the punch and implemented that in Chrome first), figuring we could always spec events in a future revision. (Please try to direct conversations here or to the whatwg list, so everyone has a chance to participate...) If you note the dates you can see that this was well before standardization work started. This was just feedback on a prototype. Supporting polling is a separate issue from whether the Gamepad interface is live or a snapshot. You definitely want to be able to retrieve a snapshot of the current state, and as long as you can do that you automatically support polling. Yes, it's true. In any event, this is going a bit afield. We're not going to spec events for the first version of the spec. We have two mostly-compatible implementations shipping in Firefox and Chrome supporting polling, I'd just like to nail down the remaining uncertain bits of the spec (like the topic at hand) so others can ship compatible implementations. Once that's done we can certainly discuss features for a next revision, there's already a wiki page[1] to gather ideas. (Aside: I'm not sure if the top one is correct. Does getGamepads()[n].index == n, so that gamepadState[i] always corresponds to lastGamepadState[i]? The spec suggests that with index of the gamepad in the Navigator, but I'm not sure. If so, what is getGamepads()[1] if controller index 1 is disconnected, since you can't reorder the later items? undefined?) Yes, Gamepad.index is the index into the list returned by navigator.getGamepads(), so that holds true. If the latter portion isn't answered in the spec I can add some text to clarify: there are allowed to be holes in the array where controllers were removed. I'm not sure what they are in current practice, but null or undefined both seem like legitimate values. -Ted 1. https://www.w3.org/wiki/Webapps/GamepadFeatures
Re: [Gamepad] Liveness of Gamepad objects
On 4/29/2014 10:39 AM, Ted Mielczarek wrote: The only major issue that needs to be fixed in the Gamepad API spec currently is the liveness of Gamepad objects[1]. After reading through the discussion here I'm leaning towards specifying the snapshot behavior that Chrome implements. Regardless of whether we spec an event-based update mechanism in the future, being able to refer to a snapshot of Gamepad state seems useful, and there's not much overhead in calling navigator.getGamepads()[i] instead of referring directly to a saved Gamepad object. My only reservation is that if Gamepad becomes a snapshot instead of a live object, it feels weird to suggest adding output methods to it (like adding vibration support). Perhaps I'm overthinking it, though. Any other thoughts here? -Ted
Re: [Gamepad] Liveness of Gamepad objects
On Wed, Apr 30, 2014 at 5:58 AM, Ted Mielczarek t...@mozilla.com wrote: Yes, it's true. In any event, this is going a bit afield. We're not going to spec events for the first version of the spec. Examining the features that each design would make easier or harder isn't afield. On Wed, Apr 30, 2014 at 6:11 AM, Ted Mielczarek t...@mozilla.com wrote: My only reservation is that if Gamepad becomes a snapshot instead of a live object, it feels weird to suggest adding output methods to it (like adding vibration support). Perhaps I'm overthinking it, though. I cut out a comment about that for length, actually. It would be better to have separate objects for the gamepad itself and where output methods live, and another interface holding a snapshot of an input state. Then, you'd just call gamepad.getState() to read the state for that device. It's also a natural place for an event interface to live, and for input state that doesn't change, like the device's ID. I definitely wouldn't make Gamepad live just to avoid doing that, though. It could always be added later, by adding a GamepadDevice interface, eg: gamepadDevices = navigator.getGamepadDevices(); gamepad = gamepads[0]; state = gamepad.getState(); equivalent to navigator.getGamepads()[0]. -- Glenn Maynard
Re: [Gamepad] Liveness of Gamepad objects
On Wed, Apr 30, 2014 at 12:21 AM, Glenn Maynard gl...@zewt.org wrote: On Tue, Apr 29, 2014 at 8:25 PM, Ted Mielczarek t...@mozilla.com wrote: On 4/29/2014 7:28 PM, Glenn Maynard wrote: Gamepad objects should definitely be a snapshot. Otherwise, change events could only expose the most recent state of the gamepad. For example, if the user presses a button and then releases it very quickly (before the down press gets handled by script), and you fire two change events, the script would never see the buttons as pressed. This is a good point--if we have live objects then if we do implement change events we'd need to store the state elsewhere. Firefox has gamepadbutton{press,release} events and gamepadaxismove events[1][2] (behind a pref), they actually do this already but it's not fantastic. There should simply be a change event, which is fired when any property changes. (Some rate clamping might be needed for analog inputs, which could change very quickly, but that's an implementation detail.) My original prototype provided the events mentioned above. The feedback I received was overwhelmingly in favor of a polling API instead[3]. I decided to go ahead with that (actually Scott beat me to the punch and implemented that in Chrome first), figuring we could always spec events in a future revision. (Please try to direct conversations here or to the whatwg list, so everyone has a chance to participate...) Supporting polling is a separate issue from whether the Gamepad interface is live or a snapshot. You definitely want to be able to retrieve a snapshot of the current state, and as long as you can do that you automatically support polling. That is, users can either use polling: onRequestAnimationFrame = function() { // Once we create this, it never changes, so we can compare it the next time around when it becomes lastGamepadState. var gamepadState = navigator.getGamepads(); // Find differences between lastGamepadState and gamepadState and act on them: for(var i = 0; i gamepadState.length; ++i) processInput(gamepadState[i], lastGamepadState[i]); // Save the current state, for comparison during the next frame. lastGamepadState = gamepadState; } or events: navigator.onGamepadChange = function(e) { var gamepadState = e.state; processInput(e.gamepadIndex, gamepadState, lastGamepadState); lastGamepadState[e.gamepadIndex] = gamepadState; } This is exactly the semantics I described here http://lists.w3.org/Archives/Public/public-webapps/2014AprJun/0266.html, with the exception that the Gamepad object is live and the change event states are snapshots. Something else to consider: how does a Gamepad object behave with Object.observe? var gamepads = navigator.getGamepads(); Object.observe(gamepads[0], function(changeRecords) { ... }); Presumably the live object design will work as expected, invoking the observe handler at the end of each processing turn microtask (changeRecords will always include the previous and current values), and the snapshot does not. Rick
RE: [Gamepad] Liveness of Gamepad objects
From: Ted Mielczarek t...@mozilla.com Does anyone have any feedback on which of these seems more natural? Is there any precedent in the web platform to prefer one approach over the other? If the snapshot approach is chosen, I think it would be best to rename the Gamepad interface to GamepadSnapshot. Without that change, the live approach seems a lot more natural.
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 4:24 PM, Domenic Denicola dome...@domenicdenicola.com wrote: If the snapshot approach is chosen, I think it would be best to rename the Gamepad interface to GamepadSnapshot. Without that change, the live approach seems a lot more natural. DOM nodes are live. That is, you keep getting back the same copy, and bits of such as attributes can change over time. I think that is generally the pattern we follow throughout the platform. Notifications API being an exception of sorts due to its cross-realm nature. I think the main problem with making a Gamepad live is that the lifetime of the object has to be lifetime of the associated global. Otherwise GC can be observed through expandos. -- http://annevankesteren.nl/
Re: [Gamepad] Liveness of Gamepad objects
On 4/29/14, 11:32 AM, Anne van Kesteren wrote: I think the main problem with making a Gamepad live is that the lifetime of the object has to be lifetime of the associated global. Otherwise GC can be observed through expandos. For what it's worth, the way Gecko implements this is by setting up that lifetime guarantee only when an expando is added to the object (or some other things, like use as a WeakMap key, happen). Until then we allow it to be GCed. -Boris
Re: [Gamepad] Liveness of Gamepad objects
Boris Zbarsky wrote: For what it's worth, the way Gecko implements this is by setting up that lifetime guarantee only when an expando is added to the object (or some other things, like use as a WeakMap key, happen). Until then we allow it to be GCed. What do other engines do in general? Unobservable GC is a requirement, if you ask me and Mark Miller. /be
Re: [Gamepad] Liveness of Gamepad objects
I don't know anything about Gamepad. Could someone provide enough context that I can understand the question? Thanks. (Yes, I found https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.htmlby googling. It's not what I need.) On Tue, Apr 29, 2014 at 10:16 AM, Brendan Eich bren...@secure.meer.netwrote: Boris Zbarsky wrote: For what it's worth, the way Gecko implements this is by setting up that lifetime guarantee only when an expando is added to the object (or some other things, like use as a WeakMap key, happen). Until then we allow it to be GCed. What do other engines do in general? Unobservable GC is a requirement, if you ask me and Mark Miller. /be -- Cheers, --MarkM
Re: [Gamepad] Liveness of Gamepad objects
I don't think that API design should be driven by implementation details, but it may be useful to provide some background on Chrome's Gamepad implementation here: The current polling-only API Chrome uses is largely due to practicality with the multiprocess architecture. The gamepad data is acquired in the central browser process, placed in shared memory, and then polled by the tab processes when getGamepads() is called. This cuts down on a lot of IPC overhead that would otherwise result from constant Hey, Gamepad N changed! messages broadcast to all tabs. Given that, if we decide that the gamepad objects should be live and not snapshots I think that Chrome will probably put a system in place where the first access of a gamepad object property does a behind-the-scenes poll and then does not poll again until control has been given back to the browser. (Which is probably not an issue since many games will be processing input in a rAF loop.) I can't think of any scenario where a forced policy of one update per frame would be detrimental, but I'm open to feedback on the matter. If it were my call I'd vote for gamepad objects being snapshots simply because it will add some additional overhead to make them live and it avoid concerns about observing GC, but I don't really object to either design. --Brandon On Tue Apr 29 2014 at 10:18:24 AM, Brendan Eich bren...@secure.meer.net wrote: Boris Zbarsky wrote: For what it's worth, the way Gecko implements this is by setting up that lifetime guarantee only when an expando is added to the object (or some other things, like use as a WeakMap key, happen). Until then we allow it to be GCed. What do other engines do in general? Unobservable GC is a requirement, if you ask me and Mark Miller. /be
Re: [Gamepad] Liveness of Gamepad objects
On Tue Apr 29 2014 at 10:24:48 AM, Mark S. Miller erig...@google.com wrote: I don't know anything about Gamepad. Could someone provide enough context that I can understand the question? Thanks. The Gamepad API returns an array of Gamepad state objects when you call getGamepads(), like so: requestAnimationFrame(function() { var gamepads = navigator.getGamepads(); var playerGamepad = gamepads[0]; if (playerGamepad.buttons[0].pressed) { player.jump(); } } That code currently would work in both Firefox and Chrome. The Liveness question concerns the following code: var gamepads = navigator.getGamepads(); var playerGamepad = gamepads[0]; requestAnimationFrame(function() { if (playerGamepad.buttons[0].pressed) { player.jump(); } } In Firefox this code will be functionally equivalent to the first code snippet, since it continues to update the values Gamepad state object after you've acquired it. AKA: The object is live. In Chrome, however, the gamepad state returned is a snapshot and as such the second code snippet will not observe changes to the gamepad input. The spec is currently ambiguous on the matter, so we want to clarify whether or not the second code snippet is valid or not and update the browser implementations accordingly. --Brandon On Tue, Apr 29, 2014 at 10:16 AM, Brendan Eich bren...@secure.meer.netwrote: Boris Zbarsky wrote: For what it's worth, the way Gecko implements this is by setting up that lifetime guarantee only when an expando is added to the object (or some other things, like use as a WeakMap key, happen). Until then we allow it to be GCed. What do other engines do in general? Unobservable GC is a requirement, if you ask me and Mark Miller. /be -- Cheers, --MarkM
Re: [Gamepad] Liveness of Gamepad objects
How would either make GC observable? On Tue, Apr 29, 2014 at 10:45 AM, Brandon Jones bajo...@google.com wrote: On Tue Apr 29 2014 at 10:24:48 AM, Mark S. Miller erig...@google.com wrote: I don't know anything about Gamepad. Could someone provide enough context that I can understand the question? Thanks. The Gamepad API returns an array of Gamepad state objects when you call getGamepads(), like so: requestAnimationFrame(function() { var gamepads = navigator.getGamepads(); var playerGamepad = gamepads[0]; if (playerGamepad.buttons[0].pressed) { player.jump(); } } That code currently would work in both Firefox and Chrome. The Liveness question concerns the following code: var gamepads = navigator.getGamepads(); var playerGamepad = gamepads[0]; requestAnimationFrame(function() { if (playerGamepad.buttons[0].pressed) { player.jump(); } } In Firefox this code will be functionally equivalent to the first code snippet, since it continues to update the values Gamepad state object after you've acquired it. AKA: The object is live. In Chrome, however, the gamepad state returned is a snapshot and as such the second code snippet will not observe changes to the gamepad input. The spec is currently ambiguous on the matter, so we want to clarify whether or not the second code snippet is valid or not and update the browser implementations accordingly. --Brandon On Tue, Apr 29, 2014 at 10:16 AM, Brendan Eich bren...@secure.meer.netwrote: Boris Zbarsky wrote: For what it's worth, the way Gecko implements this is by setting up that lifetime guarantee only when an expando is added to the object (or some other things, like use as a WeakMap key, happen). Until then we allow it to be GCed. What do other engines do in general? Unobservable GC is a requirement, if you ask me and Mark Miller. /be -- Cheers, --MarkM -- Cheers, --MarkM
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 10:39 AM, Ted Mielczarek t...@mozilla.com wrote: The only major issue that needs to be fixed in the Gamepad API spec currently is the liveness of Gamepad objects[1]. Currently this is implemented differently in Firefox and Chrome--Firefox uses live Gamepad objects, in that you can take the .gamepad property from a GamepadEvent or a Gamepad from navigator.getGamepads(), assign it to a variable, and check its state on every pass through the event loop to get the latest values of .buttons[]/.axes[]. Chrome uses snapshot Gamepad objects, so the Gamepad you get from navigator.getGamepads() is static, and you have to call getGamepads() on every pass through the event loop to get the latest state of the controller. I obviously have a bias towards what I've already implemented, but I can see the appeal of both approaches. With the live approach you can take a Gamepad object and assign it as a property of another object and use it that way, like player.input = gamepad, which makes it easy to manage Gamepad input as part of other code. With the snapshot approach you can easily save an old snapshot so that you can compare two snapshots and see what's changed. (Additionally as an implementation detail this maps very well to the Windows XInput API, which is a polling-based API.) Does anyone have any feedback on which of these seems more natural? Is there any precedent in the web platform to prefer one approach over the other? We just implemented gamepad entity live-ness in the dualshock-controller module for node. The discussion is here: https://github.com/rdepena/node-dualshock-controller/issues/27 Rick
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 1:45 PM, Brandon Jones bajo...@google.com wrote: On Tue Apr 29 2014 at 10:24:48 AM, Mark S. Miller erig...@google.com wrote: I don't know anything about Gamepad. Could someone provide enough context that I can understand the question? Thanks. The Gamepad API returns an array of Gamepad state objects when you call getGamepads(), like so: requestAnimationFrame(function() { var gamepads = navigator.getGamepads(); var playerGamepad = gamepads[0]; if (playerGamepad.buttons[0].pressed) { player.jump(); } } That code currently would work in both Firefox and Chrome. The Liveness question concerns the following code: var gamepads = navigator.getGamepads(); var playerGamepad = gamepads[0]; requestAnimationFrame(function() { if (playerGamepad.buttons[0].pressed) { player.jump(); } } In Firefox this code will be functionally equivalent to the first code snippet, since it continues to update the values Gamepad state object after you've acquired it. AKA: The object is live. In Chrome, however, the gamepad state returned is a snapshot and as such the second code snippet will not observe changes to the gamepad input. I'd prefer to be very wrong about this, but my immediate reaction to this is that it would be expensive to allocate these snapshot objects. Tell me where I'm misunderstanding: SnapShot 1. For each rAF turn: a. Let gp be a snapshot of gamepad b. Do stuff with one or more values from gp vs. Live 1. Let gp be gamepad 2. For each rAF turn: a. Do stuff with one or more values from gp The latter also follows the general model used in Node-based hardware programming/communication API designs. Rick The spec is currently ambiguous on the matter, so we want to clarify whether or not the second code snippet is valid or not and update the browser implementations accordingly. --Brandon On Tue, Apr 29, 2014 at 10:16 AM, Brendan Eich bren...@secure.meer.netwrote: Boris Zbarsky wrote: For what it's worth, the way Gecko implements this is by setting up that lifetime guarantee only when an expando is added to the object (or some other things, like use as a WeakMap key, happen). Until then we allow it to be GCed. What do other engines do in general? Unobservable GC is a requirement, if you ask me and Mark Miller. /be -- Cheers, --MarkM
Re: [Gamepad] Liveness of Gamepad objects
On 4/29/14, 1:46 PM, Mark S. Miller wrote: How would either make GC observable? Consider the following code: navigator.getGamepads()[0].foo = 5; var intervals = 0; var id = setInterval(function() { ++intervals; if (navigator.getGamepads()[0].foo != 5) { alert(What happened after + intervals + intervals?); clearInterval(id); } }, 1000); In Chrome's current implementation, where getGamepads() returns a new object each time getGamepads()[0] is a new object each time this will consistently alert What happened after 1 intervals?. In Firefox's current implementation this will not alert at all unless the set of connected gamepads changes. In an implementation which brokenly GCed and lazily recreated the JS reflections of Gamepad objects, the alert could happen after some random number of intervals, depending on GC timing. Does that help? -Boris
Re: [Gamepad] Liveness of Gamepad objects
On 4/29/2014 1:34 PM, Brandon Jones wrote: I don't think that API design should be driven by implementation details, but it may be useful to provide some background on Chrome's Gamepad implementation here: The current polling-only API Chrome uses is largely due to practicality with the multiprocess architecture. The gamepad data is acquired in the central browser process, placed in shared memory, and then polled by the tab processes when getGamepads() is called. This cuts down on a lot of IPC overhead that would otherwise result from constant Hey, Gamepad N changed! messages broadcast to all tabs. Given that, if we decide that the gamepad objects should be live and not snapshots I think that Chrome will probably put a system in place where the first access of a gamepad object property does a behind-the-scenes poll and then does not poll again until control has been given back to the browser. (Which is probably not an issue since many games will be processing input in a rAF loop.) I can't think of any scenario where a forced policy of one update per frame would be detrimental, but I'm open to feedback on the matter. I think what I'll wind up writing in the spec will describe the liveness in terms of tasks[1], which is how web specs talk about the event loop nowadays. Something like changes in the state of the gamepad should queue a task in the task queue to update the state of the Gamepad object. So your proposed implementation would match that exactly, which is nice. This is what we're already doing in Firefox, either by virtue of simply handling input on the main thread, or posting events from a background thread that's handling input. Performance-wise, I think this will wind up being functionally equivalent to your existing implementation anyway--assuming that content is polling navigator.getGamepads() in a rAF loop, you're going to be delivering one state update per frame anyway. If it were my call I'd vote for gamepad objects being snapshots simply because it will add some additional overhead to make them live and it avoid concerns about observing GC, but I don't really object to either design. Anne mentioned the observable GC concern, he said the spec should state that the lifetime of Gamepad objects is tied to the lifetime of the global, which isn't too terrible. (There aren't going to be a ton of them in play anyway.) I agree that having to make an architectural change like this sucks, I wish I had spec'ed it better from the beginning. I certainly don't want to enforce the Firefox implementation as correct just because it's mine, that's why I started this discussion. -Ted 1. http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#concept-task
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 11:07 AM, Boris Zbarsky bzbar...@mit.edu wrote: On 4/29/14, 1:46 PM, Mark S. Miller wrote: How would either make GC observable? Consider the following code: navigator.getGamepads()[0].foo = 5; var intervals = 0; var id = setInterval(function() { ++intervals; if (navigator.getGamepads()[0].foo != 5) { alert(What happened after + intervals + intervals?); clearInterval(id); } }, 1000); In Chrome's current implementation, where getGamepads() returns a new object each time getGamepads()[0] is a new object each time this will consistently alert What happened after 1 intervals?. In Firefox's current implementation this will not alert at all unless the set of connected gamepads changes. In an implementation which brokenly GCed and lazily recreated the JS reflections of Gamepad objects, the alert could happen after some random number of intervals, depending on GC timing. I see. Let's not do that then ;). Does that help? -Boris -- Cheers, --MarkM
Re: [Gamepad] Liveness of Gamepad objects
I think both semantics are workable. I'd likely prefer the gamepad state to be immutable from JS, because assigning state there is smelly. I'd also prefer the option that incurs less GC overhead if possible. Beyond that, I just think the implementations should be semantically and symbolically identical. On Tue, Apr 29, 2014 at 9:19 PM, Mark S. Miller erig...@google.com wrote: On Tue, Apr 29, 2014 at 11:07 AM, Boris Zbarsky bzbar...@mit.edu wrote: On 4/29/14, 1:46 PM, Mark S. Miller wrote: How would either make GC observable? Consider the following code: navigator.getGamepads()[0].foo = 5; var intervals = 0; var id = setInterval(function() { ++intervals; if (navigator.getGamepads()[0].foo != 5) { alert(What happened after + intervals + intervals?); clearInterval(id); } }, 1000); In Chrome's current implementation, where getGamepads() returns a new object each time getGamepads()[0] is a new object each time this will consistently alert What happened after 1 intervals?. In Firefox's current implementation this will not alert at all unless the set of connected gamepads changes. In an implementation which brokenly GCed and lazily recreated the JS reflections of Gamepad objects, the alert could happen after some random number of intervals, depending on GC timing. I see. Let's not do that then ;). Does that help? -Boris -- Cheers, --MarkM
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 3:27 PM, Florian Bösch pya...@gmail.com wrote: I think both semantics are workable. I'd likely prefer the gamepad state to be immutable from JS, because assigning state there is smelly. Yes, there should be no way for user code to directly alter the value of properties that represent the state of an entity in the physical world. A firm capabilities limitation policy is used throughout the Johnny-Five framework to enforce the immutability of such values (implemented as get-only accessors). Rick
Re: [Gamepad] Liveness of Gamepad objects
Gamepad objects should definitely be a snapshot. Otherwise, change events could only expose the most recent state of the gamepad. For example, if the user presses a button and then releases it very quickly (before the down press gets handled by script), and you fire two change events, the script would never see the buttons as pressed. (That said, I'm confused--where's the event to tell the user that the gamepad has changed? Surely this API doesn't require the developer to poll, which would lose inputs at the slightest GC skip and could never give high resolution timing.) I'd also be very surprised if I received a Gamepad object and its values were live--the interface looks like a snapshot. On Tue, Apr 29, 2014 at 9:39 AM, Ted Mielczarek t...@mozilla.com wrote: snapshots and see what's changed. (Additionally as an implementation detail this maps very well to the Windows XInput API, which is a polling-based API.) You can't just map a gamepad.xButton property to NativeInputAPI.getCurrentXButton(), because you need to guarantee that if you read the property twice in a row without returning to the event loop the result is always the same, even if the button state changes while the script is executing. You could prevent this by caching the result and clearing the cache when scripts aren't running, of course. On Tue, Apr 29, 2014 at 2:27 PM, Florian Bösch pya...@gmail.com wrote: I think both semantics are workable. I'd likely prefer the gamepad state to be immutable from JS, because assigning state there is smelly. I'd also prefer the option that incurs less GC overhead if possible. Beyond that, I just think the implementations should be semantically and symbolically identical. No, the object should be mutable, since most web API objects have mutable properties. If I want to do things like gamepadState = getGamepads()[0] // Run the input logic, but pretend the A button isn't pressed: gamepadState.aButton = false; checkInput(gamepadState); then I should be allowed to. There's nothing strange about this in a JS API. -- Glenn Maynard
RE: [Gamepad] Liveness of Gamepad objects
If it were my call I'd vote for gamepad objects being snapshots simply because it will add some additional overhead to make them live and it avoid concerns about observing GC, but I don't really object to either design. Anne mentioned the observable GC concern, he said the spec should state that the lifetime of Gamepad objects is tied to the lifetime of the global, which isn't too terrible. (There aren't going to be a ton of them in play anyway.) Originally I was leaning towards live model but I am now leaning towards a snapshot model being the better option. We also found that there was added overhead with making the values live. Having had a few developers play around with both the idea of a snapshot vs live I observed it was much easier for them to add the snapshot approach to their already published games. It also seemed easier for them to conceptual grab the concept I guess because it seemed like a more natural model that fit with their games where at each frame they grab the snapshot to modify that frame then repeat.
Re: [Gamepad] Liveness of Gamepad objects
On Tue Apr 29 2014 at 4:28:31 PM, Glenn Maynard gl...@zewt.org wrote: (That said, I'm confused--where's the event to tell the user that the gamepad has changed? Surely this API doesn't require the developer to poll, which would lose inputs at the slightest GC skip and could never give high resolution timing.) This is slightly off topic, but worth addressing. The spec does not, in fact, have any change notifications. Firefox has some experimental ones you can enable but they're not official. This does indeed provide an opportunity for input loss, but I'm not aware of anyone who's actually found it to be a problem. (Given the sparse number of apps using the API, though, that doesn't say much.) This is good feedback, though. It may be that snapshot + change events is the most effective way to go? No, the object should be mutable, since most web API objects have mutable properties. If I want to do things like gamepadState = getGamepads()[0] // Run the input logic, but pretend the A button isn't pressed: gamepadState.aButton = false; checkInput(gamepadState); then I should be allowed to. There's nothing strange about this in a JS API. No complaints here. A good use-case for mutable properties may be a JS script that intercepts gamepad snapshots and re-maps them in-place to a standard mapping if the browser has not already done so.
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 6:42 PM, Brandon Jones bajo...@google.com wrote: On Tue Apr 29 2014 at 4:28:31 PM, Glenn Maynard gl...@zewt.org wrote: (That said, I'm confused--where's the event to tell the user that the gamepad has changed? Surely this API doesn't require the developer to poll, which would lose inputs at the slightest GC skip and could never give high resolution timing.) This is slightly off topic, but worth addressing. The spec does not, in fact, have any change notifications. Firefox has some experimental ones you can enable but they're not official. This does indeed provide an opportunity for input loss, but I'm not aware of anyone who's actually found it to be a problem. (Given the sparse number of apps using the API, though, that doesn't say much.) Using snapshots makes it easier to add this later, even if it's not done right away, since you just stash a snapshot in each event when you create it. I think not having change events assumed that everyone using gamepads will have a requestAnimationFrame loop running, but not everything that might use gamepads is a game. Regular web pages can also use gamepads, eg. for navigating menus. -- Glenn Maynard
Re: [Gamepad] Liveness of Gamepad objects
On 4/29/2014 7:28 PM, Glenn Maynard wrote: Gamepad objects should definitely be a snapshot. Otherwise, change events could only expose the most recent state of the gamepad. For example, if the user presses a button and then releases it very quickly (before the down press gets handled by script), and you fire two change events, the script would never see the buttons as pressed. This is a good point--if we have live objects then if we do implement change events we'd need to store the state elsewhere. Firefox has gamepadbutton{press,release} events and gamepadaxismove events[1][2] (behind a pref), they actually do this already but it's not fantastic. (That said, I'm confused--where's the event to tell the user that the gamepad has changed? Surely this API doesn't require the developer to poll, which would lose inputs at the slightest GC skip and could never give high resolution timing.) My original prototype provided the events mentioned above. The feedback I received was overwhelmingly in favor of a polling API instead[3]. I decided to go ahead with that (actually Scott beat me to the punch and implemented that in Chrome first), figuring we could always spec events in a future revision. I'd also be very surprised if I received a Gamepad object and its values were live--the interface looks like a snapshot. The interface is...not incredibly consistent because I designed some of it with the live object model in mind and Scott designed some of it with the snapshot model in mind. On Tue, Apr 29, 2014 at 9:39 AM, Ted Mielczarek t...@mozilla.com mailto:t...@mozilla.com wrote: snapshots and see what's changed. (Additionally as an implementation detail this maps very well to the Windows XInput API, which is a polling-based API.) You can't just map a gamepad.xButton property to NativeInputAPI.getCurrentXButton(), because you need to guarantee that if you read the property twice in a row without returning to the event loop the result is always the same, even if the button state changes while the script is executing. You could prevent this by caching the result and clearing the cache when scripts aren't running, of course. I meant mapping navigator.getGamepads to a poll of XInput and returning the result for each gamepad there, not polling on each access of .buttons/.axes. -Ted 1. http://mxr.mozilla.org/mozilla-central/source/dom/webidl/GamepadButtonEvent.webidl 2. http://mxr.mozilla.org/mozilla-central/source/dom/webidl/GamepadAxisMoveEvent.webidl 3. https://bugzilla.mozilla.org/show_bug.cgi?id=604039
Re: [Gamepad] Liveness of Gamepad objects
On 4/29/2014 7:35 PM, Oren Freiberg wrote: Originally I was leaning towards live model but I am now leaning towards a snapshot model being the better option. We also found that there was added overhead with making the values live. Having had a few developers play around with both the idea of a snapshot vs live I observed it was much easier for them to add the snapshot approach to their already published games. It also seemed easier for them to conceptual grab the concept I guess because it seemed like a more natural model that fit with their games where at each frame they grab the snapshot to modify that frame then repeat. This is good feedback, thanks. Currently due to the implementation difference users are forced to consume the API as if it was providing snapshots anyway if they want their code to work in Chrome, so settling on a snapshot model would simply codify that existing behavior. We risk breaking content that has special-cased Firefox's behavior or only works in Firefox, I suppose, but the API doesn't have much surface area and hasn't been around that long so that doesn't actually seem all that bad. -Ted
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 7:28 PM, Glenn Maynard gl...@zewt.org wrote: Gamepad objects should definitely be a snapshot. Otherwise, change events could only expose the most recent state of the gamepad. For example, if the user presses a button and then releases it very quickly (before the down press gets handled by script), and you fire two change events, the script would never see the buttons as pressed. The previously node-dualshock-controller API, emits change events from the live object. The change event delivers the state of the actual change. A user might quickly press button A and the listener for A does whatever updating it must do in the program and has access to both the change state and the current live state of the object. Rick
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 9:38 PM, Rick Waldron waldron.r...@gmail.comwrote: On Tue, Apr 29, 2014 at 7:28 PM, Glenn Maynard gl...@zewt.org wrote: Gamepad objects should definitely be a snapshot. Otherwise, change events could only expose the most recent state of the gamepad. For example, if the user presses a button and then releases it very quickly (before the down press gets handled by script), and you fire two change events, the script would never see the buttons as pressed. The previously node-dualshock-controller API, emits change events from the live object. The change event delivers the state of the actual change. A user might quickly press button A and the listener for A does whatever updating it must do in the program and has access to both the change state and the current live state of the object. The node-xbox-controller module also follows this design. Rick
Re: [Gamepad] Liveness of Gamepad objects
On Tue, Apr 29, 2014 at 8:25 PM, Ted Mielczarek t...@mozilla.com wrote: On 4/29/2014 7:28 PM, Glenn Maynard wrote: Gamepad objects should definitely be a snapshot. Otherwise, change events could only expose the most recent state of the gamepad. For example, if the user presses a button and then releases it very quickly (before the down press gets handled by script), and you fire two change events, the script would never see the buttons as pressed. This is a good point--if we have live objects then if we do implement change events we'd need to store the state elsewhere. Firefox has gamepadbutton{press,release} events and gamepadaxismove events[1][2] (behind a pref), they actually do this already but it's not fantastic. There should simply be a change event, which is fired when any property changes. (Some rate clamping might be needed for analog inputs, which could change very quickly, but that's an implementation detail.) My original prototype provided the events mentioned above. The feedback I received was overwhelmingly in favor of a polling API instead[3]. I decided to go ahead with that (actually Scott beat me to the punch and implemented that in Chrome first), figuring we could always spec events in a future revision. (Please try to direct conversations here or to the whatwg list, so everyone has a chance to participate...) Supporting polling is a separate issue from whether the Gamepad interface is live or a snapshot. You definitely want to be able to retrieve a snapshot of the current state, and as long as you can do that you automatically support polling. That is, users can either use polling: onRequestAnimationFrame = function() { // Once we create this, it never changes, so we can compare it the next time around when it becomes lastGamepadState. var gamepadState = navigator.getGamepads(); // Find differences between lastGamepadState and gamepadState and act on them: for(var i = 0; i gamepadState.length; ++i) processInput(gamepadState[i], lastGamepadState[i]); // Save the current state, for comparison during the next frame. lastGamepadState = gamepadState; } or events: navigator.onGamepadChange = function(e) { var gamepadState = e.state; processInput(e.gamepadIndex, gamepadState, lastGamepadState); lastGamepadState[e.gamepadIndex] = gamepadState; } In either case, gamepadState is a static snapshot. (Aside: I'm not sure if the top one is correct. Does getGamepads()[n].index == n, so that gamepadState[i] always corresponds to lastGamepadState[i]? The spec suggests that with index of the gamepad in the Navigator, but I'm not sure. If so, what is getGamepads()[1] if controller index 1 is disconnected, since you can't reorder the later items? undefined?) -- Glenn Maynard