Skip to content
Source
Sign inSign up

snapShotShortcut.ts

120 lines4.0 KB

1import {
2 isModifierPairShortcut,
3 snapShotModifierPairLabel,
4 snapShotShortcutModifierPair,
5 type KeybindingShortcut,
6 type SnapShotModifier,
7 type SnapShotShortcut,
8} from "@t3tools/contracts";
9import { parseKeybindingShortcut } from "@t3tools/shared/keybindings";
10​
11import { formatShortcutKeyLabel, formatShortcutLabel, shortcutConflictKey } from "../keybindings";
12import { isMacPlatform, isWindowsPlatform } from "./utils";
13​
14const DESKTOP_KEY_ALIASES: Readonly<Record<string, string>> = {
15 return: "enter",
16 page_up: "pageup",
17 page_down: "pagedown",
18 left: "arrowleft",
19 right: "arrowright",
20 up: "arrowup",
21 down: "arrowdown",
22 plus: "+",
23 minus: "-",
24};
25​
26export function parseDesktopSnapShotShortcut(label: string): KeybindingShortcut | null {
27 const text = label.trim().replace(/^Press\s+/i, "");
28 if (!text) return null;
29 const gtk = text.match(/^((?:<[^<>]+>)+)([^<>]+)$/);
30 const input = (gtk ? gtk[1]!.replace(/<([^<>]+)>/g, "$1+") + gtk[2]! : text).replace(
31 /\b(super|win|primary)\b/gi,
32 (modifier) => (modifier.toLowerCase() === "primary" ? "ctrl" : "meta"),
33 );
34 if (input !== "+" && input.endsWith("+") && !input.endsWith("++")) return null;
35 const shortcut = parseKeybindingShortcut(input);
36 if (!shortcut) return null;
37 const key = DESKTOP_KEY_ALIASES[shortcut.key] ?? shortcut.key;
38 if (
39 key !== " " &&
40 !/^[^\s<>]$/u.test(key) &&
41 !/^(?:f(?:[1-9]|1\d|2[0-4])|enter|tab|escape|backspace|delete|insert|home|end|pageup|pagedown|arrow(?:left|right|up|down)|pause|printscreen)$/i.test(
42 key,
43 )
44 ) {
45 return null;
46 }
47 return { ...shortcut, key };
49​
50export function formatSnapShotShortcutLabel(
51 shortcut: SnapShotShortcut,
52 platform = navigator.platform,
53): string {
54 return isModifierPairShortcut(shortcut)
55 ? snapShotModifierPairLabel(snapShotShortcutModifierPair(shortcut), isMacPlatform(platform))
56 : formatShortcutLabel(shortcut, platform);
58​
59function modifierKeyLabel(modifier: SnapShotModifier, platform: string): string {
60 if (modifier === "shift") return "⇧";
61 if (isMacPlatform(platform)) {
62 if (modifier === "meta") return "⌘";
63 if (modifier === "control") return "⌃";
64 return "⌥";
65 }
66 if (modifier === "meta") return isWindowsPlatform(platform) ? "⊞" : "Super";
67 return modifier === "control" ? "Ctrl" : "Alt";
69​
70export function snapShotShortcutKeyLabels(
71 shortcut: SnapShotShortcut,
72 platform = navigator.platform,
73): readonly string[] {
74 if (isModifierPairShortcut(shortcut)) {
75 const label = modifierKeyLabel(snapShotShortcutModifierPair(shortcut), platform);
76 return [label, label];
77 }
78​
79 const useMetaForMod = isMacPlatform(platform);
80 const modifiers: readonly [boolean, SnapShotModifier][] = [
81 [shortcut.ctrlKey || (shortcut.modKey && !useMetaForMod), "control"],
82 [shortcut.altKey, "alt"],
83 [shortcut.shiftKey, "shift"],
84 [shortcut.metaKey || (shortcut.modKey && useMetaForMod), "meta"],
85 ];
86 return [
87 ...modifiers
88 .filter(([enabled]) => enabled)
89 .map(([, modifier]) => modifierKeyLabel(modifier, platform)),
90 formatShortcutKeyLabel(shortcut.key),
91 ];
93​
94export function sameSnapShotShortcut(
95 left: SnapShotShortcut,
96 right: SnapShotShortcut,
97 platform = navigator.platform,
98): boolean {
99 if (isModifierPairShortcut(left) || isModifierPairShortcut(right)) {
100 return (
101 isModifierPairShortcut(left) &&
102 isModifierPairShortcut(right) &&
103 snapShotShortcutModifierPair(left) === snapShotShortcutModifierPair(right)
104 );
105 }
106 return shortcutConflictKey(left, platform) === shortcutConflictKey(right, platform);
108​
109export function snapShotKeybindingConflict<Command extends string>(
110 shortcut: SnapShotShortcut,
111 keybindings: ReadonlyArray<{ readonly command: Command; readonly shortcut: KeybindingShortcut }>,
112 platform = navigator.platform,
113): Command | null {
114 if (isModifierPairShortcut(shortcut)) return null;
115 const key = shortcutConflictKey(shortcut, platform);
116 return (
117 keybindings.find((binding) => shortcutConflictKey(binding.shortcut, platform) === key)
118 ?.command ?? null
119 );