/** * @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 Key = require('./keys/Key'); var KeyCodes = require('./keys/KeyCodes'); var KeyCombo = require('./combo/KeyCombo'); var KeyMap = require('./keys/KeyMap'); var ProcessKeyDown = require('./keys/ProcessKeyDown'); var ProcessKeyUp = require('./keys/ProcessKeyUp'); /** * @classdesc * The Keyboard class monitors keyboard input and dispatches keyboard events. * * _Note_: many keyboards are unable to process certain combinations of keys due to hardware limitations known as ghosting. * See http://www.html5gamedevs.com/topic/4876-impossible-to-use-more-than-2-keyboard-input-buttons-at-the-same-time/ for more details. * * Also please be aware that certain browser extensions can disable or override Phaser keyboard handling. * For example the Chrome extension vimium is known to disable Phaser from using the D key. And there are others. * So please check your extensions before opening Phaser issues. * * @class KeyboardManager * @extends EventEmitter * @memberOf Phaser.Input.Keyboard * @constructor * @since 3.0.0 * * @param {Phaser.Input.InputManager} inputManager - [description] */ var KeyboardManager = new Class({ Extends: EventEmitter, initialize: function KeyboardManager (inputManager) { EventEmitter.call(this); /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#manager * @type {Phaser.Input.InputManager} * @since 3.0.0 */ this.manager = inputManager; /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#enabled * @type {boolean} * @default false * @since 3.0.0 */ this.enabled = false; /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#target * @type {?object} * @since 3.0.0 */ this.target; /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#keys * @type {Phaser.Input.Keyboard.Key[]} * @default [] * @since 3.0.0 */ this.keys = []; /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#combos * @type {Phaser.Input.Keyboard.KeyCombo[]} * @default [] * @since 3.0.0 */ this.combos = []; /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#captures * @type {array} * @default [] * @since 3.0.0 */ this.captures = []; /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#queue * @type {KeyboardEvent[]} * @default [] * @since 3.0.0 */ this.queue = []; /** * [description] * * @name Phaser.Input.Keyboard.KeyboardManager#handler * @type {?function} * @since 3.0.0 */ this.handler; }, /** * The Boot handler is called by Phaser.Game when it first starts up. * * @method Phaser.Input.Keyboard.KeyboardManager#boot * @since 3.0.0 */ boot: function () { var config = this.manager.config; this.enabled = config.inputKeyboard; this.target = config.inputKeyboardEventTarget; if (this.enabled) { this.startListeners(); } }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#startListeners * @since 3.0.0 */ startListeners: function () { var queue = this.queue; var captures = this.captures; var handler = function (event) { if (event.defaultPrevented) { // Do nothing if event already handled return; } queue.push(event); if (captures[event.keyCode]) { event.preventDefault(); } }; this.handler = handler; this.target.addEventListener('keydown', handler, false); this.target.addEventListener('keyup', handler, false); }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#stopListeners * @since 3.0.0 */ stopListeners: function () { this.target.removeEventListener('keydown', this.handler); this.target.removeEventListener('keyup', this.handler); }, /** * Creates and returns an object containing 4 hotkeys for Up, Down, Left and Right, and also space and shift. * * @method Phaser.Input.Keyboard.KeyboardManager#createCursorKeys * @since 3.0.0 * * @return {object} [description] */ createCursorKeys: function () { return this.addKeys({ up: KeyCodes.UP, down: KeyCodes.DOWN, left: KeyCodes.LEFT, right: KeyCodes.RIGHT, space: KeyCodes.SPACE, shift: KeyCodes.SHIFT }); }, /** * A practical way to create an object containing user selected hotkeys. * * For example, * * addKeys( { 'up': Phaser.KeyCode.W, 'down': Phaser.KeyCode.S, 'left': Phaser.KeyCode.A, 'right': Phaser.KeyCode.D } ); * * would return an object containing properties (`up`, `down`, `left` and `right`) referring to {@link Phaser.Key} object. * * @method Phaser.Input.Keyboard.KeyboardManager#addKeys * @since 3.0.0 * * @param {object} keys - [description] * * @return {object} [description] */ addKeys: function (keys) { var output = {}; for (var key in keys) { output[key] = this.addKey(keys[key]); } return output; }, /** * If you need more fine-grained control over a Key you can create a new Phaser.Key object via this method. * The Key object can then be polled, have events attached to it, etc. * * @method Phaser.Input.Keyboard.KeyboardManager#addKey * @since 3.0.0 * * @param {string|integer} keyCode - [description] * * @return {Phaser.Input.Keyboard.Key} [description] */ addKey: function (keyCode) { var keys = this.keys; if (!keys[keyCode]) { keys[keyCode] = new Key(keyCode); this.captures[keyCode] = true; } return keys[keyCode]; }, /** * Removes a Key object from the Keyboard manager. * * @method Phaser.Input.Keyboard.KeyboardManager#removeKey * @since 3.0.0 * * @param {string|integer} keyCode - [description] */ removeKey: function (keyCode) { if (this.keys[keyCode]) { this.keys[keyCode] = undefined; this.captures[keyCode] = false; } }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#addKeyCapture * @since 3.0.0 * * @param {string|integer|string[]|integer[]} keyCodes - [description] */ addKeyCapture: function (keyCodes) { if (!Array.isArray(keyCodes)) { keyCodes = [ keyCodes ]; } for (var i = 0; i < keyCodes.length; i++) { this.captures[keyCodes[i]] = true; } }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#removeKeyCapture * @since 3.0.0 * * @param {string|integer|string[]|integer[]} keyCodes - [description] */ removeKeyCapture: function (keyCodes) { if (!Array.isArray(keyCodes)) { keyCodes = [ keyCodes ]; } for (var i = 0; i < keyCodes.length; i++) { this.captures[keyCodes[i]] = false; } }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#createCombo * @since 3.0.0 * * @param {string|integer[]|object[]} keys - [description] * @param {object} config - [description] * * @return {Phaser.Input.Keyboard.KeyCombo} [description] */ createCombo: function (keys, config) { return new KeyCombo(this, keys, config); }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#update * @since 3.0.0 */ update: function () { var len = this.queue.length; if (!this.enabled || len === 0) { return; } // Clears the queue array, and also means we don't work on array data that could potentially // be modified during the processing phase var queue = this.queue.splice(0, len); var keys = this.keys; // 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 code = event.keyCode; if (event.type === 'keydown') { if (KeyMap[code] && (keys[code] === undefined || keys[code].isDown === false)) { // Will emit a keyboard or keyup event this.emit(event.type, event); this.emit('keydown_' + KeyMap[code], event); } if (keys[code]) { ProcessKeyDown(keys[code], event); } } else { // Will emit a keyboard or keyup event this.emit(event.type, event); this.emit('keyup_' + KeyMap[code], event); if (keys[code]) { ProcessKeyUp(keys[code], event); } } } }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#shutdown * @since 3.0.0 */ shutdown: function () { this.removeAllListeners(); }, /** * [description] * * @method Phaser.Input.Keyboard.KeyboardManager#destroy * @since 3.0.0 */ destroy: function () { this.stopListeners(); this.removeAllListeners(); this.keys = []; this.combos = []; this.captures = []; this.queue = []; this.handler = undefined; this.manager = null; } }); module.exports = KeyboardManager;