import { ManualInput } from 'virtjs/devices/inputs/ManualInput'; let DEFAULT_KEY_MAP = { /* eslint-disable no-magic-numbers */ 37: [ 0, `LEFT` ], // arrow left 39: [ 0, `RIGHT` ], // arrow right 38: [ 0, `UP` ], // arrow up 40: [ 0, `DOWN` ], // arrow down 65: [ 0, `A` ], // 'A' 81: [ 0, `A` ], // 'Q' 90: [ 0, `B` ], // 'Z' 87: [ 0, `B` ], // 'W' 66: [ 0, `B` ], // 'B' 76: [ 0, `L` ], // 'L' 82: [ 0, `R` ], // 'R' 13: [ 0, `START` ], // enter 8: [ 0, `SELECT` ], // backspace 32: [ 0, `SELECT` ] // space /* eslint-enable no-magic-numbers */ }; export class KeyboardInput { /** * A KeyboardInput is an input device that will monitor the keystrokes on a specified DOM element and transmit those actions to the engines. * * @constructor * @implements {Input} * * @param {object} [options] - The device options. * @param {Element} [options.element] - The element on which will be bound the DOM listeners. * @param {KeyMap} [options.keyMap] - The initial key map. */ constructor({ element = document.body, keyMap = DEFAULT_KEY_MAP, inputMap = null } = {}) { /** * This value contains the element on which the DOM listeners have been bound. * * @member * @readonly * @type {Element} */ this.element = null; /** * This value contains the current key map used to filter keys. * * @member * @readonly * @type {KeyMap} */ this.keyMap = null; this.input = new ManualInput({ inputMap }); this.onKeyDown = this.onKeyDown.bind(this); this.onKeyUp = this.onKeyUp.bind(this); this.setKeyMap(keyMap); this.setElement(element); } /** * Change the element on which are bound the DOM listeners. */ setElement(element) { if (element === this.element) return; if (this.element !== null) this.detachEvents(); this.element = element; if (this.element !== null) { this.attachEvents(); } } /** * Set the key map that will be used to translate key codes into inputs. * * Any old key that doesn't map to the same input anymore will be automatically released. * * @param {KeyMap} keyMap - The new key map. */ setKeyMap(keyMap) { if (keyMap === this.keyMap) return; if (this.keyMap) { for (let key of Reflect.ownKeys(this.keyMap)) { let [ port, code ] = this.keyMap[key]; if (keyMap && Reflect.has(keyMap, key) && keyMap[key][0] === port && keyMap[key][1] === code) continue; this.input.up(port, code); } } this.keyMap = keyMap; } /** * @borrows ManualInput#setCodeMap as KeyboardInput#setCodeMap */ setCodeMap(codeMap) { this.input.setCodeMap(codeMap); } pollInputs() { this.input.pollInputs(); } getState(port, code) { return this.input.getState(port, code); } attachEvents() { this.element.addEventListener(`keydown`, this.onKeyDown); this.element.addEventListener(`keyup`, this.onKeyUp); } detachEvents() { this.element.removeEventListener(`keydown`, this.onKeyDown); this.element.removeEventListener(`keyup`, this.onKeyUp); } onKeyDown(e) { if ([ `select`, `input`, `textarea` ].includes(e.target.tagName.toLowerCase())) return; if (e.keyCode === 8 /* backspace */) // eslint-disable-line no-magic-numbers e.preventDefault(); if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return; if (!Reflect.has(this.keyMap, e.keyCode)) return; e.preventDefault(); let [ port, code ] = this.keyMap[e.keyCode]; this.input.down(port, code); } onKeyUp(e) { if (!Reflect.has(this.keyMap, e.keyCode)) return; let [ port, code ] = this.keyMap[e.keyCode]; this.input.up(port, code); } }