50 lines
1.3 KiB
TypeScript
50 lines
1.3 KiB
TypeScript
import type { Dispatch } from "@commands/dispatcher";
|
|
import type { CommandId, CommandPayloads } from "@commands/payloads";
|
|
|
|
export type Keybind = string;
|
|
|
|
export type KeybindEvent = {
|
|
key: string;
|
|
code: string;
|
|
altKey: boolean;
|
|
ctrlKey: boolean;
|
|
metaKey: boolean;
|
|
shiftKey: boolean;
|
|
};
|
|
|
|
export type GlobalKeybindConsumer = (event: KeybindEvent) => boolean;
|
|
|
|
export type CommandKeybind<TCommandId extends CommandId = CommandId> = {
|
|
commandId: TCommandId;
|
|
payload: CommandPayloads[TCommandId];
|
|
};
|
|
|
|
export type KeybindMap = ReadonlyMap<Keybind, CommandKeybind>;
|
|
|
|
export function keybindFromEvent(event: KeybindEvent): Keybind {
|
|
const parts = [
|
|
event.metaKey ? "Meta" : undefined,
|
|
event.ctrlKey ? "Ctrl" : undefined,
|
|
event.altKey ? "Alt" : undefined,
|
|
event.shiftKey ? "Shift" : undefined,
|
|
event.key,
|
|
].filter(Boolean);
|
|
|
|
return parts.join("+");
|
|
}
|
|
|
|
export function handleKeybind(options: {
|
|
event: KeybindEvent;
|
|
globalConsumer: GlobalKeybindConsumer;
|
|
keybindMap: KeybindMap;
|
|
dispatch: Dispatch;
|
|
}): boolean {
|
|
if (options.globalConsumer(options.event)) return true;
|
|
|
|
const command = options.keybindMap.get(keybindFromEvent(options.event));
|
|
if (!command) return false;
|
|
|
|
options.dispatch(command.commandId, command.payload);
|
|
return true;
|
|
}
|