New version

This commit is contained in:
sguenter 2025-06-30 07:47:38 +02:00
parent b80961adf2
commit 90faaff8d2
3 changed files with 38 additions and 22 deletions

View File

@ -66,11 +66,19 @@ export class HotKeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
addListener<HotkeyName extends keyof HotkeyConfig>( addListener<HotkeyName extends keyof HotkeyConfig>(
hotkeyName: HotkeyName, hotkeyName: HotkeyName,
callback: HotkeyListener<SubKeyType<HotkeyConfig, HotkeyName>>, callback: HotkeyListener<SubKeyType<HotkeyConfig, HotkeyName>>,
order = 100,
) { ) {
const { callbacks } = this.hotKeys[hotkeyName]; const { callbacks } = this.hotKeys[hotkeyName];
callbacks.push(callback); const callbackElement = { order, callback };
for (let i = 0; i <= callbacks.length; i++) {
if (i === callbacks.length || callbacks[i].order > order) {
callbacks.splice(i, 0, callbackElement);
break;
}
}
return () => { return () => {
const index = callbacks.indexOf(callback); const index = callbacks.indexOf(callbackElement);
if (index > -1) { if (index > -1) {
callbacks.splice(index, 1); callbacks.splice(index, 1);
} }
@ -146,6 +154,10 @@ export class HotKeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
this.checkHotkeys(e); this.checkHotkeys(e);
} }
}); });
window.addEventListener('blur', () => {
this.clearMap();
});
} }
getHotKeysPressedMap() { getHotKeysPressedMap() {
@ -198,23 +210,25 @@ export class HotKeyManager<HotkeyConfig extends Record<string, HotkeyEntry<strin
private triggerListenerFor( private triggerListenerFor(
key: keyof HotkeyConfig, key: keyof HotkeyConfig,
event: KeyboardEvent, event: KeyboardEvent | undefined,
oldKeyMap: HotkeyPressedMap<HotkeyConfig>[keyof HotkeyConfig], oldKeyMap: HotkeyPressedMap<HotkeyConfig>[keyof HotkeyConfig],
isRepeated: boolean, isRepeated: boolean,
) { ) {
const pressedEntry = this.hotKeysPressedMap[key]; const pressedEntry = this.hotKeysPressedMap[key];
this.hotKeys[key].callbacks.forEach((callback) => this.hotKeys[key].callbacks.some((callback) => {
callback({ return (
event, callback.callback({
subKeys: pressedEntry.subKeys, event,
isPressed: pressedEntry.isPressed, subKeys: pressedEntry.subKeys,
previous: oldKeyMap, isPressed: pressedEntry.isPressed,
isRepeated, previous: oldKeyMap,
}), isRepeated,
); }) === true
);
});
} }
private checkHotkeys(event: KeyboardEvent) { private checkHotkeys(event?: KeyboardEvent) {
const hotkeysToTrigger: (keyof HotkeyConfig)[] = []; const hotkeysToTrigger: (keyof HotkeyConfig)[] = [];
const oldMap = this.hotKeysPressedMap; const oldMap = this.hotKeysPressedMap;
@ -232,21 +246,21 @@ 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();
const hotkeysToTroggerAgain = hotkeysToCheckAffection.filter(([key]) => { const hotkeysToTriggerAgain = hotkeysToCheckAffection.filter(([key]) => {
const keyDefinition = this.hotKeys[key]; const keyDefinition = this.hotKeys[key];
if (HotKeyManager.checkAffections(keyDefinition.keys, eventKey)) { if (eventKey && HotKeyManager.checkAffections(keyDefinition.keys, eventKey)) {
return true; return true;
} }
return ObjectHelper.values(keyDefinition.subKeys).some((subKeyDefinitions) => { return ObjectHelper.values(keyDefinition.subKeys).some((subKeyDefinitions) => {
return HotKeyManager.checkAffections(subKeyDefinitions, eventKey); return eventKey && HotKeyManager.checkAffections(subKeyDefinitions, eventKey);
}); });
}); });
hotkeysToTrigger.forEach((key) => this.triggerListenerFor(key, event, oldMap[key], false)); hotkeysToTrigger.forEach((key) => this.triggerListenerFor(key, event, oldMap[key], false));
hotkeysToTroggerAgain.forEach(([key]) => this.triggerListenerFor(key, event, oldMap[key], true)); hotkeysToTriggerAgain.forEach(([key]) => this.triggerListenerFor(key, event, oldMap[key], true));
} }
private clearMap(event: KeyboardEvent) { private clearMap(event?: KeyboardEvent) {
this.keyPressedMap.clear(); this.keyPressedMap.clear();
this.checkHotkeys(event); this.checkHotkeys(event);
} }

View File

@ -4,5 +4,5 @@ import { HotkeyListener } from './HotkeyListener';
export type HotkeyEntry<SubKeys extends string> = { export type HotkeyEntry<SubKeys extends string> = {
keys: HotkeyDefinitionType[]; keys: HotkeyDefinitionType[];
subKeys: { [key in SubKeys]: HotkeyDefinitionType[] }; subKeys: { [key in SubKeys]: HotkeyDefinitionType[] };
callbacks: HotkeyListener<SubKeys>[]; callbacks: { order: number; callback: HotkeyListener<SubKeys> }[];
}; };

View File

@ -1,5 +1,5 @@
export type HotkeyListenerEvent<SubKeys extends string | symbol | number> = { export type HotkeyListenerEvent<SubKeys extends string | symbol | number> = {
event: KeyboardEvent; event: KeyboardEvent | undefined;
subKeys: Record<SubKeys, boolean>; subKeys: Record<SubKeys, boolean>;
isPressed: boolean; isPressed: boolean;
previous: { previous: {
@ -9,4 +9,6 @@ export type HotkeyListenerEvent<SubKeys extends string | symbol | number> = {
isRepeated: boolean; isRepeated: boolean;
}; };
export type HotkeyListener<SubKeys extends string | symbol | number> = (ev: HotkeyListenerEvent<SubKeys>) => unknown; export type HotkeyListener<SubKeys extends string | symbol | number> = (
ev: HotkeyListenerEvent<SubKeys>,
) => unknown | boolean;