update
This commit is contained in:
parent
da535c5de2
commit
c86abe5ff7
@ -1,24 +1,21 @@
|
|||||||
import { HotkeyDefinitionType, specialKeys } from './HotkeyDefinitionType';
|
import { HotkeyDefinitionType, specialKeys } from './HotkeyDefinitionType';
|
||||||
import { HotkeyListener } from './HotkeyListener';
|
import { HotkeyListener } from './HotkeyListener';
|
||||||
import { JsonHelper, ObjectHelper } from '@ainias42/js-helper';
|
import { JsonHelper, ObjectHelper, Override } from '@ainias42/js-helper';
|
||||||
import { HotkeyEntry } from './HotkeyEntry';
|
import { HotkeyEntry } from './HotkeyEntry';
|
||||||
import { SubKeyType } from './SubKeyType';
|
import { SubKeyType } from './SubKeyType';
|
||||||
import { HotkeyPressedMap } from './HotkeyPressedMap';
|
import { HotkeyPressedMap } from './HotkeyPressedMap';
|
||||||
import { HotkeyConfigWithOptionals } from './HotkeyConfigWithOptionals';
|
import { HotkeyConfigWithOptionals } from './HotkeyConfigWithOptionals';
|
||||||
|
|
||||||
export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<string>>> {
|
export class HotKeyManager<HotkeyConfig extends Record<string, HotkeyEntry<string>>> {
|
||||||
private keyPressedMap = new Map<string, boolean>();
|
private keyPressedMap = new Map<string, boolean>();
|
||||||
private hotkeys: HotkeyConfig;
|
private hotKeys: HotkeyConfig;
|
||||||
private hotkeysPressedMap: HotkeyPressedMap<HotkeyConfig>;
|
private hotKeysPressedMap: HotkeyPressedMap<HotkeyConfig>;
|
||||||
private enabled = true;
|
private enabled = true;
|
||||||
private ignoreFormElements = true;
|
private readonly ignoreFormElements: boolean = true;
|
||||||
|
|
||||||
constructor(hotkeys: HotkeyConfigWithOptionals<HotkeyConfig>, ignoreFormElements?: boolean) {
|
constructor(hotkeys: HotkeyConfigWithOptionals<HotkeyConfig>, ignoreFormElements?: boolean) {
|
||||||
this.hotkeys = ObjectHelper.entries(hotkeys).reduce((acc, [key, value]) => {
|
this.hotKeys = {} as HotkeyConfig;
|
||||||
acc[key] = { subKeys: {}, callbacks: [], ...value } as unknown as HotkeyConfig[typeof key];
|
this.addHotKeys(hotkeys);
|
||||||
return acc;
|
|
||||||
}, {} as HotkeyConfig);
|
|
||||||
this.hotkeysPressedMap = this.generateHotkeyPressedMap();
|
|
||||||
|
|
||||||
if (ignoreFormElements !== undefined) {
|
if (ignoreFormElements !== undefined) {
|
||||||
this.ignoreFormElements = ignoreFormElements;
|
this.ignoreFormElements = ignoreFormElements;
|
||||||
@ -29,7 +26,8 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
return (
|
return (
|
||||||
element instanceof HTMLInputElement ||
|
element instanceof HTMLInputElement ||
|
||||||
element instanceof HTMLSelectElement ||
|
element instanceof HTMLSelectElement ||
|
||||||
element instanceof HTMLTextAreaElement
|
element instanceof HTMLTextAreaElement ||
|
||||||
|
(element instanceof HTMLElement && element.contentEditable === 'true')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +36,7 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static checkAffections(keyDefinitions: HotkeyDefinitionType[], key: string): boolean {
|
private static checkAffections(keyDefinitions: HotkeyDefinitionType[], key: string): boolean {
|
||||||
return keyDefinitions.some((keyDefinition) => HotkeyManager.checkAffection(keyDefinition, key));
|
return keyDefinitions.some((keyDefinition) => HotKeyManager.checkAffection(keyDefinition, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static checkAffection(keyDefinition: HotkeyDefinitionType, key: string): boolean {
|
private static checkAffection(keyDefinition: HotkeyDefinitionType, key: string): boolean {
|
||||||
@ -48,11 +46,28 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addHotKeys<NewHotkeyConfig extends Record<string, HotkeyEntry<string>>>(
|
||||||
|
hotkeys: HotkeyConfigWithOptionals<NewHotkeyConfig>,
|
||||||
|
) {
|
||||||
|
type NewConfig = Override<HotkeyConfig, NewHotkeyConfig>;
|
||||||
|
|
||||||
|
this.hotKeys = {
|
||||||
|
...this.hotKeys,
|
||||||
|
...ObjectHelper.entries(hotkeys).reduce((acc, [key, value]) => {
|
||||||
|
acc[key] = { subKeys: {}, callbacks: [], ...value } as unknown as NewConfig[typeof key];
|
||||||
|
return acc;
|
||||||
|
}, {} as NewConfig),
|
||||||
|
};
|
||||||
|
this.hotKeysPressedMap = this.generateHotkeyPressedMap();
|
||||||
|
|
||||||
|
return this as unknown as HotKeyManager<NewConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
addListener<HotkeyName extends keyof HotkeyConfig>(
|
addListener<HotkeyName extends keyof HotkeyConfig>(
|
||||||
hotkeyName: HotkeyName,
|
hotkeyName: HotkeyName,
|
||||||
callback: HotkeyListener<SubKeyType<HotkeyConfig, HotkeyName>>,
|
callback: HotkeyListener<SubKeyType<HotkeyConfig, HotkeyName>>,
|
||||||
) {
|
) {
|
||||||
const { callbacks } = this.hotkeys[hotkeyName];
|
const { callbacks } = this.hotKeys[hotkeyName];
|
||||||
callbacks.push(callback);
|
callbacks.push(callback);
|
||||||
return () => {
|
return () => {
|
||||||
const index = callbacks.indexOf(callback);
|
const index = callbacks.indexOf(callback);
|
||||||
@ -71,15 +86,15 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
addHotKeyDefinition(hotkey: keyof HotkeyConfig, definition: HotkeyDefinitionType) {
|
addHotKeyDefinition(hotkey: keyof HotkeyConfig, definition: HotkeyDefinitionType) {
|
||||||
this.hotkeys[hotkey].keys.push(definition);
|
this.hotKeys[hotkey].keys.push(definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeHotkeyDefinition(hotkey: keyof HotkeyConfig, definition: HotkeyDefinitionType) {
|
removeHotKeyDefinition(hotkey: keyof HotkeyConfig, definition: HotkeyDefinitionType) {
|
||||||
this.hotkeys[hotkey].keys = this.hotkeys[hotkey].keys.filter((key) => !HotkeyManager.isEqual(key, definition));
|
this.hotKeys[hotkey].keys = this.hotKeys[hotkey].keys.filter((key) => !HotKeyManager.isEqual(key, definition));
|
||||||
}
|
}
|
||||||
|
|
||||||
setHotkeyDefinitions(hotkey: keyof HotkeyConfig, definitions: HotkeyDefinitionType[]) {
|
setHotKeyDefinitions(hotkey: keyof HotkeyConfig, definitions: HotkeyDefinitionType[]) {
|
||||||
this.hotkeys[hotkey].keys = definitions;
|
this.hotKeys[hotkey].keys = definitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubKeyDefinition<HotkeyName extends keyof HotkeyConfig>(
|
addSubKeyDefinition<HotkeyName extends keyof HotkeyConfig>(
|
||||||
@ -87,7 +102,7 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
subKey: SubKeyType<HotkeyConfig, HotkeyName>,
|
subKey: SubKeyType<HotkeyConfig, HotkeyName>,
|
||||||
definition: HotkeyDefinitionType,
|
definition: HotkeyDefinitionType,
|
||||||
) {
|
) {
|
||||||
this.hotkeys[hotkey].subKeys[subKey as string].push(definition);
|
this.hotKeys[hotkey].subKeys[subKey as string].push(definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSubKeyDefinition<HotkeyName extends keyof HotkeyConfig>(
|
removeSubKeyDefinition<HotkeyName extends keyof HotkeyConfig>(
|
||||||
@ -95,8 +110,8 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
subKey: SubKeyType<HotkeyConfig, HotkeyName>,
|
subKey: SubKeyType<HotkeyConfig, HotkeyName>,
|
||||||
definition: HotkeyDefinitionType,
|
definition: HotkeyDefinitionType,
|
||||||
) {
|
) {
|
||||||
const { subKeys } = this.hotkeys[hotkey];
|
const { subKeys } = this.hotKeys[hotkey];
|
||||||
subKeys[subKey as string] = subKeys[subKey as string].filter((key) => !HotkeyManager.isEqual(key, definition));
|
subKeys[subKey as string] = subKeys[subKey as string].filter((key) => !HotKeyManager.isEqual(key, definition));
|
||||||
}
|
}
|
||||||
|
|
||||||
setSubKeyDefinitions<HotkeyName extends keyof HotkeyConfig>(
|
setSubKeyDefinitions<HotkeyName extends keyof HotkeyConfig>(
|
||||||
@ -104,16 +119,16 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
subKey: SubKeyType<HotkeyConfig, HotkeyName>,
|
subKey: SubKeyType<HotkeyConfig, HotkeyName>,
|
||||||
definitions: HotkeyDefinitionType[],
|
definitions: HotkeyDefinitionType[],
|
||||||
) {
|
) {
|
||||||
this.hotkeys[hotkey].subKeys[subKey as string] = definitions;
|
this.hotKeys[hotkey].subKeys[subKey as string] = definitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfig() {
|
getConfig() {
|
||||||
return this.hotkeys;
|
return this.hotKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
addKeyListeners() {
|
addKeyListeners() {
|
||||||
window.addEventListener('keydown', (e) => {
|
window.addEventListener('keydown', (e) => {
|
||||||
if (this.ignoreFormElements && HotkeyManager.isFormElement(e.target)) {
|
if (this.ignoreFormElements && HotKeyManager.isFormElement(e.target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,16 +149,16 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getHotkeysPressedMap() {
|
getHotKeysPressedMap() {
|
||||||
return this.hotkeysPressedMap;
|
return this.hotKeysPressedMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
isHotkeyPressed(hotkey: keyof HotkeyConfig) {
|
isHotKeyPressed(hotkey: keyof HotkeyConfig) {
|
||||||
return this.hotkeysPressedMap[hotkey].isPressed;
|
return this.hotKeysPressedMap[hotkey].isPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
isSubKeyPressed<Hotkey extends keyof HotkeyConfig>(hotkey: Hotkey, subkey: SubKeyType<HotkeyConfig, Hotkey>) {
|
isSubKeyPressed<Hotkey extends keyof HotkeyConfig>(hotkey: Hotkey, subkey: SubKeyType<HotkeyConfig, Hotkey>) {
|
||||||
return this.hotkeysPressedMap[hotkey].isPressed && this.hotkeysPressedMap[hotkey].subKeys[subkey];
|
return this.hotKeysPressedMap[hotkey].isPressed && this.hotKeysPressedMap[hotkey].subKeys[subkey];
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkHotkeyDefinitions(keyDefinitions: HotkeyDefinitionType[]): boolean {
|
private checkHotkeyDefinitions(keyDefinitions: HotkeyDefinitionType[]): boolean {
|
||||||
@ -165,7 +180,7 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
private generateHotkeyPressedMap() {
|
private generateHotkeyPressedMap() {
|
||||||
return ObjectHelper.entries(this.hotkeys).reduce((acc, [key, value]) => {
|
return ObjectHelper.entries(this.hotKeys).reduce((acc, [key, value]) => {
|
||||||
const isPressed = this.checkHotkeyDefinitions(value.keys);
|
const isPressed = this.checkHotkeyDefinitions(value.keys);
|
||||||
acc[key] = {
|
acc[key] = {
|
||||||
isPressed,
|
isPressed,
|
||||||
@ -183,8 +198,8 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
private triggerListenerFor(key: keyof HotkeyConfig, event: KeyboardEvent) {
|
private triggerListenerFor(key: keyof HotkeyConfig, event: KeyboardEvent) {
|
||||||
const pressedEntry = this.hotkeysPressedMap[key];
|
const pressedEntry = this.hotKeysPressedMap[key];
|
||||||
this.hotkeys[key].callbacks.forEach((callback) =>
|
this.hotKeys[key].callbacks.forEach((callback) =>
|
||||||
callback({ event, subKeys: pressedEntry.subKeys, isPressed: pressedEntry.isPressed }),
|
callback({ event, subKeys: pressedEntry.subKeys, isPressed: pressedEntry.isPressed }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -192,9 +207,9 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
private checkHotkeys(event: KeyboardEvent) {
|
private checkHotkeys(event: KeyboardEvent) {
|
||||||
const hotkeysToTrigger: (keyof HotkeyConfig)[] = [];
|
const hotkeysToTrigger: (keyof HotkeyConfig)[] = [];
|
||||||
|
|
||||||
const oldMap = this.hotkeysPressedMap;
|
const oldMap = this.hotKeysPressedMap;
|
||||||
this.hotkeysPressedMap = this.generateHotkeyPressedMap();
|
this.hotKeysPressedMap = this.generateHotkeyPressedMap();
|
||||||
const hotkeysToCheckAffection = ObjectHelper.entries(this.hotkeysPressedMap).filter(([key, value]) => {
|
const hotkeysToCheckAffection = ObjectHelper.entries(this.hotKeysPressedMap).filter(([key, value]) => {
|
||||||
const oldValue = oldMap[key];
|
const oldValue = oldMap[key];
|
||||||
if (
|
if (
|
||||||
oldValue.isPressed !== value.isPressed ||
|
oldValue.isPressed !== value.isPressed ||
|
||||||
@ -209,12 +224,12 @@ export class HotkeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
|
|||||||
// Check for repeated pressed. Nothing changed, but key is pressed again
|
// Check for repeated pressed. Nothing changed, but key is pressed again
|
||||||
const eventKey = event.key.toLowerCase();
|
const eventKey = event.key.toLowerCase();
|
||||||
hotkeysToCheckAffection.forEach(([key]) => {
|
hotkeysToCheckAffection.forEach(([key]) => {
|
||||||
const keyDefinition = this.hotkeys[key];
|
const keyDefinition = this.hotKeys[key];
|
||||||
if (HotkeyManager.checkAffections(keyDefinition.keys, eventKey)) {
|
if (HotKeyManager.checkAffections(keyDefinition.keys, eventKey)) {
|
||||||
hotkeysToTrigger.push(key);
|
hotkeysToTrigger.push(key);
|
||||||
} else {
|
} else {
|
||||||
ObjectHelper.values(keyDefinition.subKeys).forEach((subKeyDefinitions) => {
|
ObjectHelper.values(keyDefinition.subKeys).forEach((subKeyDefinitions) => {
|
||||||
if (HotkeyManager.checkAffections(subKeyDefinitions, eventKey)) {
|
if (HotKeyManager.checkAffections(subKeyDefinitions, eventKey)) {
|
||||||
hotkeysToTrigger.push(key);
|
hotkeysToTrigger.push(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user