@@ -12,70 +12,156 @@ pub fn normalize_shortcut_keys(shortcut: &str) -> String {
1212}
1313
1414/// Normalize a single key string
15- fn normalize_single_key ( key : & str ) -> & str {
15+ fn normalize_single_key ( key : & str ) -> String {
1616 // First check case-insensitive matches for common modifiers
1717 match key. to_lowercase ( ) . as_str ( ) {
18- "cmd" => return "CommandOrControl" ,
19- "ctrl" => return "CommandOrControl" ,
20- "control" => return "Control" , // Keep Control separate for macOS Cmd+Ctrl support
21- "command" => return "CommandOrControl" ,
22- "meta" => return "CommandOrControl" ,
23- "super" => return "Super" , // Super is Command on macOS
24- "option" => return "Alt" ,
25- "alt" => return "Alt" ,
26- "shift" => return "Shift" ,
27- "space" => return "Space" ,
18+ "cmd" => return "CommandOrControl" . to_string ( ) ,
19+ "ctrl" => return "CommandOrControl" . to_string ( ) ,
20+ "control" => return "Control" . to_string ( ) , // Keep Control separate for macOS Cmd+Ctrl support
21+ "command" => return "CommandOrControl" . to_string ( ) ,
22+ "meta" => return "CommandOrControl" . to_string ( ) ,
23+ "super" => return "CommandOrControl" . to_string ( ) , // Super maps to CommandOrControl for Tauri
24+ "option" => return "Alt" . to_string ( ) ,
25+ "alt" => return "Alt" . to_string ( ) ,
26+ "shift" => return "Shift" . to_string ( ) ,
27+ "space" => return "Space" . to_string ( ) ,
28+ _ => { }
29+ }
30+
31+ // Handle shifted characters - convert them back to their base keys
32+ // This is needed because frontend might capture shifted characters
33+ // Complete mapping for US/UK keyboard shifted characters
34+ match key {
35+ // Shifted punctuation
36+ "<" => return "Comma" . to_string ( ) ,
37+ ">" => return "Period" . to_string ( ) ,
38+ "?" => return "Slash" . to_string ( ) ,
39+ ":" => return "Semicolon" . to_string ( ) ,
40+ "\" " => return "Quote" . to_string ( ) ,
41+ "{" => return "BracketLeft" . to_string ( ) ,
42+ "}" => return "BracketRight" . to_string ( ) ,
43+ "|" => return "Backslash" . to_string ( ) ,
44+ "+" => return "Equal" . to_string ( ) ,
45+ "_" => return "Minus" . to_string ( ) ,
46+ "~" => return "Backquote" . to_string ( ) ,
47+
48+ // Shifted numbers (top row)
49+ "!" => return "Digit1" . to_string ( ) ,
50+ "@" => return "Digit2" . to_string ( ) ,
51+ "#" => return "Digit3" . to_string ( ) ,
52+ "$" => return "Digit4" . to_string ( ) ,
53+ "%" => return "Digit5" . to_string ( ) ,
54+ "^" => return "Digit6" . to_string ( ) ,
55+ "&" => return "Digit7" . to_string ( ) ,
56+ "*" => return "Digit8" . to_string ( ) ,
57+ "(" => return "Digit9" . to_string ( ) ,
58+ ")" => return "Digit0" . to_string ( ) ,
59+
60+ // Common punctuation (unshifted) - normalize these too
61+ "," => return "Comma" . to_string ( ) ,
62+ "." => return "Period" . to_string ( ) ,
63+ "/" => return "Slash" . to_string ( ) ,
64+ ";" => return "Semicolon" . to_string ( ) ,
65+ "'" => return "Quote" . to_string ( ) ,
66+ "[" => return "BracketLeft" . to_string ( ) ,
67+ "]" => return "BracketRight" . to_string ( ) ,
68+ "\\ " => return "Backslash" . to_string ( ) ,
69+ "=" => return "Equal" . to_string ( ) ,
70+ "-" => return "Minus" . to_string ( ) ,
71+ "`" => return "Backquote" . to_string ( ) ,
72+
2873 _ => { }
2974 }
3075
3176 // First, try to parse as keyboard_types::Key for semantic normalization
3277 if let Ok ( parsed_key) = Key :: from_str ( key) {
3378 match parsed_key {
34- Key :: Enter => "Enter" ,
35- Key :: Tab => "Tab" ,
36- Key :: Backspace => "Backspace" ,
37- Key :: Escape => "Escape" ,
38- Key :: Character ( s) if s == " " => "Space" ,
39- Key :: ArrowDown => "Down" ,
40- Key :: ArrowLeft => "Left" ,
41- Key :: ArrowRight => "Right" ,
42- Key :: ArrowUp => "Up" ,
43- Key :: End => "End" ,
44- Key :: Home => "Home" ,
45- Key :: PageDown => "PageDown" ,
46- Key :: PageUp => "PageUp" ,
47- Key :: Delete => "Delete" ,
48- Key :: F1 => "F1" ,
49- Key :: F2 => "F2" ,
50- Key :: F3 => "F3" ,
51- Key :: F4 => "F4" ,
52- Key :: F5 => "F5" ,
53- Key :: F6 => "F6" ,
54- Key :: F7 => "F7" ,
55- Key :: F8 => "F8" ,
56- Key :: F9 => "F9" ,
57- Key :: F10 => "F10" ,
58- Key :: F11 => "F11" ,
59- Key :: F12 => "F12" ,
60- _ => key, // Return original if no normalization needed
79+ Key :: Enter => "Enter" . to_string ( ) ,
80+ Key :: Tab => "Tab" . to_string ( ) ,
81+ Key :: Backspace => "Backspace" . to_string ( ) ,
82+ Key :: Escape => "Escape" . to_string ( ) ,
83+ Key :: Character ( s) if s == " " => "Space" . to_string ( ) ,
84+ Key :: ArrowDown => "Down" . to_string ( ) ,
85+ Key :: ArrowLeft => "Left" . to_string ( ) ,
86+ Key :: ArrowRight => "Right" . to_string ( ) ,
87+ Key :: ArrowUp => "Up" . to_string ( ) ,
88+ Key :: End => "End" . to_string ( ) ,
89+ Key :: Home => "Home" . to_string ( ) ,
90+ Key :: PageDown => "PageDown" . to_string ( ) ,
91+ Key :: PageUp => "PageUp" . to_string ( ) ,
92+ Key :: Delete => "Delete" . to_string ( ) ,
93+ Key :: F1 => "F1" . to_string ( ) ,
94+ Key :: F2 => "F2" . to_string ( ) ,
95+ Key :: F3 => "F3" . to_string ( ) ,
96+ Key :: F4 => "F4" . to_string ( ) ,
97+ Key :: F5 => "F5" . to_string ( ) ,
98+ Key :: F6 => "F6" . to_string ( ) ,
99+ Key :: F7 => "F7" . to_string ( ) ,
100+ Key :: F8 => "F8" . to_string ( ) ,
101+ Key :: F9 => "F9" . to_string ( ) ,
102+ Key :: F10 => "F10" . to_string ( ) ,
103+ Key :: F11 => "F11" . to_string ( ) ,
104+ Key :: F12 => "F12" . to_string ( ) ,
105+ _ => key. to_string ( ) , // Return original if no normalization needed
61106 }
62107 } else {
63108 // Handle special cases that might not parse
64109 match key {
65- "Return" => "Enter" ,
66- "ArrowUp" => "Up" ,
67- "ArrowDown" => "Down" ,
68- "ArrowLeft" => "Left" ,
69- "ArrowRight" => "Right" ,
70- "CommandOrControl" => "CommandOrControl" , // Keep as-is for Tauri
71- "Cmd" => "CommandOrControl" ,
72- "Ctrl" => "CommandOrControl" ,
73- "Control" => "Control" , // Keep Control separate
74- "Command" => "CommandOrControl" ,
75- "Super" => "Super" , // Super is Command on macOS
76- "Option" => "Alt" ,
77- "Meta" => "CommandOrControl" ,
78- _ => key,
110+ // Navigation keys
111+ "Return" => "Enter" . to_string ( ) ,
112+ "ArrowUp" => "Up" . to_string ( ) ,
113+ "ArrowDown" => "Down" . to_string ( ) ,
114+ "ArrowLeft" => "Left" . to_string ( ) ,
115+ "ArrowRight" => "Right" . to_string ( ) ,
116+ "Insert" => "Insert" . to_string ( ) ,
117+
118+ // Modifiers
119+ "CommandOrControl" => "CommandOrControl" . to_string ( ) , // Keep as-is for Tauri
120+ "Cmd" => "CommandOrControl" . to_string ( ) ,
121+ "Ctrl" => "CommandOrControl" . to_string ( ) ,
122+ "Control" => "Control" . to_string ( ) , // Keep Control separate
123+ "Command" => "CommandOrControl" . to_string ( ) ,
124+ "Super" => "CommandOrControl" . to_string ( ) , // Super maps to CommandOrControl for Tauri
125+ "Option" => "Alt" . to_string ( ) ,
126+ "Meta" => "CommandOrControl" . to_string ( ) ,
127+
128+ // Function keys (F1-F24)
129+ k if k. starts_with ( 'F' ) && k. len ( ) <= 3 => {
130+ // Validate it's a function key F1-F24
131+ if let Ok ( num) = k[ 1 ..] . parse :: < u8 > ( ) {
132+ if num >= 1 && num <= 24 {
133+ return key. to_string ( ) ; // Valid function key
134+ }
135+ }
136+ key. to_string ( ) // Return as-is if not valid
137+ }
138+
139+ // Numpad keys
140+ k if k. starts_with ( "Numpad" ) => key. to_string ( ) , // NumpadX, NumpadAdd, etc.
141+ "NumLock" => "NumLock" . to_string ( ) ,
142+ "ScrollLock" => "ScrollLock" . to_string ( ) ,
143+ "Pause" => "Pause" . to_string ( ) ,
144+ "PrintScreen" => "PrintScreen" . to_string ( ) ,
145+ "Clear" => "Clear" . to_string ( ) ,
146+
147+ // Media keys (common ones)
148+ "AudioVolumeUp" => "AudioVolumeUp" . to_string ( ) ,
149+ "AudioVolumeDown" => "AudioVolumeDown" . to_string ( ) ,
150+ "AudioVolumeMute" => "AudioVolumeMute" . to_string ( ) ,
151+ "MediaPlayPause" => "MediaPlayPause" . to_string ( ) ,
152+ "MediaStop" => "MediaStop" . to_string ( ) ,
153+ "MediaTrackNext" => "MediaTrackNext" . to_string ( ) ,
154+ "MediaTrackPrevious" => "MediaTrackPrevious" . to_string ( ) ,
155+
156+ // Letter keys - ensure uppercase
157+ k if k. len ( ) == 1 && k. chars ( ) . all ( |c| c. is_alphabetic ( ) ) => {
158+ k. to_uppercase ( )
159+ }
160+
161+ // Number keys (already handled above for shifted versions)
162+ "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" => key. to_string ( ) ,
163+
164+ _ => key. to_string ( ) ,
79165 }
80166 }
81167}
@@ -131,7 +217,6 @@ pub fn validate_key_combination_with_rules(
131217 matches ! (
132218 key,
133219 "CommandOrControl"
134- | "Super"
135220 | "Shift"
136221 | "Alt"
137222 | "Control"
@@ -140,6 +225,7 @@ pub fn validate_key_combination_with_rules(
140225 | "Ctrl"
141226 | "Option"
142227 | "Meta"
228+ | "Super" // Super will be normalized to CommandOrControl
143229 )
144230 } ;
145231
@@ -243,11 +329,11 @@ mod tests {
243329 assert_eq ! ( normalize_shortcut_keys( "Alt+A" ) , "Alt+A" ) ;
244330 assert_eq ! ( normalize_shortcut_keys( "Shift+Space" ) , "Shift+Space" ) ;
245331
246- // Test Super modifier (Command on macOS )
247- assert_eq ! ( normalize_shortcut_keys( "Super+A" ) , "Super +A" ) ;
248- assert_eq ! ( normalize_shortcut_keys( "Super+Control+A" ) , "Super +Control+A" ) ;
249- assert_eq ! ( normalize_shortcut_keys( "Super+Control+Alt+A" ) , "Super +Control+Alt+A" ) ;
250- assert_eq ! ( normalize_shortcut_keys( "Super+Control+Alt+Shift+A" ) , "Super +Control+Alt+Shift+A" ) ;
332+ // Test Super modifier (maps to CommandOrControl for Tauri )
333+ assert_eq ! ( normalize_shortcut_keys( "Super+A" ) , "CommandOrControl +A" ) ;
334+ assert_eq ! ( normalize_shortcut_keys( "Super+Control+A" ) , "CommandOrControl +Control+A" ) ;
335+ assert_eq ! ( normalize_shortcut_keys( "Super+Control+Alt+A" ) , "CommandOrControl +Control+Alt+A" ) ;
336+ assert_eq ! ( normalize_shortcut_keys( "Super+Control+Alt+Shift+A" ) , "CommandOrControl +Control+Alt+Shift+A" ) ;
251337 }
252338
253339 #[ test]
@@ -301,8 +387,8 @@ mod tests {
301387 assert ! ( validate_key_combination( "CommandOrControl+ü" ) . is_ok( ) ) ;
302388 assert ! ( validate_key_combination( "Alt+ñ" ) . is_ok( ) ) ;
303389
304- // Test Super modifier combinations (Command on macOS )
305- assert ! ( validate_key_combination( "Super+A" ) . is_ok( ) ) ;
390+ // Test Super modifier combinations (maps to CommandOrControl for Tauri )
391+ assert ! ( validate_key_combination( "Super+A" ) . is_ok( ) ) ; // Will be normalized to CommandOrControl
306392 assert ! ( validate_key_combination( "Super+Control+A" ) . is_ok( ) ) ;
307393 assert ! ( validate_key_combination( "Super+Control+Alt+A" ) . is_ok( ) ) ;
308394 assert ! ( validate_key_combination( "Super+Control+Alt+Shift+A" ) . is_ok( ) ) ;
0 commit comments