import EventEmitter from "../../common/events/EventEmitter.js";
/**
* Keyboard Input Wrapper
*
* To detect if a key is pressed, we use [KeyboardEvent.code](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code), since `which`, `keyCode` and `charCode` are deprecated.
* `e.key` would be another option but `e.key` could be "z" in german and english, no matter which layout but "я" in russian.
*
* `e.code` represents the physical key on the keyboard, **NOT** the charcode generated by the event!
*
* > For example, the code returned is "KeyQ" for the `Q` key on a QWERTY layout keyboard, but the same code value also represents the `'` key on Dvorak keyboards and the `A` key on AZERTY keyboards. That makes it impossible to use the value of code to determine what the name of the key is to users if they're not using an anticipated keyboard layout.
*
* Getting the string associated to a physical key might be possible in the future using [Keyboard.getLayoutMap()](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/getLayoutMap) but this is experimental technology.
*
* **Your game should not care about which character the keypress would have caused**, your game should translate from physical key to in-game action
* and let the user decide which physical key the want for that action via a settings page.
*
* Choosing a reasonable default could be a QWERTY layout keyboard while avoiding keys like y and z, but in the end you do not know what kind of input device the user actually has.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
*/
class Keyboard extends EventEmitter {
constructor() {
super();
this.pressed = new Map();
this.active = true;
// create callback to bind/unbind keyboard events
var self = this;
this._onKeyDown = function(event) {
self._onKeyChange(event, true);
};
this._onKeyUp = function(event) {
self._onKeyChange(event, false);
};
// bind keyEvents
document.addEventListener("keydown", this._onKeyDown, false);
document.addEventListener("keyup", this._onKeyUp, false);
}
/**
* unbind the keydown / keyup events
*/
destroy() {
// unbind keyEvents
document.removeEventListener("keydown", this._onKeyDown, false);
document.removeEventListener("keyup", this._onKeyUp, false);
}
_onKeyChange(event, pressed) {
let e = {
pressed: pressed,
time: Date.now(),
};
this.pressed.set(event.code, e);
/**
* Keydown event.
*
* @event Keyboard#down
* @property {Boolean} pressed - Indicates whether the key is pressed or not
* @property {Number} time - Indicates when the keypress occured
*/
/**
* Keyup event.
*
* @event Keyboard#up
* @property {Boolean} pressed - Indicates whether the key is pressed or not
* @property {Number} time - Indicates when the keypress occured
*/
this.emit(pressed ? "down" : "up", Object.assign({
originalEvent: event
}, e))
}
/**
* query keyboard state to know if a key is pressed of not
*
* @param {String} code the description of the key. format : modifiers+key e.g shift+A
* @returns {Integer} Millisecond timestamp of the time it was last pressed or released
*/
time(code) {
return this.pressed.has(code) ? this.pressed.get(code).time : 0;
}
/**
* query keyboard state to know if a key is pressed of not
*
* @param {String|Array} code single keycode or array of keycodes
* @returns {Boolean} true if the key is pressed, false otherwise
*/
isPressed(code) {
var keys = Array.isArray(code) ? code : [code];
for (var i = 0; i < keys.length; i++) {
var code = keys[i];
if (!this.pressed.has(code) || !this.pressed.get(code).pressed) return false;
}
return true;
}
getCurrentlyPressed() {
let pressed = [];
this.pressed.forEach((p, code) => {
if (p.pressed) pressed.push({
code,
time: p.time
})
});
pressed.sort((a, b) => b.time - a.time);
return pressed;
}
}
export default Keyboard;