source dump of claude code
at main 127 lines 3.6 kB view raw
1import { getPlatform } from '../utils/platform.js' 2 3/** 4 * Shortcuts that are typically intercepted by the OS, terminal, or shell 5 * and will likely never reach the application. 6 */ 7export type ReservedShortcut = { 8 key: string 9 reason: string 10 severity: 'error' | 'warning' 11} 12 13/** 14 * Shortcuts that cannot be rebound - they are hardcoded in Claude Code. 15 */ 16export const NON_REBINDABLE: ReservedShortcut[] = [ 17 { 18 key: 'ctrl+c', 19 reason: 'Cannot be rebound - used for interrupt/exit (hardcoded)', 20 severity: 'error', 21 }, 22 { 23 key: 'ctrl+d', 24 reason: 'Cannot be rebound - used for exit (hardcoded)', 25 severity: 'error', 26 }, 27 { 28 key: 'ctrl+m', 29 reason: 30 'Cannot be rebound - identical to Enter in terminals (both send CR)', 31 severity: 'error', 32 }, 33] 34 35/** 36 * Terminal control shortcuts that are intercepted by the terminal/OS. 37 * These will likely never reach the application. 38 * 39 * Note: ctrl+s (XOFF) and ctrl+q (XON) are NOT included here because: 40 * - Most modern terminals disable flow control by default 41 * - We use ctrl+s for the stash feature 42 */ 43export const TERMINAL_RESERVED: ReservedShortcut[] = [ 44 { 45 key: 'ctrl+z', 46 reason: 'Unix process suspend (SIGTSTP)', 47 severity: 'warning', 48 }, 49 { 50 key: 'ctrl+\\', 51 reason: 'Terminal quit signal (SIGQUIT)', 52 severity: 'error', 53 }, 54] 55 56/** 57 * macOS-specific shortcuts that the OS intercepts. 58 */ 59export const MACOS_RESERVED: ReservedShortcut[] = [ 60 { key: 'cmd+c', reason: 'macOS system copy', severity: 'error' }, 61 { key: 'cmd+v', reason: 'macOS system paste', severity: 'error' }, 62 { key: 'cmd+x', reason: 'macOS system cut', severity: 'error' }, 63 { key: 'cmd+q', reason: 'macOS quit application', severity: 'error' }, 64 { key: 'cmd+w', reason: 'macOS close window/tab', severity: 'error' }, 65 { key: 'cmd+tab', reason: 'macOS app switcher', severity: 'error' }, 66 { key: 'cmd+space', reason: 'macOS Spotlight', severity: 'error' }, 67] 68 69/** 70 * Get all reserved shortcuts for the current platform. 71 * Includes non-rebindable shortcuts and terminal-reserved shortcuts. 72 */ 73export function getReservedShortcuts(): ReservedShortcut[] { 74 const platform = getPlatform() 75 // Non-rebindable shortcuts first (highest priority) 76 const reserved = [...NON_REBINDABLE, ...TERMINAL_RESERVED] 77 78 if (platform === 'macos') { 79 reserved.push(...MACOS_RESERVED) 80 } 81 82 return reserved 83} 84 85/** 86 * Normalize a key string for comparison (lowercase, sorted modifiers). 87 * Chords (space-separated steps like "ctrl+x ctrl+b") are normalized 88 * per-step — splitting on '+' first would mangle "x ctrl" into a mainKey 89 * overwritten by the next step, collapsing the chord into its last key. 90 */ 91export function normalizeKeyForComparison(key: string): string { 92 return key.trim().split(/\s+/).map(normalizeStep).join(' ') 93} 94 95function normalizeStep(step: string): string { 96 const parts = step.split('+') 97 const modifiers: string[] = [] 98 let mainKey = '' 99 100 for (const part of parts) { 101 const lower = part.trim().toLowerCase() 102 if ( 103 [ 104 'ctrl', 105 'control', 106 'alt', 107 'opt', 108 'option', 109 'meta', 110 'cmd', 111 'command', 112 'shift', 113 ].includes(lower) 114 ) { 115 // Normalize modifier names 116 if (lower === 'control') modifiers.push('ctrl') 117 else if (lower === 'option' || lower === 'opt') modifiers.push('alt') 118 else if (lower === 'command' || lower === 'cmd') modifiers.push('cmd') 119 else modifiers.push(lower) 120 } else { 121 mainKey = lower 122 } 123 } 124 125 modifiers.sort() 126 return [...modifiers, mainKey].join('+') 127}