/** * @author Richard Davey * @copyright 2018 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ var Class = require('../../utils/Class'); var EventEmitter = require('eventemitter3'); var Gamepad = require('./Gamepad'); // https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API // https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API // https://www.smashingmagazine.com/2015/11/gamepad-api-in-web-games/ // http://html5gamepad.com/ /** * @typedef {object} Pad * * @property {string} id - [description] * @property {integer} index - [description] */ /** * @callback GamepadHandler * * @property {GamepadEvent} event - [description] */ /** * @classdesc * [description] * * @class GamepadManager * @extends Phaser.Events.EventEmitter * @memberOf Phaser.Input.Gamepad * @constructor * @since 3.0.0 * * @param {Phaser.Input.InputManager} inputManager - [description] */ var GamepadManager = new Class({ Extends: EventEmitter, initialize: function GamepadManager (inputManager) { EventEmitter.call(this); /** * [description] * * @name Phaser.Input.Gamepad.GamepadManager#manager * @type {Phaser.Input.InputManager} * @since 3.0.0 */ this.manager = inputManager; /** * [description] * * @name Phaser.Input.Gamepad.GamepadManager#enabled * @type {boolean} * @default false * @since 3.0.0 */ this.enabled = false; /** * [description] * * @name Phaser.Input.Gamepad.GamepadManager#target * @type {?object} * @since 3.0.0 */ this.target; /** * [description] * * @name Phaser.Input.Gamepad.GamepadManager#handler * @type {?GamepadHandler} * @since 3.0.0 */ this.handler; /** * [description] * * @name Phaser.Input.Gamepad.GamepadManager#gamepads * @type {Phaser.Input.Gamepad.Gamepad[]} * @default [] * @since 3.0.0 */ this.gamepads = []; /** * Standard FIFO queue. * * @name Phaser.Input.Gamepad.GamepadManager#queue * @type {GamepadEvent[]} * @default [] * @since 3.0.0 */ this.queue = []; }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#boot * @since 3.0.0 */ boot: function () { var config = this.manager.config; this.enabled = config.inputGamepad && this.manager.game.device.input.gamepads; this.target = window; if (this.enabled) { this.startListeners(); } }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#startListeners * @since 3.0.0 */ startListeners: function () { var queue = this.queue; var handler = function handler (event) { if (event.defaultPrevented) { // Do nothing if event already handled return; } queue.push(event); }; this.handler = handler; var target = this.target; target.addEventListener('gamepadconnected', handler, false); target.addEventListener('gamepaddisconnected', handler, false); // FF only for now: target.addEventListener('gamepadbuttondown', handler, false); target.addEventListener('gamepadbuttonup', handler, false); target.addEventListener('gamepadaxismove', handler, false); }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#stopListeners * @since 3.0.0 */ stopListeners: function () { var target = this.target; var handler = this.handler; target.removeEventListener('gamepadconnected', handler); target.removeEventListener('gamepaddisconnected', handler); target.removeEventListener('gamepadbuttondown', handler); target.removeEventListener('gamepadbuttonup', handler); target.removeEventListener('gamepadaxismove', handler); }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#disconnectAll * @since 3.0.0 */ disconnectAll: function () { for (var i = 0; i < this.gamepads.length; i++) { this.gamepads.connected = false; } }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#addPad * @since 3.0.0 * * @param {Pad} pad - [description] * * @return {Phaser.Input.Gamepad.Gamepad} [description] */ addPad: function (pad) { var gamepad = new Gamepad(this, pad.id, pad.index); this.gamepads[pad.index] = gamepad; return gamepad; }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#removePad * @since 3.0.0 * @todo Code this feature * * @param {number} index - [description] * @param {Pad} pad - [description] */ removePad: function () { // TODO }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#refreshPads * @since 3.0.0 * * @param {Pad[]} pads - [description] */ refreshPads: function (pads) { if (!pads) { this.disconnectAll(); } else { for (var i = 0; i < pads.length; i++) { var pad = pads[i]; if (!pad) { // removePad? continue; } if (this.gamepads[pad.index] === undefined) { this.addPad(pad); } this.gamepads[pad.index].update(pad); } } }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#getAll * @since 3.0.0 * * @return {Phaser.Input.Gamepad.Gamepad[]} [description] */ getAll: function () { var out = []; for (var i = 0; i < this.gamepads.length; i++) { if (this.gamepads[i]) { out.push(this.gamepads[i]); } } return out; }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#getPad * @since 3.0.0 * * @param {number} index - [description] * * @return {Phaser.Input.Gamepad.Gamepad} [description] */ getPad: function (index) { for (var i = 0; i < this.gamepads.length; i++) { if (this.gamepads[i].index === index) { return this.gamepads[i]; } } }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#update * @since 3.0.0 */ update: function () { if (!this.enabled) { return; } this.refreshPads(navigator.getGamepads()); var len = this.queue.length; if (len === 0) { return; } var queue = this.queue.splice(0, len); // Process the event queue, dispatching all of the events that have stored up for (var i = 0; i < len; i++) { var event = queue[i]; var pad; switch (event.type) { case 'gamepadconnected': pad = this.getPad(event.gamepad.index); this.emit('connected', pad, event); break; case 'gamepaddisconnected': pad = this.getPad(event.gamepad.index); this.emit('disconnected', pad, event); break; } } }, /** * [description] * * @method Phaser.Input.Gamepad.GamepadManager#destroy * @since 3.0.0 */ destroy: function () { this.stopListeners(); this.disconnectAll(); this.gamepads = []; }, /** * The total number of connected game pads. * * @name Phaser.Input.Gamepad.GamepadManager#total * @type {number} * @since 3.0.0 */ total: { get: function () { return this.gamepads.length; } } }); module.exports = GamepadManager;