phaser/src/input/keyboard/KeyboardManager.js
2018-04-06 18:17:58 +01:00

442 lines
11 KiB
JavaScript

/**
* @author Richard Davey <rich@photonstorm.com>
* @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');
/**
* @callback KeyboardHandler
*
* @property {KeyboardEvent} event - [description]
*/
/**
* @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 Phaser.Events.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 {?KeyboardHandler}
* @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);
},
/**
* @typedef {object} CursorKeys
*
* @property {Phaser.Input.Keyboard.Key} [up] - [description]
* @property {Phaser.Input.Keyboard.Key} [down] - [description]
* @property {Phaser.Input.Keyboard.Key} [left] - [description]
* @property {Phaser.Input.Keyboard.Key} [right] - [description]
* @property {Phaser.Input.Keyboard.Key} [space] - [description]
* @property {Phaser.Input.Keyboard.Key} [shift] - [description]
*/
/**
* 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 {CursorKeys} [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.Input.Keyboard.KeyCodes.W, 'down': Phaser.Input.Keyboard.KeyCodes.S });
*
* would return an object containing properties (`up` and `down`) referring to {@link Phaser.Input.Keyboard.Key} objects.
*
* @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 {KeyComboConfig} 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;