(
hotkey: Hotkey | (string & {}),
platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
)
| 29 | * ``` |
| 30 | */ |
| 31 | export function parseHotkey( |
| 32 | hotkey: Hotkey | (string & {}), |
| 33 | platform: 'mac' | 'windows' | 'linux' = detectPlatform(), |
| 34 | ): ParsedHotkey { |
| 35 | const parts = hotkey.split('+') |
| 36 | const modifiers: Set<CanonicalModifier> = new Set() |
| 37 | let key = '' |
| 38 | |
| 39 | for (let i = 0; i < parts.length; i++) { |
| 40 | const part = parts[i]!.trim() |
| 41 | |
| 42 | if (i === parts.length - 1) { |
| 43 | // Last part is always the key |
| 44 | key = normalizeKeyName(part) |
| 45 | } else { |
| 46 | // All other parts are modifiers |
| 47 | const alias = |
| 48 | MODIFIER_ALIASES[part] ?? MODIFIER_ALIASES[part.toLowerCase()] |
| 49 | |
| 50 | if (alias) { |
| 51 | const resolved = resolveModifier(alias, platform) |
| 52 | modifiers.add(resolved) |
| 53 | } else { |
| 54 | // Unknown modifier, treat as part of the key if it's the only part |
| 55 | // or ignore if there are more parts |
| 56 | if (parts.length === 1) { |
| 57 | key = normalizeKeyName(part) |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | // If no key was found (empty string), use the last part as-is |
| 64 | if (!key && parts.length > 0) { |
| 65 | key = normalizeKeyName(parts[parts.length - 1]!.trim()) |
| 66 | } |
| 67 | |
| 68 | return { |
| 69 | key, |
| 70 | ctrl: modifiers.has('Control'), |
| 71 | shift: modifiers.has('Shift'), |
| 72 | alt: modifiers.has('Alt'), |
| 73 | meta: modifiers.has('Meta'), |
| 74 | modifiers: MODIFIER_ORDER.filter((m) => modifiers.has(m)), |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | /** |
| 79 | * Converts a RawHotkey object to a ParsedHotkey. |
no test coverage detected
searching dependent graphs…