const System = require('engine/system'); const keyboard = require('./keyboard'); const { removeItems } = require('engine/utils/array'); /** * Input system which provides key bindings. * @class SystemInput */ class SystemInput extends System { /** * @constructor */ constructor() { super(); this.name = 'Input'; this.bindings = {}; this.keyList = []; this.actions = {}; this.lastPressed = {}; this.lastReleased = {}; } /** * Bind a key to a specific action. * @memberof SystemInput# * @method bind * @param {String} key Key to bind * @param {String} action Action name * @return {SystemInput} Self for chaining */ bind(key, action) { if (Array.isArray(this.bindings[key])) { this.bindings[key].push(action); } else { this.bindings[key] = [action]; } if (this.keyList.indexOf(key) < 0) { this.keyList.push(key); } this.lastPressed[action] = false; this.lastReleased[action] = false; return this; } /** * Unbind an action from a key. * @memberof SystemInput# * @method unbind * @param {String} key Key to unbind * @param {String} action Action to unbind * @return {SystemInput} Self for chaining */ unbind(key, action) { if (Array.isArray(this.bindings[key])) { let idx = this.bindings[key].indexOf(action); if (idx >= 0) { removeItems(this.bindings[key], idx, 1); } delete this.lastPressed[action]; delete this.lastReleased[action]; } return this; } /** * Unbind all the actions. * @memberof SystemInput# * @method unbindAll */ unbindAll() { for (let k in this.bindings) { if (Array.isArray(this.bindings[k])) { this.bindings[k].length = 0; } } this.lastPressed = {}; this.lastReleased = {}; } /** * Whether an action is currently pressed. * @memberof SystemInput# * @method state * @param {String} action Action name * @return {Boolean} Pressed or not */ state(action) { return !!this.actions[action]; } /** * Whether an action is just pressed. * @memberof SystemInput# * @method pressed * @param {String} action Action name * @return {Boolean} Pressed or not */ pressed(action) { return !!this.lastPressed[action]; } /** * Whether an action is just released. * @memberof SystemInput# * @method released * @param {String} action Action name * @return {Boolean} Released or not */ released(action) { return !!this.lastReleased[action]; } /** * Awake callback. * @memberof SystemInput# * @method awake * @private */ awake() { keyboard.on('keydown', this.keydown, this); keyboard.on('keyup', this.keyup, this); this.resetFlags(); } /** * Fixed update callback. * @memberof SystemInput# * @method fixedUpdate * @private */ fixedUpdate() { // Mark press/release action as false this.resetFlags(); } /** * Freeze callback. * @memberof SystemInput# * @method freeze * @private */ freeze() { keyboard.off('keydown', this.keydown, this); keyboard.off('keyup', this.keyup, this); this.resetFlags(); } /** * Key down listener * @memberof SystemInput# * @method keydown * @param {String} k Name of the key * @private */ keydown(k) { if (this.keyList.indexOf(k) !== -1) { let i, list = this.bindings[k]; for (i = 0; i < list.length; i++) { this.actions[list[i]] = true; this.lastPressed[list[i]] = true; } } } /** * Key up listener * @memberof SystemInput# * @method keyup * @param {String} k Name of the key * @private */ keyup(k) { if (this.keyList.indexOf(k) !== -1) { let i, list = this.bindings[k]; for (i = 0; i < list.length; i++) { this.actions[list[i]] = false; this.lastReleased[list[i]] = true; } } } /** * Reset press and release flags. * @memberof SystemInput# * @method resetFlags * @private */ resetFlags() { let k; for (k in this.lastPressed) { this.lastPressed[k] = false; } for (k in this.lastReleased) { this.lastReleased[k] = false; } } } module.exports = SystemInput;