From 324dd5fa86d9c20a69e812b63cc0aba4ced9cab7 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 5 Jan 2024 11:53:47 +0100 Subject: [PATCH] On macOS, reported shifted key with shift+Ctrl/Cmd Fixes #3078. --- CHANGELOG.md | 1 + src/platform_impl/macos/event.rs | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c94f9caca..f1da5bfb44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Unreleased` header. - On X11, fix `NotSupported` error not propagated when creating event loop. - On Wayland, fix resize not issued when scale changes - On X11 and Wayland, fix arrow up on keypad reported as `ArrowLeft`. +- On macOS, report correct logical key when Ctrl or Cmd is pressed. # 0.29.8 diff --git a/src/platform_impl/macos/event.rs b/src/platform_impl/macos/event.rs index cdd79297ec..77d527eb54 100644 --- a/src/platform_impl/macos/event.rs +++ b/src/platform_impl/macos/event.rs @@ -39,6 +39,7 @@ impl KeyEventExtModifierSupplement for KeyEvent { } } +/// Ignores ALL modifiers. pub fn get_modifierless_char(scancode: u16) -> Key { let mut string = [0; 16]; let input_source; @@ -97,6 +98,7 @@ pub fn get_modifierless_char(scancode: u16) -> Key { Key::Character(SmolStr::new(chars)) } +// Ignores all modifiers except for SHIFT (yes, even ALT is ignored). fn get_logical_key_char(ns_event: &NSEvent, modifierless_chars: &str) -> Key { let string = ns_event .charactersIgnoringModifiers() @@ -126,6 +128,13 @@ pub(crate) fn create_key_event( let mut physical_key = key_override.unwrap_or_else(|| PhysicalKey::from_scancode(scancode as u32)); + // NOTE: The logical key should heed both SHIFT and ALT if possible. + // For instance: + // * Pressing the A key: logical key should be "a" + // * Pressing SHIFT A: logical key should be "A" + // * Pressing CTRL SHIFT A: logical key should also be "A" + // This is not easy to tease out of `NSEvent`, but we do our best. + let text_with_all_modifiers: Option = if key_override.is_some() { None } else { @@ -146,21 +155,29 @@ pub(crate) fn create_key_event( let key_from_code = code_to_key(physical_key, scancode); let (logical_key, key_without_modifiers) = if matches!(key_from_code, Key::Unidentified(_)) { + // `get_modifierless_char/key_without_modifiers` ignores ALL modifiers. let key_without_modifiers = get_modifierless_char(scancode); let modifiers = NSEvent::modifierFlags(ns_event); let has_ctrl = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + let has_cmd = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); let logical_key = match text_with_all_modifiers.as_ref() { - // Only checking for ctrl here, not checking for alt because we DO want to + // Only checking for ctrl and cmd here, not checking for alt because we DO want to // include its effect in the key. For example if -on the Germay layout- one // presses alt+8, the logical key should be "{" // Also not checking if this is a release event because then this issue would // still affect the key release. - Some(text) if !has_ctrl => Key::Character(text.clone()), + Some(text) if !has_ctrl && !has_cmd => { + // Character heeding both SHIFT and ALT. + Key::Character(text.clone()) + } + _ => match key_without_modifiers.as_ref() { + // Character heeding just SHIFT, ignoring ALT. Key::Character(ch) => get_logical_key_char(ns_event, ch), - // Don't try to get text for events which likely don't have it. + + // Character ignoring ALL modifiers. _ => key_without_modifiers.clone(), }, };