Miguel Raz Guzmán MacedoChange .join("") to .concat() (#58200)df4058e5 months agoHistory
1502 lines · 38.3 KB · Rust
RawDownload
use collections::HashMap;use std::ffi::{CStr, c_void}; use objc::{msg_send, runtime::Object, sel, sel_impl}; use gpui::{KeybindingKeystroke, Keystroke, PlatformKeyboardLayout, PlatformKeyboardMapper}; use crate::{    TISCopyCurrentKeyboardLayoutInputSource, TISGetInputSourceProperty, kTISPropertyInputSourceID,    kTISPropertyLocalizedName,}; pub(crate) struct MacKeyboardLayout {    id: String,    name: String,} pub(crate) struct MacKeyboardMapper {    key_equivalents: Option<HashMap<char, char>>,} impl PlatformKeyboardLayout for MacKeyboardLayout {    fn id(&self) -> &str {        &self.id    }     fn name(&self) -> &str {        &self.name    }} impl PlatformKeyboardMapper for MacKeyboardMapper {    fn map_key_equivalent(        &self,        mut keystroke: Keystroke,        use_key_equivalents: bool,    ) -> KeybindingKeystroke {        if use_key_equivalents && let Some(key_equivalents) = &self.key_equivalents {            if keystroke.key.chars().count() == 1                && let Some(key) = key_equivalents.get(&keystroke.key.chars().next().unwrap())            {                keystroke.key = key.to_string();            }        }        KeybindingKeystroke::from_keystroke(keystroke)    }     fn get_key_equivalents(&self) -> Option<&HashMap<char, char>> {        self.key_equivalents.as_ref()    }} impl MacKeyboardLayout {    pub(crate) fn new() -> Self {        unsafe {            let current_keyboard = TISCopyCurrentKeyboardLayoutInputSource();             let id: *mut Object = TISGetInputSourceProperty(                current_keyboard,                kTISPropertyInputSourceID as *const c_void,            );            let id: *const std::os::raw::c_char = msg_send![id, UTF8String];            let id = CStr::from_ptr(id).to_str().unwrap().to_string();             let name: *mut Object = TISGetInputSourceProperty(                current_keyboard,                kTISPropertyLocalizedName as *const c_void,            );            let name: *const std::os::raw::c_char = msg_send![name, UTF8String];            let name = CStr::from_ptr(name).to_str().unwrap().to_string();             let _: () = msg_send![current_keyboard, release];             Self { id, name }        }    }} impl MacKeyboardMapper {    pub(crate) fn new(layout_id: &str) -> Self {        let key_equivalents = get_key_equivalents(layout_id);         Self { key_equivalents }    }} // On some keyboards (e.g. German QWERTZ) it is not possible to type the full ASCII range// without using option. This means that some of our built in keyboard shortcuts do not work// for those users.//// The way macOS solves this problem is to move shortcuts around so that they are all reachable,// even if the mnemonic changes. https://developer.apple.com/documentation/swiftui/keyboardshortcut/localization-swift.struct//// For example, cmd-> is the "switch window" shortcut because the > key is right above tab.// To ensure this doesn't cause problems for shortcuts defined for a QWERTY layout, apple moves// any shortcuts defined as cmd-> to cmd-:. Coincidentally this s also the same keyboard position// as cmd-> on a QWERTY layout.//// Another example is cmd-[ and cmd-], as they cannot be typed without option, those keys are remapped to cmd-ö// and cmd-ä. These shortcuts are not in the same position as a QWERTY keyboard, because on a QWERTZ keyboard// the + key is in the way; and shortcuts bound to cmd-+ are still typed as cmd-+ on either keyboard (though the// specific key moves)//// As far as I can tell, there's no way to query the mappings Apple uses except by rendering a menu with every// possible key combination, and inspecting the UI to see what it rendered. So that's what we did...//// These mappings were generated by running https://github.com/ConradIrwin/keyboard-inspector, tidying up the// output to remove languages with no mappings and other oddities, and converting it to a less verbose representation with://  jq -s 'map(to_entries | map({key: .key, value: [(.value | to_entries | map(.key) | concat()), (.value | to_entries | map(.value) | concat())]}) | from_entries) | add'// From there I used multi-cursor to produce this match statement.fn get_key_equivalents(layout_id: &str) -> Option<HashMap<char, char>> {    let mappings: &[(char, char)] = match layout_id {        "com.apple.keylayout.ABC-AZERTY" => &[            ('!', '1'),            ('"', '%'),            ('#', '3'),            ('$', '4'),            ('%', '5'),            ('&', '7'),            ('(', '9'),            (')', '0'),            ('*', '8'),            ('.', ';'),            ('/', ':'),            ('0', 'à'),            ('1', '&'),            ('2', 'é'),            ('3', '"'),            ('4', '\''),            ('5', '('),            ('6', '§'),            ('7', 'è'),            ('8', '!'),            ('9', 'ç'),            (':', '°'),            (';', ')'),            ('<', '.'),            ('>', '/'),            ('@', '2'),            ('[', '^'),            ('\'', 'ù'),            ('\\', '`'),            (']', '$'),            ('^', '6'),            ('`', '<'),            ('{', '¨'),            ('|', '£'),            ('}', '*'),            ('~', '>'),        ],        "com.apple.keylayout.ABC-QWERTZ" => &[            ('"', '`'),            ('#', '§'),            ('&', '/'),            ('(', ')'),            (')', '='),            ('*', '('),            ('/', 'ß'),            (':', 'Ü'),            (';', 'ü'),            ('<', ';'),            ('=', '*'),            ('>', ':'),            ('@', '"'),            ('[', 'ö'),            ('\'', '´'),            ('\\', '#'),            (']', 'ä'),            ('^', '&'),            ('`', '<'),            ('{', 'Ö'),            ('|', '\''),            ('}', 'Ä'),            ('~', '>'),        ],        "com.apple.keylayout.Albanian" => &[            ('"', '\''),            (':', 'Ç'),            (';', 'ç'),            ('<', ';'),            ('>', ':'),            ('@', '"'),            ('\'', '@'),            ('\\', 'ë'),            ('`', '<'),            ('|', 'Ë'),            ('~', '>'),        ],        "com.apple.keylayout.Austrian" => &[            ('"', '`'),            ('#', '§'),            ('&', '/'),            ('(', ')'),            (')', '='),            ('*', '('),            ('/', 'ß'),            (':', 'Ü'),            (';', 'ü'),            ('<', ';'),            ('=', '*'),            ('>', ':'),            ('@', '"'),            ('[', 'ö'),            ('\'', '´'),            ('\\', '#'),            (']', 'ä'),            ('^', '&'),            ('`', '<'),            ('{', 'Ö'),            ('|', '\''),            ('}', 'Ä'),            ('~', '>'),        ],        "com.apple.keylayout.Azeri" => &[            ('"', 'Ə'),            (',', 'ç'),            ('.', 'ş'),            ('/', '.'),            (':', 'I'),            (';', 'ı'),            ('<', 'Ç'),            ('>', 'Ş'),            ('?', ','),            ('W', 'Ü'),            ('[', 'ö'),            ('\'', 'ə'),            (']', 'ğ'),            ('w', 'ü'),            ('{', 'Ö'),            ('|', '/'),            ('}', 'Ğ'),        ],        "com.apple.keylayout.Belgian" => &[            ('!', '1'),            ('"', '%'),            ('#', '3'),            ('$', '4'),            ('%', '5'),            ('&', '7'),            ('(', '9'),            (')', '0'),            ('*', '8'),            ('.', ';'),            ('/', ':'),            ('0', 'à'),            ('1', '&'),            ('2', 'é'),            ('3', '"'),            ('4', '\''),            ('5', '('),            ('6', '§'),            ('7', 'è'),            ('8', '!'),            ('9', 'ç'),            (':', '°'),            (';', ')'),            ('<', '.'),            ('>', '/'),            ('@', '2'),            ('[', '^'),            ('\'', 'ù'),            ('\\', '`'),            (']', '$'),            ('^', '6'),            ('`', '<'),            ('{', '¨'),            ('|', '£'),            ('}', '*'),            ('~', '>'),        ],        "com.apple.keylayout.Brazilian-ABNT2" => &[            ('"', '`'),            ('/', 'ç'),            ('?', 'Ç'),            ('\'', '´'),            ('\\', '~'),            ('^', '¨'),            ('`', '\''),            ('|', '^'),            ('~', '"'),        ],        "com.apple.keylayout.Brazilian-Pro" => &[('^', 'ˆ'), ('~', '˜')],        "com.apple.keylayout.British" => &[('#', '£')],        "com.apple.keylayout.Canadian-CSA" => &[            ('"', 'È'),            ('/', 'é'),            ('<', '\''),            ('>', '"'),            ('?', 'É'),            ('[', '^'),            ('\'', 'è'),            ('\\', 'à'),            (']', 'ç'),            ('`', 'ù'),            ('{', '¨'),            ('|', 'À'),            ('}', 'Ç'),            ('~', 'Ù'),        ],        "com.apple.keylayout.Croatian" => &[            ('"', 'Ć'),            ('&', '\''),            ('(', ')'),            (')', '='),            ('*', '('),            (':', 'Č'),            (';', 'č'),            ('<', ';'),            ('=', '*'),            ('>', ':'),            ('@', '"'),            ('[', 'š'),            ('\'', 'ć'),            ('\\', 'ž'),            (']', 'đ'),            ('^', '&'),            ('`', '<'),            ('{', 'Š'),            ('|', 'Ž'),            ('}', 'Đ'),            ('~', '>'),        ],        "com.apple.keylayout.Croatian-PC" => &[            ('"', 'Ć'),            ('&', '/'),            ('(', ')'),            (')', '='),            ('*', '('),            ('/', '\''),            (':', 'Č'),            (';', 'č'),            ('<', ';'),            ('=', '*'),            ('>', ':'),            ('@', '"'),            ('[', 'š'),            ('\'', 'ć'),            ('\\', 'ž'),            (']', 'đ'),            ('^', '&'),            ('`', '<'),            ('{', 'Š'),            ('|', 'Ž'),            ('}', 'Đ'),            ('~', '>'),        ],        "com.apple.keylayout.Czech" => &[            ('!', '1'),            ('"', '!'),            ('#', '3'),            ('$', '4'),            ('%', '5'),            ('&', '7'),            ('(', '9'),            (')', '0'),            ('*', '8'),            ('+', '%'),            ('/', '\''),            ('0', 'é'),            ('1', '+'),            ('2', 'ě'),            ('3', 'š'),            ('4', 'č'),            ('5', 'ř'),            ('6', 'ž'),            ('7', 'ý'),            ('8', 'á'),            ('9', 'í'),            (':', '"'),            (';', 'ů'),            ('<', '?'),            ('>', ':'),            ('?', 'ˇ'),            ('@', '2'),            ('[', 'ú'),            ('\'', '§'),            (']', ')'),            ('^', '6'),            ('`', '¨'),            ('{', 'Ú'),            ('}', '('),            ('~', '`'),        ],        "com.apple.keylayout.Czech-QWERTY" => &[            ('!', '1'),            ('"', '!'),            ('#', '3'),            ('$', '4'),            ('%', '5'),            ('&', '7'),            ('(', '9'),            (')', '0'),            ('*', '8'),            ('+', '%'),            ('/', '\''),            ('0', 'é'),            ('1', '+'),            ('2', 'ě'),            ('3', 'š'),            ('4', 'č'),            ('5', 'ř'),            ('6', 'ž'),            ('7', 'ý'),            ('8', 'á'),            ('9', 'í'),            (':', '"'),            (';', 'ů'),            ('<', '?'),            ('>', ':'),            ('?', 'ˇ'),            ('@', '2'),            ('[', 'ú'),            ('\'', '§'),            (']', ')'),            ('^', '6'),            ('`', '¨'),            ('{', 'Ú'),            ('}', '('),            ('~', '`'),        ],        "com.apple.keylayout.Danish" => &[            ('"', '^'),            ('$', '€'),            ('&', '/'),            ('(', ')'),            (')', '='),            ('*', '('),            ('/', '´'),            (':', 'Å'),            (';', 'å'),            ('<', ';'),            ('=', '`'),            ('>', ':'),            ('@', '"'),            ('[', 'æ'),            ('\'', '¨'),            ('\\', '\''),            (']', 'ø'),            ('^', '&'),            ('`', '<'),            ('{', 'Æ'),            ('|', '*'),            ('}', 'Ø'),            ('~', '>'),        ],        "com.apple.keylayout.Faroese" => &[            ('"', 'Ø'),            ('$', '€'),            ('&', '/'),            ('(', ')'),            (')', '='),            ('*', '('),            ('/', '´'),            (':', 'Æ'),            (';', 'æ'),            ('<', ';'),            ('=', '`'),            ('>', ':'),            ('@', '"'),            ('[', 'å'),            ('\'', 'ø'),            ('\\', '\''),            (']', 'ð'),            ('^', '&'),            ('`', '<'),            ('{', 'Å'),            ('|', '*'),            ('}', 'Ð'),            ('~', '>'),        ],        "com.apple.keylayout.Finnish" => &[            ('"', '^'),            ('$', '€'),            ('&', '/'),            ('(', ')'),            (')', '='),            ('*', '('),            ('/', '´'),            (':', 'Å'),            (';', 'å'),            ('<', ';'),            ('=', '`'),            ('>', ':'),            ('@', '"'),            ('[', 'ö'),            ('\'', '¨'),            ('\\', '\''),            (']', 'ä'),            ('^', '&'),            ('`', '<'),            ('{', 'Ö'),            ('|', '*'),            ('}', 'Ä'),            ('~', '>'),        ],        "com.apple.keylayout.FinnishExtended" => &[            ('"', 'ˆ'),            ('$', '€'),            ('&', '/'),            ('(', ')'),

Lines 1–500 of 1502.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t