diff --git a/nebula_app/src/gpui_shell/terminal/keymap/win32.rs b/nebula_app/src/gpui_shell/terminal/keymap/win32.rs index f9a73dd..77f6bfb 100644 --- a/nebula_app/src/gpui_shell/terminal/keymap/win32.rs +++ b/nebula_app/src/gpui_shell/terminal/keymap/win32.rs @@ -75,7 +75,7 @@ pub(super) fn virtual_key_of(key: &str) -> Option { /// Tab=0x09、Backspace=0x08):OpenConsole 1.22 的 VT 翻译层会丢弃 uChar=0 /// 的 VK_ESCAPE,于是读字节流的那类应用(Claude Code)收不到 Esc。修饰键与 /// 功能键保持 0,与真实键盘一致。逐条同旧壳 `control_char_fallback`。 -fn unicode_char_of(ks: &Keystroke, scan_code: u32) -> u16 { +fn unicode_char_of(ks: &Keystroke, virtual_key: u16, scan_code: u32) -> u16 { // 平台已经判出文本的(含 Ctrl 变体)以它为准,与 WM_CHAR 语义一致。 // `key_char` 若是 NUL,当作没文本:真实键盘的 Esc 不会写出 U+0000。 if let Some(text) = ks.key_char.as_deref() { @@ -88,7 +88,8 @@ fn unicode_char_of(ks: &Keystroke, scan_code: u32) -> u16 { } match ks.key.as_str() { "escape" => 0x1b, - "enter" => crate::platform::keyboard::enter_character( + "enter" => crate::platform::keyboard::native_character( + virtual_key, scan_code, ks.modifiers.shift, ks.modifiers.control, @@ -106,6 +107,24 @@ fn unicode_char_of(ks: &Keystroke, scan_code: u32) -> u16 { } }, "space" => b' ' as u16, + // GPUI 丢弃 Ctrl+字母的 C0 文本;Win32 记录必须恢复它,adb 等字节流 + // 应用才能收到 Ctrl+C。只补缺失文本,不把 AltGr 等组合合成为控制字符。 + _ if ks.key_char.is_none() + && ks.modifiers.control + && !ks.modifiers.alt + && !ks.modifiers.platform + && !ks.modifiers.function + && matches!(virtual_key, 0x41..=0x5a) => + { + let character = crate::platform::keyboard::native_character( + virtual_key, + scan_code, + ks.modifiers.shift, + ks.modifiers.control, + ks.modifiers.alt, + ); + if character <= 0x1f { character } else { 0 } + }, _ => 0, } } @@ -140,7 +159,7 @@ pub(super) fn win32_input_record(ks: &Keystroke, key_down: bool) -> Option u16 { +/// Recover native character data without changing keyboard composition state. +/// GPUI filters control text out of `key_char`, including Ctrl+C's ETX. +pub(crate) fn native_character( + virtual_key: u16, + scan_code: u32, + shift: bool, + control: bool, + alt: bool, +) -> u16 { use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ - ToUnicode, VK_CONTROL, VK_MENU, VK_RETURN, VK_SHIFT, + ToUnicode, VK_CONTROL, VK_MENU, VK_SHIFT, }; let mut state = [0_u8; 256]; @@ -16,7 +22,7 @@ pub(crate) fn enter_character(scan_code: u32, shift: bool, control: bool, alt: b // prevents dead-key state mutation; 0x1 selects menu translation semantics. let count = unsafe { ToUnicode( - u32::from(VK_RETURN), + u32::from(virtual_key), scan_code, state.as_ptr(), text.as_mut_ptr(),