Files
dbx/src/lib/keyboardShortcuts.ts
T

96 lines
3.3 KiB
TypeScript

import {
DEFAULT_SHORTCUT_SETTINGS,
normalizeShortcutSettings,
type ShortcutActionId,
type ShortcutSettings,
} from "@/lib/shortcutRegistry";
export interface ShortcutLikeEvent {
key: string;
metaKey?: boolean;
ctrlKey?: boolean;
altKey?: boolean;
shiftKey?: boolean;
isComposing?: boolean;
}
function normalizeKey(key: string): string {
if (key === " ") return "Space";
return key.length === 1 ? key.toLowerCase() : key;
}
function shortcutKeyName(key: string): string | null {
if (key === " ") return "Space";
if (["Control", "Meta", "Shift", "Alt"].includes(key)) return null;
if (key.length === 1) return key.toUpperCase();
return key;
}
export function eventToShortcut(event: ShortcutLikeEvent): string | null {
if (event.isComposing) return null;
const key = shortcutKeyName(event.key);
if (!key) return null;
const hasModifier = !!event.metaKey || !!event.ctrlKey || !!event.altKey || !!event.shiftKey;
if (!hasModifier && key.length === 1) return null;
const parts: string[] = [];
if (event.shiftKey) parts.push("Shift");
if (event.metaKey || event.ctrlKey) parts.push("Mod");
if (event.altKey) parts.push("Alt");
parts.push(key);
return parts.join("+");
}
export function matchesShortcut(event: ShortcutLikeEvent, shortcut: string): boolean {
if (event.isComposing) return false;
const parts = shortcut.split("+");
const key = parts[parts.length - 1] ?? "";
const modifiers = new Set(parts.slice(0, -1));
const usesMod = modifiers.has("Mod");
const usesMeta = modifiers.has("Meta");
const usesCtrl = modifiers.has("Ctrl");
if (usesMod) {
if (!event.metaKey && !event.ctrlKey) return false;
} else {
if (!!event.metaKey !== usesMeta) return false;
if (!!event.ctrlKey !== usesCtrl) return false;
}
if (!!event.altKey !== modifiers.has("Alt")) return false;
if (!!event.shiftKey !== modifiers.has("Shift")) return false;
return normalizeKey(event.key) === normalizeKey(key);
}
function actionShortcut(actionId: ShortcutActionId, shortcuts?: Partial<ShortcutSettings>): string {
return normalizeShortcutSettings(shortcuts)[actionId] || DEFAULT_SHORTCUT_SETTINGS[actionId];
}
export function isExecuteSqlShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
return matchesShortcut(event, actionShortcut("executeSql", shortcuts));
}
export function isCloseTabShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
return matchesShortcut(event, actionShortcut("closeTab", shortcuts));
}
export function isFocusSearchShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
return matchesShortcut(event, actionShortcut("focusSearch", shortcuts));
}
export function isSaveShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
return matchesShortcut(event, actionShortcut("saveSql", shortcuts));
}
export function isObjectSourceSaveShortcutTarget(
target: { closest(selector: string): unknown } | null | undefined,
): boolean {
return !!target?.closest("[data-object-source-editor], [data-object-source-preview]");
}
export function isCancelSearchShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
return matchesShortcut(event, actionShortcut("cancelSearch", shortcuts));
}