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:
parent
d501a877a0
commit
25c8cf0c5c
1 changed files with 82 additions and 125 deletions
|
@ -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]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue