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

View File

@ -4,5 +4,5 @@ import { HotkeyListener } from './HotkeyListener';
export type HotkeyEntry<SubKeys extends string> = {
keys: 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> = {
event: KeyboardEvent;
event: KeyboardEvent | undefined;
subKeys: Record<SubKeys, boolean>;
isPressed: boolean;
previous: {
@ -9,4 +9,6 @@ export type HotkeyListenerEvent<SubKeys extends string | symbol | number> = {
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;