From 25c8cf0c5c8d20c5c66a94cabd131680ce63aae0 Mon Sep 17 00:00:00 2001 From: agamcsama <171503309+agamcsama@users.noreply.github.com> Date: Thu, 20 Jun 2024 19:39:20 +0100 Subject: [PATCH] windows: Fix Zed/GPUI misinterpreting keycodes + Refactor (#12814) Release Notes: - Fixed Zed/GPUI misinterpreting keycodes on non-US keyboards ([#12811](https://github.com/zed-industries/zed/issues/12811)). --------- Co-authored-by: Marshall Bowers Co-authored-by: Mikayla Maki --- crates/gpui/src/platform/windows/events.rs | 207 ++++++++------------- 1 file changed, 82 insertions(+), 125 deletions(-) diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index f849215dcea736d5e9eb20b0e6f38bfd422cd3f5..35360fb24d97f8d1cae2e28345bbb9ce8a3b7fe7 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -1082,37 +1082,30 @@ fn parse_syskeydown_msg_keystroke(wparam: WPARAM) -> Option { } let vk_code = wparam.loword(); - let basic_key = basic_vkcode_to_string(vk_code, modifiers); - if basic_key.is_some() { - return basic_key; - } let key = match VIRTUAL_KEY(vk_code) { - VK_BACK => Some("backspace"), - VK_RETURN => Some("enter"), - VK_TAB => Some("tab"), - VK_UP => Some("up"), - VK_DOWN => Some("down"), - VK_RIGHT => Some("right"), - VK_LEFT => Some("left"), - VK_HOME => Some("home"), - VK_END => Some("end"), - VK_PRIOR => Some("pageup"), - VK_NEXT => Some("pagedown"), - VK_ESCAPE => Some("escape"), - VK_INSERT => Some("insert"), - _ => None, - }; - - if let Some(key) = key { - Some(Keystroke { - modifiers, - key: key.to_string(), - ime_key: None, - }) - } else { - None + VK_BACK => "backspace", + VK_RETURN => "enter", + VK_TAB => "tab", + VK_UP => "up", + VK_DOWN => "down", + VK_RIGHT => "right", + VK_LEFT => "left", + VK_HOME => "home", + VK_END => "end", + VK_PRIOR => "pageup", + VK_NEXT => "pagedown", + VK_ESCAPE => "escape", + VK_INSERT => "insert", + _ => return basic_vkcode_to_string(vk_code, modifiers), } + .to_owned(); + + Some(Keystroke { + modifiers, + key: key, + ime_key: None, + }) } enum KeystrokeOrModifier { @@ -1125,67 +1118,62 @@ fn parse_keydown_msg_keystroke(wparam: WPARAM) -> Option { let modifiers = current_modifiers(); - if is_modifier(VIRTUAL_KEY(vk_code)) { - return Some(KeystrokeOrModifier::Modifier(modifiers)); - } + let key = match VIRTUAL_KEY(vk_code) { + VK_BACK => "backspace", + VK_RETURN => "enter", + VK_TAB => "tab", + VK_UP => "up", + VK_DOWN => "down", + VK_RIGHT => "right", + VK_LEFT => "left", + VK_HOME => "home", + VK_END => "end", + VK_PRIOR => "pageup", + VK_NEXT => "pagedown", + VK_ESCAPE => "escape", + VK_INSERT => "insert", + VK_DELETE => "delete", + _ => { + if is_modifier(VIRTUAL_KEY(vk_code)) { + return Some(KeystrokeOrModifier::Modifier(modifiers)); + } - if modifiers.control || modifiers.alt { - let basic_key = basic_vkcode_to_string(vk_code, modifiers); - if let Some(basic_key) = basic_key { - return Some(KeystrokeOrModifier::Keystroke(basic_key)); - } - } + if modifiers.control || modifiers.alt { + let basic_key = basic_vkcode_to_string(vk_code, modifiers); + if let Some(basic_key) = basic_key { + return Some(KeystrokeOrModifier::Keystroke(basic_key)); + } + } - if vk_code >= VK_F1.0 && vk_code <= VK_F24.0 { - let offset = vk_code - VK_F1.0; - return Some(KeystrokeOrModifier::Keystroke(Keystroke { - modifiers, - key: format!("f{}", offset + 1), - ime_key: None, - })); + if vk_code >= VK_F1.0 && vk_code <= VK_F24.0 { + let offset = vk_code - VK_F1.0; + return Some(KeystrokeOrModifier::Keystroke(Keystroke { + modifiers, + key: format!("f{}", offset + 1), + ime_key: None, + })); + }; + return None; + } } + .to_owned(); - let key = match VIRTUAL_KEY(vk_code) { - VK_BACK => Some("backspace"), - VK_RETURN => Some("enter"), - VK_TAB => Some("tab"), - VK_UP => Some("up"), - VK_DOWN => Some("down"), - VK_RIGHT => Some("right"), - VK_LEFT => Some("left"), - VK_HOME => Some("home"), - VK_END => Some("end"), - VK_PRIOR => Some("pageup"), - VK_NEXT => Some("pagedown"), - VK_ESCAPE => Some("escape"), - VK_INSERT => Some("insert"), - VK_DELETE => Some("delete"), - _ => None, - }; - - if let Some(key) = key { - Some(KeystrokeOrModifier::Keystroke(Keystroke { - modifiers, - key: key.to_string(), - ime_key: None, - })) - } else { - None - } + Some(KeystrokeOrModifier::Keystroke(Keystroke { + modifiers, + key: key, + ime_key: None, + })) } fn parse_char_msg_keystroke(wparam: WPARAM) -> Option { - let src = [wparam.0 as u16]; - let Ok(first_char) = char::decode_utf16(src).collect::>()[0] else { - return None; - }; + let first_char = char::from_u32((wparam.0 as u16).into())?; if first_char.is_control() { None } else { let mut modifiers = current_modifiers(); // for characters that use 'shift' to type it is expected that the // shift is not reported if the uppercase/lowercase are the same and instead only the key is reported - if first_char.to_lowercase().to_string() == first_char.to_uppercase().to_string() { + if first_char.to_ascii_uppercase() == first_char.to_ascii_lowercase() { modifiers.shift = false; } let key = match first_char { @@ -1262,56 +1250,25 @@ fn parse_ime_compostion_result(handle: HWND) -> Option { } fn basic_vkcode_to_string(code: u16, modifiers: Modifiers) -> Option { - match code { - // VK_0 - VK_9 - 48..=57 => Some(Keystroke { - modifiers, - key: format!("{}", code - VK_0.0), - ime_key: None, - }), - // VK_A - VK_Z - 65..=90 => Some(Keystroke { - modifiers, - key: format!("{}", (b'a' + code as u8 - VK_A.0 as u8) as char), - ime_key: None, - }), - // VK_F1 - VK_F24 - 112..=135 => Some(Keystroke { - modifiers, - key: format!("f{}", code - VK_F1.0 + 1), - ime_key: None, - }), - // OEM3: `/~, OEM_MINUS: -/_, OEM_PLUS: =/+, ... - _ => { - if let Some(key) = oemkey_vkcode_to_string(code) { - Some(Keystroke { - modifiers, - key, - ime_key: None, - }) - } else { - None - } - } - } -} + let mapped_code = unsafe { MapVirtualKeyW(code as u32, MAPVK_VK_TO_CHAR) }; -fn oemkey_vkcode_to_string(code: u16) -> Option { - match code { - 186 => Some(";".to_string()), // VK_OEM_1 - 187 => Some("=".to_string()), // VK_OEM_PLUS - 188 => Some(",".to_string()), // VK_OEM_COMMA - 189 => Some("-".to_string()), // VK_OEM_MINUS - 190 => Some(".".to_string()), // VK_OEM_PERIOD - // https://kbdlayout.info/features/virtualkeys/VK_ABNT_C1 - 191 | 193 => Some("/".to_string()), // VK_OEM_2 VK_ABNT_C1 - 192 => Some("`".to_string()), // VK_OEM_3 - 219 => Some("[".to_string()), // VK_OEM_4 - 220 => Some("\\".to_string()), // VK_OEM_5 - 221 => Some("]".to_string()), // VK_OEM_6 - 222 => Some("'".to_string()), // VK_OEM_7 - _ => None, - } + let key = match mapped_code { + 0 => None, + raw_code => char::from_u32(raw_code), + }? + .to_ascii_lowercase(); + + let key = if matches!(code as u32, 112..=135) { + format!("f{key}") + } else { + key.to_string() + }; + + Some(Keystroke { + modifiers, + key, + ime_key: None, + }) } #[inline]