Files
zed/crates/gpui_macos/src/keyboard.rs
T
Mohamad KhaniandClaude Fable 5 b72a46db68
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
logiguard fork: GPUI xdg-activation keyboard-focus serial fix
Single-commit orphan branch: full zed-industries/zed @ 8c74db0 source tree
with a 3-file patch applied (no upstream history).

Patch (crates/gpui_linux/src/linux/wayland/):
  - serial.rs: add SerialKind::KeyboardEnter
  - client.rs: store wl_keyboard.enter serial; add latest_serial_of()
  - window.rs: activate() uses keyboard-enter serial (Mutter focus gate)

Mutter honors window activation only when the token carries the keyboard-
focus serial from wl_keyboard.enter; GPUI used a stale mouse-press serial.
See docs/tray-window-focus-wayland.md in logiguard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 02:22:17 +03:30

1503 lines
38 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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) | join("")), (.value | to_entries | map(.value) | join(""))]}) | 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" => &[
('"', 'ˆ'),
('$', '€'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '¨'),
('\\', '\''),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'Ö'),
('|', '*'),
('}', 'Ä'),
('~', '>'),
],
"com.apple.keylayout.FinnishSami-PC" => &[
('"', 'ˆ'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '¨'),
('\\', '@'),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'Ö'),
('|', '*'),
('}', 'Ä'),
('~', '>'),
],
"com.apple.keylayout.French" => &[
('!', '1'),
('"', '%'),
('#', '3'),
('$', '4'),
('%', '5'),
('&', '7'),
('(', '9'),
(')', '0'),
('*', '8'),
('.', ';'),
('/', ':'),
('0', 'à'),
('1', '&'),
('2', 'é'),
('3', '"'),
('4', '\''),
('5', '('),
('6', '§'),
('7', 'è'),
('8', '!'),
('9', 'ç'),
(':', '°'),
(';', ')'),
('<', '.'),
('>', '/'),
('@', '2'),
('[', '^'),
('\'', 'ù'),
('\\', '`'),
(']', '$'),
('^', '6'),
('`', '<'),
('{', '¨'),
('|', '£'),
('}', '*'),
('~', '>'),
],
"com.apple.keylayout.French-PC" => &[
('!', '1'),
('"', '%'),
('#', '3'),
('$', '4'),
('%', '5'),
('&', '7'),
('(', '9'),
(')', '0'),
('*', '8'),
('-', ')'),
('.', ';'),
('/', ':'),
('0', 'à'),
('1', '&'),
('2', 'é'),
('3', '"'),
('4', '\''),
('5', '('),
('6', '-'),
('7', 'è'),
('8', '_'),
('9', 'ç'),
(':', '§'),
(';', '!'),
('<', '.'),
('>', '/'),
('@', '2'),
('[', '^'),
('\'', 'ù'),
('\\', '*'),
(']', '$'),
('^', '6'),
('_', '°'),
('`', '<'),
('{', '¨'),
('|', 'μ'),
('}', '£'),
('~', '>'),
],
"com.apple.keylayout.French-numerical" => &[
('!', '1'),
('"', '%'),
('#', '3'),
('$', '4'),
('%', '5'),
('&', '7'),
('(', '9'),
(')', '0'),
('*', '8'),
('.', ';'),
('/', ':'),
('0', 'à'),
('1', '&'),
('2', 'é'),
('3', '"'),
('4', '\''),
('5', '('),
('6', '§'),
('7', 'è'),
('8', '!'),
('9', 'ç'),
(':', '°'),
(';', ')'),
('<', '.'),
('>', '/'),
('@', '2'),
('[', '^'),
('\'', 'ù'),
('\\', '`'),
(']', '$'),
('^', '6'),
('`', '<'),
('{', '¨'),
('|', '£'),
('}', '*'),
('~', '>'),
],
"com.apple.keylayout.German" => &[
('"', '`'),
('#', '§'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', 'ß'),
(':', 'Ü'),
(';', 'ü'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '´'),
('\\', '#'),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'Ö'),
('|', '\''),
('}', 'Ä'),
('~', '>'),
],
"com.apple.keylayout.German-DIN-2137" => &[
('"', '`'),
('#', '§'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', 'ß'),
(':', 'Ü'),
(';', 'ü'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '´'),
('\\', '#'),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'Ö'),
('|', '\''),
('}', 'Ä'),
('~', '>'),
],
"com.apple.keylayout.Hawaiian" => &[('\'', 'ʻ')],
"com.apple.keylayout.Hungarian" => &[
('!', '\''),
('"', 'Á'),
('#', '+'),
('$', '!'),
('&', '='),
('(', ')'),
(')', 'Ö'),
('*', '('),
('+', 'Ó'),
('/', 'ü'),
('0', 'ö'),
(':', 'É'),
(';', 'é'),
('<', 'Ü'),
('=', 'ó'),
('>', ':'),
('@', '"'),
('[', 'ő'),
('\'', 'á'),
('\\', 'ű'),
(']', 'ú'),
('^', '/'),
('`', 'í'),
('{', 'Ő'),
('|', 'Ű'),
('}', 'Ú'),
('~', 'Í'),
],
"com.apple.keylayout.Hungarian-QWERTY" => &[
('!', '\''),
('"', 'Á'),
('#', '+'),
('$', '!'),
('&', '='),
('(', ')'),
(')', 'Ö'),
('*', '('),
('+', 'Ó'),
('/', 'ü'),
('0', 'ö'),
(':', 'É'),
(';', 'é'),
('<', 'Ü'),
('=', 'ó'),
('>', ':'),
('@', '"'),
('[', 'ő'),
('\'', 'á'),
('\\', 'ű'),
(']', 'ú'),
('^', '/'),
('`', 'í'),
('{', 'Ő'),
('|', 'Ű'),
('}', 'Ú'),
('~', 'Í'),
],
"com.apple.keylayout.Icelandic" => &[
('"', 'Ö'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '\''),
(':', 'Ð'),
(';', 'ð'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', 'æ'),
('\'', 'ö'),
('\\', 'þ'),
(']', '´'),
('^', '&'),
('`', '<'),
('{', 'Æ'),
('|', 'Þ'),
('}', '´'),
('~', '>'),
],
"com.apple.keylayout.Irish" => &[('#', '£')],
"com.apple.keylayout.IrishExtended" => &[('#', '£')],
"com.apple.keylayout.Italian" => &[
('!', '1'),
('"', '%'),
('#', '3'),
('$', '4'),
('%', '5'),
('&', '7'),
('(', '9'),
(')', '0'),
('*', '8'),
(',', ';'),
('.', ':'),
('/', ','),
('0', 'é'),
('1', '&'),
('2', '"'),
('3', '\''),
('4', '('),
('5', 'ç'),
('6', 'è'),
('7', ')'),
('8', '£'),
('9', 'à'),
(':', '!'),
(';', 'ò'),
('<', '.'),
('>', '/'),
('@', '2'),
('[', 'ì'),
('\'', 'ù'),
('\\', '§'),
(']', '$'),
('^', '6'),
('`', '<'),
('{', '^'),
('|', '°'),
('}', '*'),
('~', '>'),
],
"com.apple.keylayout.Italian-Pro" => &[
('"', '^'),
('#', '£'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '\''),
(':', 'é'),
(';', 'è'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', 'ò'),
('\'', 'ì'),
('\\', 'ù'),
(']', 'à'),
('^', '&'),
('`', '<'),
('{', 'ç'),
('|', '§'),
('}', '°'),
('~', '>'),
],
"com.apple.keylayout.LatinAmerican" => &[
('"', '¨'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '\''),
(':', 'Ñ'),
(';', 'ñ'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', '{'),
('\'', '´'),
('\\', '¿'),
(']', '}'),
('^', '&'),
('`', '<'),
('{', '['),
('|', '¡'),
('}', ']'),
('~', '>'),
],
"com.apple.keylayout.Lithuanian" => &[
('!', 'Ą'),
('#', 'Ę'),
('$', 'Ė'),
('%', 'Į'),
('&', 'Ų'),
('*', 'Ū'),
('+', 'Ž'),
('1', 'ą'),
('2', 'č'),
('3', 'ę'),
('4', 'ė'),
('5', 'į'),
('6', 'š'),
('7', 'ų'),
('8', 'ū'),
('=', 'ž'),
('@', 'Č'),
('^', 'Š'),
],
"com.apple.keylayout.Maltese" => &[
('#', '£'),
('[', 'ġ'),
(']', 'ħ'),
('`', 'ż'),
('{', 'Ġ'),
('}', 'Ħ'),
('~', 'Ż'),
],
"com.apple.keylayout.NorthernSami" => &[
('"', 'Ŋ'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('Q', 'Á'),
('W', 'Š'),
('X', 'Č'),
('[', 'ø'),
('\'', 'ŋ'),
('\\', 'đ'),
(']', 'æ'),
('^', '&'),
('`', 'ž'),
('q', 'á'),
('w', 'š'),
('x', 'č'),
('{', 'Ø'),
('|', 'Đ'),
('}', 'Æ'),
('~', 'Ž'),
],
"com.apple.keylayout.Norwegian" => &[
('"', '^'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ø'),
('\'', '¨'),
('\\', '@'),
(']', 'æ'),
('^', '&'),
('`', '<'),
('{', 'Ø'),
('|', '*'),
('}', 'Æ'),
('~', '>'),
],
"com.apple.keylayout.NorwegianExtended" => &[
('"', 'ˆ'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ø'),
('\\', '@'),
(']', 'æ'),
('`', '<'),
('}', 'Æ'),
('~', '>'),
],
"com.apple.keylayout.NorwegianSami-PC" => &[
('"', 'ˆ'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ø'),
('\'', '¨'),
('\\', '@'),
(']', 'æ'),
('^', '&'),
('`', '<'),
('{', 'Ø'),
('|', '*'),
('}', 'Æ'),
('~', '>'),
],
"com.apple.keylayout.Polish" => &[
('!', '§'),
('"', 'ę'),
('#', '!'),
('$', '?'),
('%', '+'),
('&', ':'),
('(', '/'),
(')', '"'),
('*', '_'),
('+', ']'),
(',', '.'),
('.', ','),
('/', 'ż'),
(':', 'Ł'),
(';', 'ł'),
('<', 'ś'),
('=', '['),
('>', 'ń'),
('?', 'Ż'),
('@', '%'),
('[', 'ó'),
('\'', 'ą'),
('\\', ';'),
(']', '('),
('^', '='),
('_', 'ć'),
('`', '<'),
('{', 'ź'),
('|', '$'),
('}', ')'),
('~', '>'),
],
"com.apple.keylayout.Portuguese" => &[
('"', '`'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '\''),
(':', 'ª'),
(';', 'º'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', 'ç'),
('\'', '´'),
(']', '~'),
('^', '&'),
('`', '<'),
('{', 'Ç'),
('}', '^'),
('~', '>'),
],
"com.apple.keylayout.Sami-PC" => &[
('"', 'Ŋ'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('Q', 'Á'),
('W', 'Š'),
('X', 'Č'),
('[', 'ø'),
('\'', 'ŋ'),
('\\', 'đ'),
(']', 'æ'),
('^', '&'),
('`', 'ž'),
('q', 'á'),
('w', 'š'),
('x', 'č'),
('{', 'Ø'),
('|', 'Đ'),
('}', 'Æ'),
('~', 'Ž'),
],
"com.apple.keylayout.Serbian-Latin" => &[
('"', 'Ć'),
('&', '\''),
('(', ')'),
(')', '='),
('*', '('),
(':', 'Č'),
(';', 'č'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', 'š'),
('\'', 'ć'),
('\\', 'ž'),
(']', 'đ'),
('^', '&'),
('`', '<'),
('{', 'Š'),
('|', 'Ž'),
('}', 'Đ'),
('~', '>'),
],
"com.apple.keylayout.Slovak" => &[
('!', '1'),
('"', '!'),
('#', '3'),
('$', '4'),
('%', '5'),
('&', '7'),
('(', '9'),
(')', '0'),
('*', '8'),
('+', '%'),
('/', '\''),
('0', 'é'),
('1', '+'),
('2', 'ľ'),
('3', 'š'),
('4', 'č'),
('5', 'ť'),
('6', 'ž'),
('7', 'ý'),
('8', 'á'),
('9', 'í'),
(':', '"'),
(';', 'ô'),
('<', '?'),
('>', ':'),
('?', 'ˇ'),
('@', '2'),
('[', 'ú'),
('\'', '§'),
(']', 'ä'),
('^', '6'),
('`', 'ň'),
('{', 'Ú'),
('}', 'Ä'),
('~', 'Ň'),
],
"com.apple.keylayout.Slovak-QWERTY" => &[
('!', '1'),
('"', '!'),
('#', '3'),
('$', '4'),
('%', '5'),
('&', '7'),
('(', '9'),
(')', '0'),
('*', '8'),
('+', '%'),
('/', '\''),
('0', 'é'),
('1', '+'),
('2', 'ľ'),
('3', 'š'),
('4', 'č'),
('5', 'ť'),
('6', 'ž'),
('7', 'ý'),
('8', 'á'),
('9', 'í'),
(':', '"'),
(';', 'ô'),
('<', '?'),
('>', ':'),
('?', 'ˇ'),
('@', '2'),
('[', 'ú'),
('\'', '§'),
(']', 'ä'),
('^', '6'),
('`', 'ň'),
('{', 'Ú'),
('}', 'Ä'),
('~', 'Ň'),
],
"com.apple.keylayout.Slovenian" => &[
('"', 'Ć'),
('&', '\''),
('(', ')'),
(')', '='),
('*', '('),
(':', 'Č'),
(';', 'č'),
('<', ';'),
('=', '*'),
('>', ':'),
('@', '"'),
('[', 'š'),
('\'', 'ć'),
('\\', 'ž'),
(']', 'đ'),
('^', '&'),
('`', '<'),
('{', 'Š'),
('|', 'Ž'),
('}', 'Đ'),
('~', '>'),
],
"com.apple.keylayout.Spanish" => &[
('!', '¡'),
('"', '¨'),
('.', 'ç'),
('/', '.'),
(':', 'º'),
(';', '´'),
('<', '¿'),
('>', 'Ç'),
('@', '!'),
('[', 'ñ'),
('\'', '`'),
('\\', '\''),
(']', ';'),
('^', '/'),
('`', '<'),
('{', 'Ñ'),
('|', '"'),
('}', ':'),
('~', '>'),
],
"com.apple.keylayout.Spanish-ISO" => &[
('"', '¨'),
('#', '·'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('.', 'ç'),
('/', '.'),
(':', 'º'),
(';', '´'),
('<', '¿'),
('>', 'Ç'),
('@', '"'),
('[', 'ñ'),
('\'', '`'),
('\\', '\''),
(']', ';'),
('^', '&'),
('`', '<'),
('{', 'Ñ'),
('|', '"'),
('}', '`'),
('~', '>'),
],
"com.apple.keylayout.Swedish" => &[
('"', '^'),
('$', '€'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '¨'),
('\\', '\''),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'Ö'),
('|', '*'),
('}', 'Ä'),
('~', '>'),
],
"com.apple.keylayout.Swedish-Pro" => &[
('"', '^'),
('$', '€'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '¨'),
('\\', '\''),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'Ö'),
('|', '*'),
('}', 'Ä'),
('~', '>'),
],
"com.apple.keylayout.SwedishSami-PC" => &[
('"', 'ˆ'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('/', '´'),
(':', 'Å'),
(';', 'å'),
('<', ';'),
('=', '`'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '¨'),
('\\', '@'),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'Ö'),
('|', '*'),
('}', 'Ä'),
('~', '>'),
],
"com.apple.keylayout.SwissFrench" => &[
('!', '+'),
('"', '`'),
('#', '*'),
('$', 'ç'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('+', '!'),
('/', '\''),
(':', 'ü'),
(';', 'è'),
('<', ';'),
('=', '¨'),
('>', ':'),
('@', '"'),
('[', 'é'),
('\'', '^'),
('\\', '$'),
(']', 'à'),
('^', '&'),
('`', '<'),
('{', 'ö'),
('|', '£'),
('}', 'ä'),
('~', '>'),
],
"com.apple.keylayout.SwissGerman" => &[
('!', '+'),
('"', '`'),
('#', '*'),
('$', 'ç'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('+', '!'),
('/', '\''),
(':', 'è'),
(';', 'ü'),
('<', ';'),
('=', '¨'),
('>', ':'),
('@', '"'),
('[', 'ö'),
('\'', '^'),
('\\', '$'),
(']', 'ä'),
('^', '&'),
('`', '<'),
('{', 'é'),
('|', '£'),
('}', 'à'),
('~', '>'),
],
"com.apple.keylayout.Turkish" => &[
('"', '-'),
('#', '"'),
('$', '\''),
('%', '('),
('&', ')'),
('(', '%'),
(')', ':'),
('*', '_'),
(',', 'ö'),
('-', 'ş'),
('.', 'ç'),
('/', '.'),
(':', '$'),
('<', 'Ö'),
('>', 'Ç'),
('@', '*'),
('[', 'ğ'),
('\'', ','),
('\\', 'ü'),
(']', 'ı'),
('^', '/'),
('_', 'Ş'),
('`', '<'),
('{', 'Ğ'),
('|', 'Ü'),
('}', 'I'),
('~', '>'),
],
"com.apple.keylayout.Turkish-QWERTY-PC" => &[
('"', 'I'),
('#', '^'),
('$', '+'),
('&', '/'),
('(', ')'),
(')', '='),
('*', '('),
('+', ':'),
(',', 'ö'),
('.', 'ç'),
('/', '*'),
(':', 'Ş'),
(';', 'ş'),
('<', 'Ö'),
('=', '.'),
('>', 'Ç'),
('@', '\''),
('[', 'ğ'),
('\'', 'ı'),
('\\', ','),
(']', 'ü'),
('^', '&'),
('`', '<'),
('{', 'Ğ'),
('|', ';'),
('}', 'Ü'),
('~', '>'),
],
"com.apple.keylayout.Turkish-Standard" => &[
('"', 'Ş'),
('#', '^'),
('&', '\''),
('(', ')'),
(')', '='),
('*', '('),
(',', '.'),
('.', ','),
(':', 'Ç'),
(';', 'ç'),
('<', ':'),
('=', '*'),
('>', ';'),
('@', '"'),
('[', 'ğ'),
('\'', 'ş'),
('\\', 'ü'),
(']', 'ı'),
('^', '&'),
('`', 'ö'),
('{', 'Ğ'),
('|', 'Ü'),
('}', 'I'),
('~', 'Ö'),
],
"com.apple.keylayout.Turkmen" => &[
('C', 'Ç'),
('Q', 'Ä'),
('V', 'Ý'),
('X', 'Ü'),
('[', 'ň'),
('\\', 'ş'),
(']', 'ö'),
('^', '№'),
('`', 'ž'),
('c', 'ç'),
('q', 'ä'),
('v', 'ý'),
('x', 'ü'),
('{', 'Ň'),
('|', 'Ş'),
('}', 'Ö'),
('~', 'Ž'),
],
"com.apple.keylayout.USInternational-PC" => &[('^', 'ˆ'), ('~', '˜')],
"com.apple.keylayout.Welsh" => &[('#', '£')],
_ => return None,
};
Some(HashMap::from_iter(mappings.iter().cloned()))
}