diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 8c69bc9df7..1a357ddd30 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -83,11 +83,11 @@ pub(crate) fn handle_msg( WM_XBUTTONUP => handle_xbutton_msg(handle, wparam, lparam, handle_mouse_up_msg, state_ptr), WM_MOUSEWHEEL => handle_mouse_wheel_msg(handle, wparam, lparam, state_ptr), WM_MOUSEHWHEEL => handle_mouse_horizontal_wheel_msg(handle, wparam, lparam, state_ptr), - WM_SYSKEYDOWN => handle_syskeydown_msg(wparam, lparam, state_ptr), - WM_SYSKEYUP => handle_syskeyup_msg(wparam, lparam, state_ptr), + WM_SYSKEYDOWN => handle_syskeydown_msg(handle, wparam, lparam, state_ptr), + WM_SYSKEYUP => handle_syskeyup_msg(handle, wparam, lparam, state_ptr), WM_SYSCOMMAND => handle_system_command(wparam, state_ptr), - WM_KEYDOWN => handle_keydown_msg(wparam, lparam, state_ptr), - WM_KEYUP => handle_keyup_msg(wparam, lparam, state_ptr), + WM_KEYDOWN => handle_keydown_msg(handle, wparam, lparam, state_ptr), + WM_KEYUP => handle_keyup_msg(handle, wparam, lparam, state_ptr), WM_CHAR => handle_char_msg(wparam, state_ptr), WM_DEADCHAR => handle_dead_char_msg(wparam, state_ptr), WM_IME_STARTCOMPOSITION => handle_ime_position(handle, state_ptr), @@ -337,12 +337,13 @@ fn handle_mouse_leave_msg(state_ptr: Rc) -> Option } fn handle_syskeydown_msg( + handle: HWND, wparam: WPARAM, lparam: LPARAM, state_ptr: Rc, ) -> Option { let mut lock = state_ptr.state.borrow_mut(); - let input = handle_key_event(wparam, lparam, &mut lock, |keystroke| { + let input = handle_key_event(handle, wparam, lparam, &mut lock, |keystroke| { PlatformInput::KeyDown(KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, @@ -358,7 +359,6 @@ fn handle_syskeydown_msg( if handled { lock.system_key_handled = true; - lock.suppress_next_char_msg = true; Some(0) } else { // we need to call `DefWindowProcW`, or we will lose the system-wide `Alt+F4`, `Alt+{other keys}` @@ -368,12 +368,13 @@ fn handle_syskeydown_msg( } fn handle_syskeyup_msg( + handle: HWND, wparam: WPARAM, lparam: LPARAM, state_ptr: Rc, ) -> Option { let mut lock = state_ptr.state.borrow_mut(); - let input = handle_key_event(wparam, lparam, &mut lock, |keystroke| { + let input = handle_key_event(handle, wparam, lparam, &mut lock, |keystroke| { PlatformInput::KeyUp(KeyUpEvent { keystroke }) })?; let mut func = lock.callbacks.input.take()?; @@ -388,12 +389,13 @@ fn handle_syskeyup_msg( // It's a known bug that you can't trigger `ctrl-shift-0`. See: // https://superuser.com/questions/1455762/ctrl-shift-number-key-combination-has-stopped-working-for-a-few-numbers fn handle_keydown_msg( + handle: HWND, wparam: WPARAM, lparam: LPARAM, state_ptr: Rc, ) -> Option { let mut lock = state_ptr.state.borrow_mut(); - let Some(input) = handle_key_event(wparam, lparam, &mut lock, |keystroke| { + let Some(input) = handle_key_event(handle, wparam, lparam, &mut lock, |keystroke| { PlatformInput::KeyDown(KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, @@ -401,32 +403,42 @@ fn handle_keydown_msg( }) else { return Some(1); }; + drop(lock); - let Some(mut func) = lock.callbacks.input.take() else { + let is_composing = with_input_handler(&state_ptr, |input_handler| { + input_handler.marked_text_range() + }) + .flatten() + .is_some(); + if is_composing { + translate_message(handle, wparam, lparam); + return Some(0); + } + + let Some(mut func) = state_ptr.state.borrow_mut().callbacks.input.take() else { return Some(1); }; - drop(lock); let handled = !func(input).propagate; - let mut lock = state_ptr.state.borrow_mut(); - lock.callbacks.input = Some(func); + state_ptr.state.borrow_mut().callbacks.input = Some(func); if handled { - lock.suppress_next_char_msg = true; Some(0) } else { + translate_message(handle, wparam, lparam); Some(1) } } fn handle_keyup_msg( + handle: HWND, wparam: WPARAM, lparam: LPARAM, state_ptr: Rc, ) -> Option { let mut lock = state_ptr.state.borrow_mut(); - let Some(input) = handle_key_event(wparam, lparam, &mut lock, |keystroke| { + let Some(input) = handle_key_event(handle, wparam, lparam, &mut lock, |keystroke| { PlatformInput::KeyUp(KeyUpEvent { keystroke }) }) else { return Some(1); @@ -1213,7 +1225,23 @@ fn handle_input_language_changed( Some(0) } +#[inline] +fn translate_message(handle: HWND, wparam: WPARAM, lparam: LPARAM) { + let msg = MSG { + hwnd: handle, + message: WM_KEYDOWN, + wParam: wparam, + lParam: lparam, + // It seems like leaving the following two parameters empty doesn't break key events, they still work as expected. + // But if any bugs pop up after this PR, this is probably the place to look first. + time: 0, + pt: POINT::default(), + }; + unsafe { TranslateMessage(&msg).ok().log_err() }; +} + fn handle_key_event( + handle: HWND, wparam: WPARAM, lparam: LPARAM, state: &mut WindowsWindowState, @@ -1222,15 +1250,10 @@ fn handle_key_event( where F: FnOnce(Keystroke) -> PlatformInput, { - state.suppress_next_char_msg = false; let virtual_key = VIRTUAL_KEY(wparam.loword()); let mut modifiers = current_modifiers(); match virtual_key { - VK_PROCESSKEY => { - // IME composition - None - } VK_SHIFT | VK_CONTROL | VK_MENU | VK_LWIN | VK_RWIN => { if state .last_reported_modifiers @@ -1244,6 +1267,11 @@ where })) } vkey => { + let vkey = if vkey == VK_PROCESSKEY { + VIRTUAL_KEY(unsafe { ImmGetVirtualKey(handle) } as u16) + } else { + vkey + }; let keystroke = parse_normal_key(vkey, lparam, modifiers)?; Some(f(keystroke)) } @@ -1491,12 +1519,7 @@ fn with_input_handler(state_ptr: &Rc, f: F) -> Opti where F: FnOnce(&mut PlatformInputHandler) -> R, { - let mut lock = state_ptr.state.borrow_mut(); - if lock.suppress_next_char_msg { - return None; - } - let mut input_handler = lock.input_handler.take()?; - drop(lock); + let mut input_handler = state_ptr.state.borrow_mut().input_handler.take()?; let result = f(&mut input_handler); state_ptr.state.borrow_mut().input_handler = Some(input_handler); Some(result) @@ -1510,9 +1533,6 @@ where F: FnOnce(&mut PlatformInputHandler, f32) -> Option, { let mut lock = state_ptr.state.borrow_mut(); - if lock.suppress_next_char_msg { - return None; - } let mut input_handler = lock.input_handler.take()?; let scale_factor = lock.scale_factor; drop(lock); diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index d3fb5d326f..1fbbd7b782 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -231,9 +231,6 @@ impl WindowsPlatform { } } _ => { - // todo(windows) - // crate `windows 0.56` reports true as Err - TranslateMessage(&msg).as_bool(); DispatchMessageW(&msg); } } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 671cf72c96..cd55a851cc 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -43,7 +43,6 @@ pub struct WindowsWindowState { pub callbacks: Callbacks, pub input_handler: Option, pub last_reported_modifiers: Option, - pub suppress_next_char_msg: bool, pub system_key_handled: bool, pub hovered: bool, @@ -103,7 +102,6 @@ impl WindowsWindowState { let callbacks = Callbacks::default(); let input_handler = None; let last_reported_modifiers = None; - let suppress_next_char_msg = false; let system_key_handled = false; let hovered = false; let click_state = ClickState::new(); @@ -123,7 +121,6 @@ impl WindowsWindowState { callbacks, input_handler, last_reported_modifiers, - suppress_next_char_msg, system_key_handled, hovered, renderer,