1use collections::HashMap;
2use std::ffi::{CStr, c_void};
3
4use objc::{msg_send, runtime::Object, sel, sel_impl};
5
6use crate::{KeybindingKeystroke, Keystroke, PlatformKeyboardLayout, PlatformKeyboardMapper};
7
8use super::{
9 TISCopyCurrentKeyboardLayoutInputSource, TISGetInputSourceProperty, kTISPropertyInputSourceID,
10 kTISPropertyLocalizedName,
11};
12
13pub(crate) struct MacKeyboardLayout {
14 id: String,
15 name: String,
16}
17
18pub(crate) struct MacKeyboardMapper {
19 key_equivalents: Option<HashMap<char, char>>,
20}
21
22impl PlatformKeyboardLayout for MacKeyboardLayout {
23 fn id(&self) -> &str {
24 &self.id
25 }
26
27 fn name(&self) -> &str {
28 &self.name
29 }
30}
31
32impl PlatformKeyboardMapper for MacKeyboardMapper {
33 fn map_key_equivalent(
34 &self,
35 mut keystroke: Keystroke,
36 use_key_equivalents: bool,
37 ) -> KeybindingKeystroke {
38 if use_key_equivalents && let Some(key_equivalents) = &self.key_equivalents {
39 if keystroke.key.chars().count() == 1
40 && let Some(key) = key_equivalents.get(&keystroke.key.chars().next().unwrap())
41 {
42 keystroke.key = key.to_string();
43 }
44 }
45 KeybindingKeystroke::from_keystroke(keystroke)
46 }
47
48 fn get_key_equivalents(&self) -> Option<&HashMap<char, char>> {
49 self.key_equivalents.as_ref()
50 }
51}
52
53impl MacKeyboardLayout {
54 pub(crate) fn new() -> Self {
55 unsafe {
56 let current_keyboard = TISCopyCurrentKeyboardLayoutInputSource();
57
58 let id: *mut Object = TISGetInputSourceProperty(
59 current_keyboard,
60 kTISPropertyInputSourceID as *const c_void,
61 );
62 let id: *const std::os::raw::c_char = msg_send![id, UTF8String];
63 let id = CStr::from_ptr(id).to_str().unwrap().to_string();
64
65 let name: *mut Object = TISGetInputSourceProperty(
66 current_keyboard,
67 kTISPropertyLocalizedName as *const c_void,
68 );
69 let name: *const std::os::raw::c_char = msg_send![name, UTF8String];
70 let name = CStr::from_ptr(name).to_str().unwrap().to_string();
71
72 Self { id, name }
73 }
74 }
75}
76
77impl MacKeyboardMapper {
78 pub(crate) fn new(layout_id: &str) -> Self {
79 let key_equivalents = get_key_equivalents(layout_id);
80
81 Self { key_equivalents }
82 }
83}
84
85// On some keyboards (e.g. German QWERTZ) it is not possible to type the full ASCII range
86// without using option. This means that some of our built in keyboard shortcuts do not work
87// for those users.
88//
89// The way macOS solves this problem is to move shortcuts around so that they are all reachable,
90// even if the mnemonic changes. https://developer.apple.com/documentation/swiftui/keyboardshortcut/localization-swift.struct
91//
92// For example, cmd-> is the "switch window" shortcut because the > key is right above tab.
93// To ensure this doesn't cause problems for shortcuts defined for a QWERTY layout, apple moves
94// any shortcuts defined as cmd-> to cmd-:. Coincidentally this s also the same keyboard position
95// as cmd-> on a QWERTY layout.
96//
97// Another example is cmd-[ and cmd-], as they cannot be typed without option, those keys are remapped to cmd-ö
98// and cmd-ä. These shortcuts are not in the same position as a QWERTY keyboard, because on a QWERTZ keyboard
99// the + key is in the way; and shortcuts bound to cmd-+ are still typed as cmd-+ on either keyboard (though the
100// specific key moves)
101//
102// As far as I can tell, there's no way to query the mappings Apple uses except by rendering a menu with every
103// possible key combination, and inspecting the UI to see what it rendered. So that's what we did...
104//
105// These mappings were generated by running https://github.com/ConradIrwin/keyboard-inspector, tidying up the
106// output to remove languages with no mappings and other oddities, and converting it to a less verbose representation with:
107// jq -s 'map(to_entries | map({key: .key, value: [(.value | to_entries | map(.key) | join("")), (.value | to_entries | map(.value) | join(""))]}) | from_entries) | add'
108// From there I used multi-cursor to produce this match statement.
109fn get_key_equivalents(layout_id: &str) -> Option<HashMap<char, char>> {
110 let mappings: &[(char, char)] = match layout_id {
111 "com.apple.keylayout.ABC-AZERTY" => &[
112 ('!', '1'),
113 ('"', '%'),
114 ('#', '3'),
115 ('$', '4'),
116 ('%', '5'),
117 ('&', '7'),
118 ('(', '9'),
119 (')', '0'),
120 ('*', '8'),
121 ('.', ';'),
122 ('/', ':'),
123 ('0', 'à'),
124 ('1', '&'),
125 ('2', 'é'),
126 ('3', '"'),
127 ('4', '\''),
128 ('5', '('),
129 ('6', '§'),
130 ('7', 'è'),
131 ('8', '!'),
132 ('9', 'ç'),
133 (':', '°'),
134 (';', ')'),
135 ('<', '.'),
136 ('>', '/'),
137 ('@', '2'),
138 ('[', '^'),
139 ('\'', 'ù'),
140 ('\\', '`'),
141 (']', '$'),
142 ('^', '6'),
143 ('`', '<'),
144 ('{', '¨'),
145 ('|', '£'),
146 ('}', '*'),
147 ('~', '>'),
148 ],
149 "com.apple.keylayout.ABC-QWERTZ" => &[
150 ('"', '`'),
151 ('#', '§'),
152 ('&', '/'),
153 ('(', ')'),
154 (')', '='),
155 ('*', '('),
156 ('/', 'ß'),
157 (':', 'Ü'),
158 (';', 'ü'),
159 ('<', ';'),
160 ('=', '*'),
161 ('>', ':'),
162 ('@', '"'),
163 ('[', 'ö'),
164 ('\'', '´'),
165 ('\\', '#'),
166 (']', 'ä'),
167 ('^', '&'),
168 ('`', '<'),
169 ('{', 'Ö'),
170 ('|', '\''),
171 ('}', 'Ä'),
172 ('~', '>'),
173 ],
174 "com.apple.keylayout.Albanian" => &[
175 ('"', '\''),
176 (':', 'Ç'),
177 (';', 'ç'),
178 ('<', ';'),
179 ('>', ':'),
180 ('@', '"'),
181 ('\'', '@'),
182 ('\\', 'ë'),
183 ('`', '<'),
184 ('|', 'Ë'),
185 ('~', '>'),
186 ],
187 "com.apple.keylayout.Austrian" => &[
188 ('"', '`'),
189 ('#', '§'),
190 ('&', '/'),
191 ('(', ')'),
192 (')', '='),
193 ('*', '('),
194 ('/', 'ß'),
195 (':', 'Ü'),
196 (';', 'ü'),
197 ('<', ';'),
198 ('=', '*'),
199 ('>', ':'),
200 ('@', '"'),
201 ('[', 'ö'),
202 ('\'', '´'),
203 ('\\', '#'),
204 (']', 'ä'),
205 ('^', '&'),
206 ('`', '<'),
207 ('{', 'Ö'),
208 ('|', '\''),
209 ('}', 'Ä'),
210 ('~', '>'),
211 ],
212 "com.apple.keylayout.Azeri" => &[
213 ('"', 'Ə'),
214 (',', 'ç'),
215 ('.', 'ş'),
216 ('/', '.'),
217 (':', 'I'),
218 (';', 'ı'),
219 ('<', 'Ç'),
220 ('>', 'Ş'),
221 ('?', ','),
222 ('W', 'Ü'),
223 ('[', 'ö'),
224 ('\'', 'ə'),
225 (']', 'ğ'),
226 ('w', 'ü'),
227 ('{', 'Ö'),
228 ('|', '/'),
229 ('}', 'Ğ'),
230 ],
231 "com.apple.keylayout.Belgian" => &[
232 ('!', '1'),
233 ('"', '%'),
234 ('#', '3'),
235 ('$', '4'),
236 ('%', '5'),
237 ('&', '7'),
238 ('(', '9'),
239 (')', '0'),
240 ('*', '8'),
241 ('.', ';'),
242 ('/', ':'),
243 ('0', 'à'),
244 ('1', '&'),
245 ('2', 'é'),
246 ('3', '"'),
247 ('4', '\''),
248 ('5', '('),
249 ('6', '§'),
250 ('7', 'è'),
251 ('8', '!'),
252 ('9', 'ç'),
253 (':', '°'),
254 (';', ')'),
255 ('<', '.'),
256 ('>', '/'),
257 ('@', '2'),
258 ('[', '^'),
259 ('\'', 'ù'),
260 ('\\', '`'),
261 (']', '$'),
262 ('^', '6'),
263 ('`', '<'),
264 ('{', '¨'),
265 ('|', '£'),
266 ('}', '*'),
267 ('~', '>'),
268 ],
269 "com.apple.keylayout.Brazilian-ABNT2" => &[
270 ('"', '`'),
271 ('/', 'ç'),
272 ('?', 'Ç'),
273 ('\'', '´'),
274 ('\\', '~'),
275 ('^', '¨'),
276 ('`', '\''),
277 ('|', '^'),
278 ('~', '"'),
279 ],
280 "com.apple.keylayout.Brazilian-Pro" => &[('^', 'ˆ'), ('~', '˜')],
281 "com.apple.keylayout.British" => &[('#', '£')],
282 "com.apple.keylayout.Canadian-CSA" => &[
283 ('"', 'È'),
284 ('/', 'é'),
285 ('<', '\''),
286 ('>', '"'),
287 ('?', 'É'),
288 ('[', '^'),
289 ('\'', 'è'),
290 ('\\', 'à'),
291 (']', 'ç'),
292 ('`', 'ù'),
293 ('{', '¨'),
294 ('|', 'À'),
295 ('}', 'Ç'),
296 ('~', 'Ù'),
297 ],
298 "com.apple.keylayout.Croatian" => &[
299 ('"', 'Ć'),
300 ('&', '\''),
301 ('(', ')'),
302 (')', '='),
303 ('*', '('),
304 (':', 'Č'),
305 (';', 'č'),
306 ('<', ';'),
307 ('=', '*'),
308 ('>', ':'),
309 ('@', '"'),
310 ('[', 'š'),
311 ('\'', 'ć'),
312 ('\\', 'ž'),
313 (']', 'đ'),
314 ('^', '&'),
315 ('`', '<'),
316 ('{', 'Š'),
317 ('|', 'Ž'),
318 ('}', 'Đ'),
319 ('~', '>'),
320 ],
321 "com.apple.keylayout.Croatian-PC" => &[
322 ('"', 'Ć'),
323 ('&', '/'),
324 ('(', ')'),
325 (')', '='),
326 ('*', '('),
327 ('/', '\''),
328 (':', 'Č'),
329 (';', 'č'),
330 ('<', ';'),
331 ('=', '*'),
332 ('>', ':'),
333 ('@', '"'),
334 ('[', 'š'),
335 ('\'', 'ć'),
336 ('\\', 'ž'),
337 (']', 'đ'),
338 ('^', '&'),
339 ('`', '<'),
340 ('{', 'Š'),
341 ('|', 'Ž'),
342 ('}', 'Đ'),
343 ('~', '>'),
344 ],
345 "com.apple.keylayout.Czech" => &[
346 ('!', '1'),
347 ('"', '!'),
348 ('#', '3'),
349 ('$', '4'),
350 ('%', '5'),
351 ('&', '7'),
352 ('(', '9'),
353 (')', '0'),
354 ('*', '8'),
355 ('+', '%'),
356 ('/', '\''),
357 ('0', 'é'),
358 ('1', '+'),
359 ('2', 'ě'),
360 ('3', 'š'),
361 ('4', 'č'),
362 ('5', 'ř'),
363 ('6', 'ž'),
364 ('7', 'ý'),
365 ('8', 'á'),
366 ('9', 'í'),
367 (':', '"'),
368 (';', 'ů'),
369 ('<', '?'),
370 ('>', ':'),
371 ('?', 'ˇ'),
372 ('@', '2'),
373 ('[', 'ú'),
374 ('\'', '§'),
375 (']', ')'),
376 ('^', '6'),
377 ('`', '¨'),
378 ('{', 'Ú'),
379 ('}', '('),
380 ('~', '`'),
381 ],
382 "com.apple.keylayout.Czech-QWERTY" => &[
383 ('!', '1'),
384 ('"', '!'),
385 ('#', '3'),
386 ('$', '4'),
387 ('%', '5'),
388 ('&', '7'),
389 ('(', '9'),
390 (')', '0'),
391 ('*', '8'),
392 ('+', '%'),
393 ('/', '\''),
394 ('0', 'é'),
395 ('1', '+'),
396 ('2', 'ě'),
397 ('3', 'š'),
398 ('4', 'č'),
399 ('5', 'ř'),
400 ('6', 'ž'),
401 ('7', 'ý'),
402 ('8', 'á'),
403 ('9', 'í'),
404 (':', '"'),
405 (';', 'ů'),
406 ('<', '?'),
407 ('>', ':'),
408 ('?', 'ˇ'),
409 ('@', '2'),
410 ('[', 'ú'),
411 ('\'', '§'),
412 (']', ')'),
413 ('^', '6'),
414 ('`', '¨'),
415 ('{', 'Ú'),
416 ('}', '('),
417 ('~', '`'),
418 ],
419 "com.apple.keylayout.Danish" => &[
420 ('"', '^'),
421 ('$', '€'),
422 ('&', '/'),
423 ('(', ')'),
424 (')', '='),
425 ('*', '('),
426 ('/', '´'),
427 (':', 'Å'),
428 (';', 'å'),
429 ('<', ';'),
430 ('=', '`'),
431 ('>', ':'),
432 ('@', '"'),
433 ('[', 'æ'),
434 ('\'', '¨'),
435 ('\\', '\''),
436 (']', 'ø'),
437 ('^', '&'),
438 ('`', '<'),
439 ('{', 'Æ'),
440 ('|', '*'),
441 ('}', 'Ø'),
442 ('~', '>'),
443 ],
444 "com.apple.keylayout.Faroese" => &[
445 ('"', 'Ø'),
446 ('$', '€'),
447 ('&', '/'),
448 ('(', ')'),
449 (')', '='),
450 ('*', '('),
451 ('/', '´'),
452 (':', 'Æ'),
453 (';', 'æ'),
454 ('<', ';'),
455 ('=', '`'),
456 ('>', ':'),
457 ('@', '"'),
458 ('[', 'å'),
459 ('\'', 'ø'),
460 ('\\', '\''),
461 (']', 'ð'),
462 ('^', '&'),
463 ('`', '<'),
464 ('{', 'Å'),
465 ('|', '*'),
466 ('}', 'Ð'),
467 ('~', '>'),
468 ],
469 "com.apple.keylayout.Finnish" => &[
470 ('"', '^'),
471 ('$', '€'),
472 ('&', '/'),
473 ('(', ')'),
474 (')', '='),
475 ('*', '('),
476 ('/', '´'),
477 (':', 'Å'),
478 (';', 'å'),
479 ('<', ';'),
480 ('=', '`'),
481 ('>', ':'),
482 ('@', '"'),
483 ('[', 'ö'),
484 ('\'', '¨'),
485 ('\\', '\''),
486 (']', 'ä'),
487 ('^', '&'),
488 ('`', '<'),
489 ('{', 'Ö'),
490 ('|', '*'),
491 ('}', 'Ä'),
492 ('~', '>'),
493 ],
494 "com.apple.keylayout.FinnishExtended" => &[
495 ('"', 'ˆ'),
496 ('$', '€'),
497 ('&', '/'),
498 ('(', ')'),
499 (')', '='),
500 ('*', '('),
501 ('/', '´'),
502 (':', 'Å'),
503 (';', 'å'),
504 ('<', ';'),
505 ('=', '`'),
506 ('>', ':'),
507 ('@', '"'),
508 ('[', 'ö'),
509 ('\'', '¨'),
510 ('\\', '\''),
511 (']', 'ä'),
512 ('^', '&'),
513 ('`', '<'),
514 ('{', 'Ö'),
515 ('|', '*'),
516 ('}', 'Ä'),
517 ('~', '>'),
518 ],
519 "com.apple.keylayout.FinnishSami-PC" => &[
520 ('"', 'ˆ'),
521 ('&', '/'),
522 ('(', ')'),
523 (')', '='),
524 ('*', '('),
525 ('/', '´'),
526 (':', 'Å'),
527 (';', 'å'),
528 ('<', ';'),
529 ('=', '`'),
530 ('>', ':'),
531 ('@', '"'),
532 ('[', 'ö'),
533 ('\'', '¨'),
534 ('\\', '@'),
535 (']', 'ä'),
536 ('^', '&'),
537 ('`', '<'),
538 ('{', 'Ö'),
539 ('|', '*'),
540 ('}', 'Ä'),
541 ('~', '>'),
542 ],
543 "com.apple.keylayout.French" => &[
544 ('!', '1'),
545 ('"', '%'),
546 ('#', '3'),
547 ('$', '4'),
548 ('%', '5'),
549 ('&', '7'),
550 ('(', '9'),
551 (')', '0'),
552 ('*', '8'),
553 ('.', ';'),
554 ('/', ':'),
555 ('0', 'à'),
556 ('1', '&'),
557 ('2', 'é'),
558 ('3', '"'),
559 ('4', '\''),
560 ('5', '('),
561 ('6', '§'),
562 ('7', 'è'),
563 ('8', '!'),
564 ('9', 'ç'),
565 (':', '°'),
566 (';', ')'),
567 ('<', '.'),
568 ('>', '/'),
569 ('@', '2'),
570 ('[', '^'),
571 ('\'', 'ù'),
572 ('\\', '`'),
573 (']', '$'),
574 ('^', '6'),
575 ('`', '<'),
576 ('{', '¨'),
577 ('|', '£'),
578 ('}', '*'),
579 ('~', '>'),
580 ],
581 "com.apple.keylayout.French-PC" => &[
582 ('!', '1'),
583 ('"', '%'),
584 ('#', '3'),
585 ('$', '4'),
586 ('%', '5'),
587 ('&', '7'),
588 ('(', '9'),
589 (')', '0'),
590 ('*', '8'),
591 ('-', ')'),
592 ('.', ';'),
593 ('/', ':'),
594 ('0', 'à'),
595 ('1', '&'),
596 ('2', 'é'),
597 ('3', '"'),
598 ('4', '\''),
599 ('5', '('),
600 ('6', '-'),
601 ('7', 'è'),
602 ('8', '_'),
603 ('9', 'ç'),
604 (':', '§'),
605 (';', '!'),
606 ('<', '.'),
607 ('>', '/'),
608 ('@', '2'),
609 ('[', '^'),
610 ('\'', 'ù'),
611 ('\\', '*'),
612 (']', '$'),
613 ('^', '6'),
614 ('_', '°'),
615 ('`', '<'),
616 ('{', '¨'),
617 ('|', 'μ'),
618 ('}', '£'),
619 ('~', '>'),
620 ],
621 "com.apple.keylayout.French-numerical" => &[
622 ('!', '1'),
623 ('"', '%'),
624 ('#', '3'),
625 ('$', '4'),
626 ('%', '5'),
627 ('&', '7'),
628 ('(', '9'),
629 (')', '0'),
630 ('*', '8'),
631 ('.', ';'),
632 ('/', ':'),
633 ('0', 'à'),
634 ('1', '&'),
635 ('2', 'é'),
636 ('3', '"'),
637 ('4', '\''),
638 ('5', '('),
639 ('6', '§'),
640 ('7', 'è'),
641 ('8', '!'),
642 ('9', 'ç'),
643 (':', '°'),
644 (';', ')'),
645 ('<', '.'),
646 ('>', '/'),
647 ('@', '2'),
648 ('[', '^'),
649 ('\'', 'ù'),
650 ('\\', '`'),
651 (']', '$'),
652 ('^', '6'),
653 ('`', '<'),
654 ('{', '¨'),
655 ('|', '£'),
656 ('}', '*'),
657 ('~', '>'),
658 ],
659 "com.apple.keylayout.German" => &[
660 ('"', '`'),
661 ('#', '§'),
662 ('&', '/'),
663 ('(', ')'),
664 (')', '='),
665 ('*', '('),
666 ('/', 'ß'),
667 (':', 'Ü'),
668 (';', 'ü'),
669 ('<', ';'),
670 ('=', '*'),
671 ('>', ':'),
672 ('@', '"'),
673 ('[', 'ö'),
674 ('\'', '´'),
675 ('\\', '#'),
676 (']', 'ä'),
677 ('^', '&'),
678 ('`', '<'),
679 ('{', 'Ö'),
680 ('|', '\''),
681 ('}', 'Ä'),
682 ('~', '>'),
683 ],
684 "com.apple.keylayout.German-DIN-2137" => &[
685 ('"', '`'),
686 ('#', '§'),
687 ('&', '/'),
688 ('(', ')'),
689 (')', '='),
690 ('*', '('),
691 ('/', 'ß'),
692 (':', 'Ü'),
693 (';', 'ü'),
694 ('<', ';'),
695 ('=', '*'),
696 ('>', ':'),
697 ('@', '"'),
698 ('[', 'ö'),
699 ('\'', '´'),
700 ('\\', '#'),
701 (']', 'ä'),
702 ('^', '&'),
703 ('`', '<'),
704 ('{', 'Ö'),
705 ('|', '\''),
706 ('}', 'Ä'),
707 ('~', '>'),
708 ],
709 "com.apple.keylayout.Hawaiian" => &[('\'', 'ʻ')],
710 "com.apple.keylayout.Hungarian" => &[
711 ('!', '\''),
712 ('"', 'Á'),
713 ('#', '+'),
714 ('$', '!'),
715 ('&', '='),
716 ('(', ')'),
717 (')', 'Ö'),
718 ('*', '('),
719 ('+', 'Ó'),
720 ('/', 'ü'),
721 ('0', 'ö'),
722 (':', 'É'),
723 (';', 'é'),
724 ('<', 'Ü'),
725 ('=', 'ó'),
726 ('>', ':'),
727 ('@', '"'),
728 ('[', 'ő'),
729 ('\'', 'á'),
730 ('\\', 'ű'),
731 (']', 'ú'),
732 ('^', '/'),
733 ('`', 'í'),
734 ('{', 'Ő'),
735 ('|', 'Ű'),
736 ('}', 'Ú'),
737 ('~', 'Í'),
738 ],
739 "com.apple.keylayout.Hungarian-QWERTY" => &[
740 ('!', '\''),
741 ('"', 'Á'),
742 ('#', '+'),
743 ('$', '!'),
744 ('&', '='),
745 ('(', ')'),
746 (')', 'Ö'),
747 ('*', '('),
748 ('+', 'Ó'),
749 ('/', 'ü'),
750 ('0', 'ö'),
751 (':', 'É'),
752 (';', 'é'),
753 ('<', 'Ü'),
754 ('=', 'ó'),
755 ('>', ':'),
756 ('@', '"'),
757 ('[', 'ő'),
758 ('\'', 'á'),
759 ('\\', 'ű'),
760 (']', 'ú'),
761 ('^', '/'),
762 ('`', 'í'),
763 ('{', 'Ő'),
764 ('|', 'Ű'),
765 ('}', 'Ú'),
766 ('~', 'Í'),
767 ],
768 "com.apple.keylayout.Icelandic" => &[
769 ('"', 'Ö'),
770 ('&', '/'),
771 ('(', ')'),
772 (')', '='),
773 ('*', '('),
774 ('/', '\''),
775 (':', 'Ð'),
776 (';', 'ð'),
777 ('<', ';'),
778 ('=', '*'),
779 ('>', ':'),
780 ('@', '"'),
781 ('[', 'æ'),
782 ('\'', 'ö'),
783 ('\\', 'þ'),
784 (']', '´'),
785 ('^', '&'),
786 ('`', '<'),
787 ('{', 'Æ'),
788 ('|', 'Þ'),
789 ('}', '´'),
790 ('~', '>'),
791 ],
792 "com.apple.keylayout.Irish" => &[('#', '£')],
793 "com.apple.keylayout.IrishExtended" => &[('#', '£')],
794 "com.apple.keylayout.Italian" => &[
795 ('!', '1'),
796 ('"', '%'),
797 ('#', '3'),
798 ('$', '4'),
799 ('%', '5'),
800 ('&', '7'),
801 ('(', '9'),
802 (')', '0'),
803 ('*', '8'),
804 (',', ';'),
805 ('.', ':'),
806 ('/', ','),
807 ('0', 'é'),
808 ('1', '&'),
809 ('2', '"'),
810 ('3', '\''),
811 ('4', '('),
812 ('5', 'ç'),
813 ('6', 'è'),
814 ('7', ')'),
815 ('8', '£'),
816 ('9', 'à'),
817 (':', '!'),
818 (';', 'ò'),
819 ('<', '.'),
820 ('>', '/'),
821 ('@', '2'),
822 ('[', 'ì'),
823 ('\'', 'ù'),
824 ('\\', '§'),
825 (']', '$'),
826 ('^', '6'),
827 ('`', '<'),
828 ('{', '^'),
829 ('|', '°'),
830 ('}', '*'),
831 ('~', '>'),
832 ],
833 "com.apple.keylayout.Italian-Pro" => &[
834 ('"', '^'),
835 ('#', '£'),
836 ('&', '/'),
837 ('(', ')'),
838 (')', '='),
839 ('*', '('),
840 ('/', '\''),
841 (':', 'é'),
842 (';', 'è'),
843 ('<', ';'),
844 ('=', '*'),
845 ('>', ':'),
846 ('@', '"'),
847 ('[', 'ò'),
848 ('\'', 'ì'),
849 ('\\', 'ù'),
850 (']', 'à'),
851 ('^', '&'),
852 ('`', '<'),
853 ('{', 'ç'),
854 ('|', '§'),
855 ('}', '°'),
856 ('~', '>'),
857 ],
858 "com.apple.keylayout.LatinAmerican" => &[
859 ('"', '¨'),
860 ('&', '/'),
861 ('(', ')'),
862 (')', '='),
863 ('*', '('),
864 ('/', '\''),
865 (':', 'Ñ'),
866 (';', 'ñ'),
867 ('<', ';'),
868 ('=', '*'),
869 ('>', ':'),
870 ('@', '"'),
871 ('[', '{'),
872 ('\'', '´'),
873 ('\\', '¿'),
874 (']', '}'),
875 ('^', '&'),
876 ('`', '<'),
877 ('{', '['),
878 ('|', '¡'),
879 ('}', ']'),
880 ('~', '>'),
881 ],
882 "com.apple.keylayout.Lithuanian" => &[
883 ('!', 'Ą'),
884 ('#', 'Ę'),
885 ('$', 'Ė'),
886 ('%', 'Į'),
887 ('&', 'Ų'),
888 ('*', 'Ū'),
889 ('+', 'Ž'),
890 ('1', 'ą'),
891 ('2', 'č'),
892 ('3', 'ę'),
893 ('4', 'ė'),
894 ('5', 'į'),
895 ('6', 'š'),
896 ('7', 'ų'),
897 ('8', 'ū'),
898 ('=', 'ž'),
899 ('@', 'Č'),
900 ('^', 'Š'),
901 ],
902 "com.apple.keylayout.Maltese" => &[
903 ('#', '£'),
904 ('[', 'ġ'),
905 (']', 'ħ'),
906 ('`', 'ż'),
907 ('{', 'Ġ'),
908 ('}', 'Ħ'),
909 ('~', 'Ż'),
910 ],
911 "com.apple.keylayout.NorthernSami" => &[
912 ('"', 'Ŋ'),
913 ('&', '/'),
914 ('(', ')'),
915 (')', '='),
916 ('*', '('),
917 ('/', '´'),
918 (':', 'Å'),
919 (';', 'å'),
920 ('<', ';'),
921 ('=', '`'),
922 ('>', ':'),
923 ('@', '"'),
924 ('Q', 'Á'),
925 ('W', 'Š'),
926 ('X', 'Č'),
927 ('[', 'ø'),
928 ('\'', 'ŋ'),
929 ('\\', 'đ'),
930 (']', 'æ'),
931 ('^', '&'),
932 ('`', 'ž'),
933 ('q', 'á'),
934 ('w', 'š'),
935 ('x', 'č'),
936 ('{', 'Ø'),
937 ('|', 'Đ'),
938 ('}', 'Æ'),
939 ('~', 'Ž'),
940 ],
941 "com.apple.keylayout.Norwegian" => &[
942 ('"', '^'),
943 ('&', '/'),
944 ('(', ')'),
945 (')', '='),
946 ('*', '('),
947 ('/', '´'),
948 (':', 'Å'),
949 (';', 'å'),
950 ('<', ';'),
951 ('=', '`'),
952 ('>', ':'),
953 ('@', '"'),
954 ('[', 'ø'),
955 ('\'', '¨'),
956 ('\\', '@'),
957 (']', 'æ'),
958 ('^', '&'),
959 ('`', '<'),
960 ('{', 'Ø'),
961 ('|', '*'),
962 ('}', 'Æ'),
963 ('~', '>'),
964 ],
965 "com.apple.keylayout.NorwegianExtended" => &[
966 ('"', 'ˆ'),
967 ('&', '/'),
968 ('(', ')'),
969 (')', '='),
970 ('*', '('),
971 ('/', '´'),
972 (':', 'Å'),
973 (';', 'å'),
974 ('<', ';'),
975 ('=', '`'),
976 ('>', ':'),
977 ('@', '"'),
978 ('[', 'ø'),
979 ('\\', '@'),
980 (']', 'æ'),
981 ('`', '<'),
982 ('}', 'Æ'),
983 ('~', '>'),
984 ],
985 "com.apple.keylayout.NorwegianSami-PC" => &[
986 ('"', 'ˆ'),
987 ('&', '/'),
988 ('(', ')'),
989 (')', '='),
990 ('*', '('),
991 ('/', '´'),
992 (':', 'Å'),
993 (';', 'å'),
994 ('<', ';'),
995 ('=', '`'),
996 ('>', ':'),
997 ('@', '"'),
998 ('[', 'ø'),
999 ('\'', '¨'),
1000 ('\\', '@'),
1001 (']', 'æ'),
1002 ('^', '&'),
1003 ('`', '<'),
1004 ('{', 'Ø'),
1005 ('|', '*'),
1006 ('}', 'Æ'),
1007 ('~', '>'),
1008 ],
1009 "com.apple.keylayout.Polish" => &[
1010 ('!', '§'),
1011 ('"', 'ę'),
1012 ('#', '!'),
1013 ('$', '?'),
1014 ('%', '+'),
1015 ('&', ':'),
1016 ('(', '/'),
1017 (')', '"'),
1018 ('*', '_'),
1019 ('+', ']'),
1020 (',', '.'),
1021 ('.', ','),
1022 ('/', 'ż'),
1023 (':', 'Ł'),
1024 (';', 'ł'),
1025 ('<', 'ś'),
1026 ('=', '['),
1027 ('>', 'ń'),
1028 ('?', 'Ż'),
1029 ('@', '%'),
1030 ('[', 'ó'),
1031 ('\'', 'ą'),
1032 ('\\', ';'),
1033 (']', '('),
1034 ('^', '='),
1035 ('_', 'ć'),
1036 ('`', '<'),
1037 ('{', 'ź'),
1038 ('|', '$'),
1039 ('}', ')'),
1040 ('~', '>'),
1041 ],
1042 "com.apple.keylayout.Portuguese" => &[
1043 ('"', '`'),
1044 ('&', '/'),
1045 ('(', ')'),
1046 (')', '='),
1047 ('*', '('),
1048 ('/', '\''),
1049 (':', 'ª'),
1050 (';', 'º'),
1051 ('<', ';'),
1052 ('=', '*'),
1053 ('>', ':'),
1054 ('@', '"'),
1055 ('[', 'ç'),
1056 ('\'', '´'),
1057 (']', '~'),
1058 ('^', '&'),
1059 ('`', '<'),
1060 ('{', 'Ç'),
1061 ('}', '^'),
1062 ('~', '>'),
1063 ],
1064 "com.apple.keylayout.Sami-PC" => &[
1065 ('"', 'Ŋ'),
1066 ('&', '/'),
1067 ('(', ')'),
1068 (')', '='),
1069 ('*', '('),
1070 ('/', '´'),
1071 (':', 'Å'),
1072 (';', 'å'),
1073 ('<', ';'),
1074 ('=', '`'),
1075 ('>', ':'),
1076 ('@', '"'),
1077 ('Q', 'Á'),
1078 ('W', 'Š'),
1079 ('X', 'Č'),
1080 ('[', 'ø'),
1081 ('\'', 'ŋ'),
1082 ('\\', 'đ'),
1083 (']', 'æ'),
1084 ('^', '&'),
1085 ('`', 'ž'),
1086 ('q', 'á'),
1087 ('w', 'š'),
1088 ('x', 'č'),
1089 ('{', 'Ø'),
1090 ('|', 'Đ'),
1091 ('}', 'Æ'),
1092 ('~', 'Ž'),
1093 ],
1094 "com.apple.keylayout.Serbian-Latin" => &[
1095 ('"', 'Ć'),
1096 ('&', '\''),
1097 ('(', ')'),
1098 (')', '='),
1099 ('*', '('),
1100 (':', 'Č'),
1101 (';', 'č'),
1102 ('<', ';'),
1103 ('=', '*'),
1104 ('>', ':'),
1105 ('@', '"'),
1106 ('[', 'š'),
1107 ('\'', 'ć'),
1108 ('\\', 'ž'),
1109 (']', 'đ'),
1110 ('^', '&'),
1111 ('`', '<'),
1112 ('{', 'Š'),
1113 ('|', 'Ž'),
1114 ('}', 'Đ'),
1115 ('~', '>'),
1116 ],
1117 "com.apple.keylayout.Slovak" => &[
1118 ('!', '1'),
1119 ('"', '!'),
1120 ('#', '3'),
1121 ('$', '4'),
1122 ('%', '5'),
1123 ('&', '7'),
1124 ('(', '9'),
1125 (')', '0'),
1126 ('*', '8'),
1127 ('+', '%'),
1128 ('/', '\''),
1129 ('0', 'é'),
1130 ('1', '+'),
1131 ('2', 'ľ'),
1132 ('3', 'š'),
1133 ('4', 'č'),
1134 ('5', 'ť'),
1135 ('6', 'ž'),
1136 ('7', 'ý'),
1137 ('8', 'á'),
1138 ('9', 'í'),
1139 (':', '"'),
1140 (';', 'ô'),
1141 ('<', '?'),
1142 ('>', ':'),
1143 ('?', 'ˇ'),
1144 ('@', '2'),
1145 ('[', 'ú'),
1146 ('\'', '§'),
1147 (']', 'ä'),
1148 ('^', '6'),
1149 ('`', 'ň'),
1150 ('{', 'Ú'),
1151 ('}', 'Ä'),
1152 ('~', 'Ň'),
1153 ],
1154 "com.apple.keylayout.Slovak-QWERTY" => &[
1155 ('!', '1'),
1156 ('"', '!'),
1157 ('#', '3'),
1158 ('$', '4'),
1159 ('%', '5'),
1160 ('&', '7'),
1161 ('(', '9'),
1162 (')', '0'),
1163 ('*', '8'),
1164 ('+', '%'),
1165 ('/', '\''),
1166 ('0', 'é'),
1167 ('1', '+'),
1168 ('2', 'ľ'),
1169 ('3', 'š'),
1170 ('4', 'č'),
1171 ('5', 'ť'),
1172 ('6', 'ž'),
1173 ('7', 'ý'),
1174 ('8', 'á'),
1175 ('9', 'í'),
1176 (':', '"'),
1177 (';', 'ô'),
1178 ('<', '?'),
1179 ('>', ':'),
1180 ('?', 'ˇ'),
1181 ('@', '2'),
1182 ('[', 'ú'),
1183 ('\'', '§'),
1184 (']', 'ä'),
1185 ('^', '6'),
1186 ('`', 'ň'),
1187 ('{', 'Ú'),
1188 ('}', 'Ä'),
1189 ('~', 'Ň'),
1190 ],
1191 "com.apple.keylayout.Slovenian" => &[
1192 ('"', 'Ć'),
1193 ('&', '\''),
1194 ('(', ')'),
1195 (')', '='),
1196 ('*', '('),
1197 (':', 'Č'),
1198 (';', 'č'),
1199 ('<', ';'),
1200 ('=', '*'),
1201 ('>', ':'),
1202 ('@', '"'),
1203 ('[', 'š'),
1204 ('\'', 'ć'),
1205 ('\\', 'ž'),
1206 (']', 'đ'),
1207 ('^', '&'),
1208 ('`', '<'),
1209 ('{', 'Š'),
1210 ('|', 'Ž'),
1211 ('}', 'Đ'),
1212 ('~', '>'),
1213 ],
1214 "com.apple.keylayout.Spanish" => &[
1215 ('!', '¡'),
1216 ('"', '¨'),
1217 ('.', 'ç'),
1218 ('/', '.'),
1219 (':', 'º'),
1220 (';', '´'),
1221 ('<', '¿'),
1222 ('>', 'Ç'),
1223 ('@', '!'),
1224 ('[', 'ñ'),
1225 ('\'', '`'),
1226 ('\\', '\''),
1227 (']', ';'),
1228 ('^', '/'),
1229 ('`', '<'),
1230 ('{', 'Ñ'),
1231 ('|', '"'),
1232 ('}', ':'),
1233 ('~', '>'),
1234 ],
1235 "com.apple.keylayout.Spanish-ISO" => &[
1236 ('"', '¨'),
1237 ('#', '·'),
1238 ('&', '/'),
1239 ('(', ')'),
1240 (')', '='),
1241 ('*', '('),
1242 ('.', 'ç'),
1243 ('/', '.'),
1244 (':', 'º'),
1245 (';', '´'),
1246 ('<', '¿'),
1247 ('>', 'Ç'),
1248 ('@', '"'),
1249 ('[', 'ñ'),
1250 ('\'', '`'),
1251 ('\\', '\''),
1252 (']', ';'),
1253 ('^', '&'),
1254 ('`', '<'),
1255 ('{', 'Ñ'),
1256 ('|', '"'),
1257 ('}', '`'),
1258 ('~', '>'),
1259 ],
1260 "com.apple.keylayout.Swedish" => &[
1261 ('"', '^'),
1262 ('$', '€'),
1263 ('&', '/'),
1264 ('(', ')'),
1265 (')', '='),
1266 ('*', '('),
1267 ('/', '´'),
1268 (':', 'Å'),
1269 (';', 'å'),
1270 ('<', ';'),
1271 ('=', '`'),
1272 ('>', ':'),
1273 ('@', '"'),
1274 ('[', 'ö'),
1275 ('\'', '¨'),
1276 ('\\', '\''),
1277 (']', 'ä'),
1278 ('^', '&'),
1279 ('`', '<'),
1280 ('{', 'Ö'),
1281 ('|', '*'),
1282 ('}', 'Ä'),
1283 ('~', '>'),
1284 ],
1285 "com.apple.keylayout.Swedish-Pro" => &[
1286 ('"', '^'),
1287 ('$', '€'),
1288 ('&', '/'),
1289 ('(', ')'),
1290 (')', '='),
1291 ('*', '('),
1292 ('/', '´'),
1293 (':', 'Å'),
1294 (';', 'å'),
1295 ('<', ';'),
1296 ('=', '`'),
1297 ('>', ':'),
1298 ('@', '"'),
1299 ('[', 'ö'),
1300 ('\'', '¨'),
1301 ('\\', '\''),
1302 (']', 'ä'),
1303 ('^', '&'),
1304 ('`', '<'),
1305 ('{', 'Ö'),
1306 ('|', '*'),
1307 ('}', 'Ä'),
1308 ('~', '>'),
1309 ],
1310 "com.apple.keylayout.SwedishSami-PC" => &[
1311 ('"', 'ˆ'),
1312 ('&', '/'),
1313 ('(', ')'),
1314 (')', '='),
1315 ('*', '('),
1316 ('/', '´'),
1317 (':', 'Å'),
1318 (';', 'å'),
1319 ('<', ';'),
1320 ('=', '`'),
1321 ('>', ':'),
1322 ('@', '"'),
1323 ('[', 'ö'),
1324 ('\'', '¨'),
1325 ('\\', '@'),
1326 (']', 'ä'),
1327 ('^', '&'),
1328 ('`', '<'),
1329 ('{', 'Ö'),
1330 ('|', '*'),
1331 ('}', 'Ä'),
1332 ('~', '>'),
1333 ],
1334 "com.apple.keylayout.SwissFrench" => &[
1335 ('!', '+'),
1336 ('"', '`'),
1337 ('#', '*'),
1338 ('$', 'ç'),
1339 ('&', '/'),
1340 ('(', ')'),
1341 (')', '='),
1342 ('*', '('),
1343 ('+', '!'),
1344 ('/', '\''),
1345 (':', 'ü'),
1346 (';', 'è'),
1347 ('<', ';'),
1348 ('=', '¨'),
1349 ('>', ':'),
1350 ('@', '"'),
1351 ('[', 'é'),
1352 ('\'', '^'),
1353 ('\\', '$'),
1354 (']', 'à'),
1355 ('^', '&'),
1356 ('`', '<'),
1357 ('{', 'ö'),
1358 ('|', '£'),
1359 ('}', 'ä'),
1360 ('~', '>'),
1361 ],
1362 "com.apple.keylayout.SwissGerman" => &[
1363 ('!', '+'),
1364 ('"', '`'),
1365 ('#', '*'),
1366 ('$', 'ç'),
1367 ('&', '/'),
1368 ('(', ')'),
1369 (')', '='),
1370 ('*', '('),
1371 ('+', '!'),
1372 ('/', '\''),
1373 (':', 'è'),
1374 (';', 'ü'),
1375 ('<', ';'),
1376 ('=', '¨'),
1377 ('>', ':'),
1378 ('@', '"'),
1379 ('[', 'ö'),
1380 ('\'', '^'),
1381 ('\\', '$'),
1382 (']', 'ä'),
1383 ('^', '&'),
1384 ('`', '<'),
1385 ('{', 'é'),
1386 ('|', '£'),
1387 ('}', 'à'),
1388 ('~', '>'),
1389 ],
1390 "com.apple.keylayout.Turkish" => &[
1391 ('"', '-'),
1392 ('#', '"'),
1393 ('$', '\''),
1394 ('%', '('),
1395 ('&', ')'),
1396 ('(', '%'),
1397 (')', ':'),
1398 ('*', '_'),
1399 (',', 'ö'),
1400 ('-', 'ş'),
1401 ('.', 'ç'),
1402 ('/', '.'),
1403 (':', '$'),
1404 ('<', 'Ö'),
1405 ('>', 'Ç'),
1406 ('@', '*'),
1407 ('[', 'ğ'),
1408 ('\'', ','),
1409 ('\\', 'ü'),
1410 (']', 'ı'),
1411 ('^', '/'),
1412 ('_', 'Ş'),
1413 ('`', '<'),
1414 ('{', 'Ğ'),
1415 ('|', 'Ü'),
1416 ('}', 'I'),
1417 ('~', '>'),
1418 ],
1419 "com.apple.keylayout.Turkish-QWERTY-PC" => &[
1420 ('"', 'I'),
1421 ('#', '^'),
1422 ('$', '+'),
1423 ('&', '/'),
1424 ('(', ')'),
1425 (')', '='),
1426 ('*', '('),
1427 ('+', ':'),
1428 (',', 'ö'),
1429 ('.', 'ç'),
1430 ('/', '*'),
1431 (':', 'Ş'),
1432 (';', 'ş'),
1433 ('<', 'Ö'),
1434 ('=', '.'),
1435 ('>', 'Ç'),
1436 ('@', '\''),
1437 ('[', 'ğ'),
1438 ('\'', 'ı'),
1439 ('\\', ','),
1440 (']', 'ü'),
1441 ('^', '&'),
1442 ('`', '<'),
1443 ('{', 'Ğ'),
1444 ('|', ';'),
1445 ('}', 'Ü'),
1446 ('~', '>'),
1447 ],
1448 "com.apple.keylayout.Turkish-Standard" => &[
1449 ('"', 'Ş'),
1450 ('#', '^'),
1451 ('&', '\''),
1452 ('(', ')'),
1453 (')', '='),
1454 ('*', '('),
1455 (',', '.'),
1456 ('.', ','),
1457 (':', 'Ç'),
1458 (';', 'ç'),
1459 ('<', ':'),
1460 ('=', '*'),
1461 ('>', ';'),
1462 ('@', '"'),
1463 ('[', 'ğ'),
1464 ('\'', 'ş'),
1465 ('\\', 'ü'),
1466 (']', 'ı'),
1467 ('^', '&'),
1468 ('`', 'ö'),
1469 ('{', 'Ğ'),
1470 ('|', 'Ü'),
1471 ('}', 'I'),
1472 ('~', 'Ö'),
1473 ],
1474 "com.apple.keylayout.Turkmen" => &[
1475 ('C', 'Ç'),
1476 ('Q', 'Ä'),
1477 ('V', 'Ý'),
1478 ('X', 'Ü'),
1479 ('[', 'ň'),
1480 ('\\', 'ş'),
1481 (']', 'ö'),
1482 ('^', '№'),
1483 ('`', 'ž'),
1484 ('c', 'ç'),
1485 ('q', 'ä'),
1486 ('v', 'ý'),
1487 ('x', 'ü'),
1488 ('{', 'Ň'),
1489 ('|', 'Ş'),
1490 ('}', 'Ö'),
1491 ('~', 'Ž'),
1492 ],
1493 "com.apple.keylayout.USInternational-PC" => &[('^', 'ˆ'), ('~', '˜')],
1494 "com.apple.keylayout.Welsh" => &[('#', '£')],
1495
1496 _ => return None,
1497 };
1498
1499 Some(HashMap::from_iter(mappings.iter().cloned()))
1500}