Additional Windows keyboard input fixes (#42294)

- Enable Alt+Numpad input
- For this to be effective, the default keybindings for Alt+{Number}
will need to be unbound. This won't be needed once we gain the ability
to differentiate numpad digit keys from alphanumeric digit keys.
  - Fixes https://github.com/zed-industries/zed/issues/40699
- Fix a number of edge cases with dead keys

Release Notes:

- N/A
This commit is contained in:
John Tur
2025-11-09 03:51:39 -05:00
committed by GitHub
parent 21f73d9c02
commit 81d38d9872
+27 -30
View File
@@ -1332,21 +1332,13 @@ fn parse_normal_key(
lparam: LPARAM,
mut modifiers: Modifiers,
) -> Option<(Keystroke, bool)> {
let mut key_char = None;
let (key_char, prefer_character_input) = process_key(vkey, lparam.hiword());
let key = parse_immutable(vkey).or_else(|| {
let scan_code = lparam.hiword() & 0xFF;
key_char = generate_key_char(
vkey,
scan_code as u32,
modifiers.control,
modifiers.shift,
modifiers.alt,
);
get_keystroke_key(vkey, scan_code as u32, &mut modifiers)
})?;
let prefer_character_input = should_prefer_character_input(vkey, lparam.hiword() & 0xFF);
Some((
Keystroke {
modifiers,
@@ -1357,11 +1349,11 @@ fn parse_normal_key(
))
}
fn should_prefer_character_input(vkey: VIRTUAL_KEY, scan_code: u16) -> bool {
fn process_key(vkey: VIRTUAL_KEY, scan_code: u16) -> (Option<String>, bool) {
let mut keyboard_state = [0u8; 256];
unsafe {
if GetKeyboardState(&mut keyboard_state).is_err() {
return false;
return (None, false);
}
}
@@ -1372,21 +1364,25 @@ fn should_prefer_character_input(vkey: VIRTUAL_KEY, scan_code: u16) -> bool {
scan_code as u32,
Some(&keyboard_state),
&mut buffer_c,
0x5,
0x4,
)
};
if result_c < 0 {
return false;
if result_c == 0 {
return (None, false);
}
let c = &buffer_c[..result_c as usize];
if char::decode_utf16(c.iter().copied())
.next()
.and_then(|ch| ch.ok())
.map(|ch| ch.is_control())
.unwrap_or(true)
{
return false;
let c = &buffer_c[..result_c.unsigned_abs() as usize];
let key_char = String::from_utf16(c)
.ok()
.filter(|s| !s.is_empty() && !s.chars().next().unwrap().is_control());
if result_c < 0 {
return (key_char, true);
}
if key_char.is_none() {
return (None, false);
}
// Workaround for some bug that makes the compiler think keyboard_state is still zeroed out
@@ -1395,9 +1391,10 @@ fn should_prefer_character_input(vkey: VIRTUAL_KEY, scan_code: u16) -> bool {
let alt_down = (keyboard_state[VK_MENU.0 as usize] & 0x80) != 0;
let win_down = (keyboard_state[VK_LWIN.0 as usize] & 0x80) != 0
|| (keyboard_state[VK_RWIN.0 as usize] & 0x80) != 0;
let has_modifiers = ctrl_down || alt_down || win_down;
if !has_modifiers {
return false;
return (key_char, false);
}
let mut state_no_modifiers = keyboard_state;
@@ -1417,15 +1414,15 @@ fn should_prefer_character_input(vkey: VIRTUAL_KEY, scan_code: u16) -> bool {
scan_code as u32,
Some(&state_no_modifiers),
&mut buffer_c_no_modifiers,
0x5,
0x4,
)
};
if result_c_no_modifiers <= 0 {
return false;
}
let c_no_modifiers = &buffer_c_no_modifiers[..result_c_no_modifiers as usize];
c != c_no_modifiers
let c_no_modifiers = &buffer_c_no_modifiers[..result_c_no_modifiers.unsigned_abs() as usize];
(
key_char,
result_c != result_c_no_modifiers || c != c_no_modifiers,
)
}
fn parse_ime_composition_string(ctx: HIMC, comp_type: IME_COMPOSITION_STRING) -> Option<String> {