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 <elliott.codes@gmail.com>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
This commit is contained in:
agamcsama 2024-06-20 19:39:20 +01:00 committed by GitHub
parent d501a877a0
commit 25c8cf0c5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1082,37 +1082,30 @@ fn parse_syskeydown_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
} }
let vk_code = wparam.loword(); 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) { let key = match VIRTUAL_KEY(vk_code) {
VK_BACK => Some("backspace"), VK_BACK => "backspace",
VK_RETURN => Some("enter"), VK_RETURN => "enter",
VK_TAB => Some("tab"), VK_TAB => "tab",
VK_UP => Some("up"), VK_UP => "up",
VK_DOWN => Some("down"), VK_DOWN => "down",
VK_RIGHT => Some("right"), VK_RIGHT => "right",
VK_LEFT => Some("left"), VK_LEFT => "left",
VK_HOME => Some("home"), VK_HOME => "home",
VK_END => Some("end"), VK_END => "end",
VK_PRIOR => Some("pageup"), VK_PRIOR => "pageup",
VK_NEXT => Some("pagedown"), VK_NEXT => "pagedown",
VK_ESCAPE => Some("escape"), VK_ESCAPE => "escape",
VK_INSERT => Some("insert"), VK_INSERT => "insert",
_ => None, _ => return basic_vkcode_to_string(vk_code, modifiers),
}; }
.to_owned();
if let Some(key) = key {
Some(Keystroke { Some(Keystroke {
modifiers, modifiers,
key: key.to_string(), key: key,
ime_key: None, ime_key: None,
}) })
} else {
None
}
} }
enum KeystrokeOrModifier { enum KeystrokeOrModifier {
@ -1125,6 +1118,22 @@ fn parse_keydown_msg_keystroke(wparam: WPARAM) -> Option<KeystrokeOrModifier> {
let modifiers = current_modifiers(); let modifiers = current_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)) { if is_modifier(VIRTUAL_KEY(vk_code)) {
return Some(KeystrokeOrModifier::Modifier(modifiers)); return Some(KeystrokeOrModifier::Modifier(modifiers));
} }
@ -1143,49 +1152,28 @@ fn parse_keydown_msg_keystroke(wparam: WPARAM) -> Option<KeystrokeOrModifier> {
key: format!("f{}", offset + 1), key: format!("f{}", offset + 1),
ime_key: None, ime_key: None,
})); }));
}
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,
}; };
return None;
}
}
.to_owned();
if let Some(key) = key {
Some(KeystrokeOrModifier::Keystroke(Keystroke { Some(KeystrokeOrModifier::Keystroke(Keystroke {
modifiers, modifiers,
key: key.to_string(), key: key,
ime_key: None, ime_key: None,
})) }))
} else {
None
}
} }
fn parse_char_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> { fn parse_char_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
let src = [wparam.0 as u16]; let first_char = char::from_u32((wparam.0 as u16).into())?;
let Ok(first_char) = char::decode_utf16(src).collect::<Vec<_>>()[0] else {
return None;
};
if first_char.is_control() { if first_char.is_control() {
None None
} else { } else {
let mut modifiers = current_modifiers(); let mut modifiers = current_modifiers();
// for characters that use 'shift' to type it is expected that the // 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 // 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; modifiers.shift = false;
} }
let key = match first_char { let key = match first_char {
@ -1262,56 +1250,25 @@ fn parse_ime_compostion_result(handle: HWND) -> Option<String> {
} }
fn basic_vkcode_to_string(code: u16, modifiers: Modifiers) -> Option<Keystroke> { fn basic_vkcode_to_string(code: u16, modifiers: Modifiers) -> Option<Keystroke> {
match code { let mapped_code = unsafe { MapVirtualKeyW(code as u32, MAPVK_VK_TO_CHAR) };
// VK_0 - VK_9
48..=57 => Some(Keystroke { let key = match mapped_code {
modifiers, 0 => None,
key: format!("{}", code - VK_0.0), raw_code => char::from_u32(raw_code),
ime_key: None, }?
}), .to_ascii_lowercase();
// VK_A - VK_Z
65..=90 => Some(Keystroke { let key = if matches!(code as u32, 112..=135) {
modifiers, format!("f{key}")
key: format!("{}", (b'a' + code as u8 - VK_A.0 as u8) as char), } else {
ime_key: None, key.to_string()
}), };
// 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 { Some(Keystroke {
modifiers, modifiers,
key, key,
ime_key: None, ime_key: None,
}) })
} else {
None
}
}
}
}
fn oemkey_vkcode_to_string(code: u16) -> Option<String> {
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,
}
} }
#[inline] #[inline]