input/KeyboardHandler.tstypescript
import { input } from "./input";
import { stamp } from "../utils/shared";
import type { EventCallback, EventCallbackStamp } from "../Events";
const STAMP_SPACER = "_";
interface ICallbackHandler {
callback: EventCallbackStamp;
sender: any;
priority: number;
}
const _sortByPriority = function (a: ICallbackHandler, b: ICallbackHandler): number {
return Number(a.priority < b.priority);
};
class KeyboardHandler {
protected _currentlyPressedKeys: Record<number, boolean>;
protected _pressedKeysCallbacks: Record<number, ICallbackHandler[]>;
protected _unpressedKeysCallbacks: Record<number, ICallbackHandler[]>;
protected _charkeysCallbacks: Record<number, ICallbackHandler[]>;
protected _anykeyCallback: any;
protected _event: KeyboardEvent | null;
protected _active: boolean;
protected _stampCache: Record<string, number>;
public onKeyEvent: ((event: KeyboardEvent) => void) | null = null;
constructor() {
this._currentlyPressedKeys = {};
this._pressedKeysCallbacks = {};
this._unpressedKeysCallbacks = {};
this._charkeysCallbacks = {};
this._anykeyCallback = null;
this._event = null;
this._active = true;
this._stampCache = {};
document.addEventListener("keydown", this._onDocumentKeyDown);
document.addEventListener("keyup", this._onDocumentKeyUp);
}
protected _onDocumentKeyDown = (event: KeyboardEvent) => {
this._event = event;
this.onKeyEvent && this.onKeyEvent(event);
this._active && this.handleKeyDown();
};
protected _onDocumentKeyUp = (event: KeyboardEvent) => {
this._event = event;
this.onKeyEvent && this.onKeyEvent(event);
this._active && this.handleKeyUp();
};
public destroy(): void {
document.removeEventListener("keydown", this._onDocumentKeyDown);
document.removeEventListener("keyup", this._onDocumentKeyUp);
this._currentlyPressedKeys = {};
this._pressedKeysCallbacks = {};
this._unpressedKeysCallbacks = {};
this._charkeysCallbacks = {};
this._anykeyCallback = null;
this._event = null;
this._stampCache = {};
}
public getcurrentlyPressedKeys(): Record<number, boolean> {
return this._currentlyPressedKeys;
}
public getPressedKeysCallbacks() {
return this._pressedKeysCallbacks;
}
public getUnpressedKeysCallbacks() {
return this._unpressedKeysCallbacks;
}
public getCharkeysCallbacks() {
return this._charkeysCallbacks;
}
public removeEvent(event: string, keyCode: number, callback: EventCallback) {
let st = this._getStamp(event, keyCode, (callback as EventCallbackStamp)._openglobus_id!);
if ((callback as EventCallbackStamp)._openglobus_id && this._stampCache[st]) {
//this._stampCache[st] = null;
delete this._stampCache[st];
if (event === "keypress") {
this._removeCallback(this._pressedKeysCallbacks[keyCode], callback);
} else if (event === "keyfree") {
this._removeCallback(this._unpressedKeysCallbacks[keyCode], callback);
} else if (event === "charkeypress") {
this._removeCallback(this._charkeysCallbacks[keyCode], callback);
}
}
}
protected _removeCallback(handlers: ICallbackHandler[] | undefined, callback: EventCallbackStamp) {
if (!handlers) return;
for (let i = 0; i < handlers.length; i++) {
if (handlers[i].callback._openglobus_id === callback._openglobus_id) {
handlers.splice(i, 1);
}
}
}
protected _getStamp(name: string, keyCode: number, ogid: number) {
return `${name}${STAMP_SPACER}${keyCode}${STAMP_SPACER}${ogid}`;
}
protected _stamp(name: string, keyCode: number, obj: any) {
const ogid = stamp(obj);
const st = this._getStamp(name, keyCode, ogid);
if (!this._stampCache[st]) {
this._stampCache[st] = ogid;
return true;
}
return false;
}
public setActivity(activity: boolean) {
this._active = activity;
}
public releaseKeys() {
this._currentlyPressedKeys = {};
}
public addEvent(event: string, keyCode: number, callback: EventCallback, sender?: any, priority?: number) {
// Event is already bound with the callback
if (!this._stamp(event, keyCode, callback)) return;
if (priority === undefined) {
priority = 1600;
}
switch (event) {
case "keyfree":
if (!this._unpressedKeysCallbacks[keyCode]) {
this._unpressedKeysCallbacks[keyCode] = [];
}
this._unpressedKeysCallbacks[keyCode].push({ callback: callback, sender: sender, priority: priority });
this._unpressedKeysCallbacks[keyCode].sort(_sortByPriority);
break;
case "keypress":
if (keyCode == null) {
this._anykeyCallback = { callback: callback, sender: sender || this };
} else {
if (!this._pressedKeysCallbacks[keyCode]) {
this._pressedKeysCallbacks[keyCode] = [];
}
this._pressedKeysCallbacks[keyCode].push({
callback: callback,
sender: sender,
priority: priority
});
this._pressedKeysCallbacks[keyCode].sort(_sortByPriority);
}
break;
case "charkeypress":
if (!this._charkeysCallbacks[keyCode]) {
this._charkeysCallbacks[keyCode] = [];
}
this._charkeysCallbacks[keyCode].push({ callback: callback, sender: sender, priority: priority });
this._charkeysCallbacks[keyCode].sort(_sortByPriority);
break;
}
}
public isKeyPressed(keyCode: number) {
return this._currentlyPressedKeys[keyCode];
}
public handleKeyDown() {
// If you want to get a key code just uncomment and check console
//console.log(this._event!.keyCode);
this._anykeyCallback && this._anykeyCallback.callback.call(this._anykeyCallback.sender, this._event);
this._currentlyPressedKeys[this._event!.keyCode] = true;
for (let ch in this._charkeysCallbacks) {
if (String.fromCharCode(this._event!.keyCode) === String.fromCharCode(Number(ch))) {
let ccl = this._charkeysCallbacks[ch];
for (let i = 0; i < ccl.length; i++) {
(ccl[i].callback as Function).call(ccl[i].sender, this._event);
}
}
}
if (this._event!.keyCode == input.KEY_ALT || this._event!.keyCode == input.KEY_SHIFT) {
this._event!.preventDefault();
}
}
public handleKeyUp() {
if (this._currentlyPressedKeys[this._event!.keyCode] || this._event!.keyCode === input.KEY_PRINTSCREEN) {
for (let pk in this._unpressedKeysCallbacks) {
if (
this._currentlyPressedKeys[pk] ||
(this._event!.keyCode === input.KEY_PRINTSCREEN && Number(pk) === input.KEY_PRINTSCREEN)
) {
let cpk = this._unpressedKeysCallbacks[pk];
for (let i = 0; i < cpk.length; i++) {
(cpk[i].callback as Function).call(cpk[i].sender, this._event);
}
}
}
}
this._currentlyPressedKeys[this._event!.keyCode] = false;
}
public handleEvents() {
for (let pk in this._pressedKeysCallbacks) {
if (this._currentlyPressedKeys[pk]) {
let cpk = this._pressedKeysCallbacks[pk];
for (let i = 0; i < cpk.length; i++) {
(cpk[i].callback as Function).call(cpk[i].sender, this._event);
}
}
}
}
}
export { KeyboardHandler };