windows: implement IME caret movement and editing while composing (#9659)

https://github.com/zed-industries/zed/assets/14981363/598440f7-0364-4053-9f44-710291f8aa92



Release Notes:

- N/A
This commit is contained in:
张小白 2024-03-22 03:10:22 +08:00 committed by GitHub
parent d557f8e36c
commit 1e543b9755
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -51,6 +51,7 @@ pub(crate) struct WindowsWindowInner {
pub(crate) handle: AnyWindowHandle, pub(crate) handle: AnyWindowHandle,
hide_title_bar: bool, hide_title_bar: bool,
display: RefCell<Rc<WindowsDisplay>>, display: RefCell<Rc<WindowsDisplay>>,
last_ime_input: RefCell<Option<String>>,
} }
impl WindowsWindowInner { impl WindowsWindowInner {
@ -110,6 +111,7 @@ impl WindowsWindowInner {
let renderer = RefCell::new(BladeRenderer::new(gpu, extent)); let renderer = RefCell::new(BladeRenderer::new(gpu, extent));
let callbacks = RefCell::new(Callbacks::default()); let callbacks = RefCell::new(Callbacks::default());
let display = RefCell::new(display); let display = RefCell::new(display);
let last_ime_input = RefCell::new(None);
Self { Self {
hwnd, hwnd,
origin, origin,
@ -122,6 +124,7 @@ impl WindowsWindowInner {
handle, handle,
hide_title_bar, hide_title_bar,
display, display,
last_ime_input,
} }
} }
@ -733,6 +736,15 @@ impl WindowsWindowInner {
} }
} }
fn retrieve_composition_cursor_position(&self) -> usize {
unsafe {
let ctx = ImmGetContext(self.hwnd);
let ret = ImmGetCompositionStringW(ctx, GCS_CURSORPOS, None, 0);
ImmReleaseContext(self.hwnd, ctx);
ret as usize
}
}
fn handle_ime_composition(&self, lparam: LPARAM) -> Option<isize> { fn handle_ime_composition(&self, lparam: LPARAM) -> Option<isize> {
if lparam.0 as u32 & GCS_COMPSTR.0 > 0 { if lparam.0 as u32 & GCS_COMPSTR.0 > 0 {
let Some((string, string_len)) = self.parse_ime_compostion_string() else { let Some((string, string_len)) = self.parse_ime_compostion_string() else {
@ -747,12 +759,22 @@ impl WindowsWindowInner {
Some(0..string_len), Some(0..string_len),
); );
self.input_handler.set(Some(input_handler)); self.input_handler.set(Some(input_handler));
None *self.last_ime_input.borrow_mut() = Some(string);
} else { }
if lparam.0 as u32 & GCS_CURSORPOS.0 > 0 {
let Some(ref comp_string) = *self.last_ime_input.borrow() else {
return None;
};
let caret_pos = self.retrieve_composition_cursor_position();
let Some(mut input_handler) = self.input_handler.take() else {
return None;
};
input_handler.replace_and_mark_text_in_range(None, comp_string, Some(0..caret_pos));
self.input_handler.set(Some(input_handler));
}
// currently, we don't care other stuff // currently, we don't care other stuff
None None
} }
}
fn parse_ime_char(&self, wparam: WPARAM) -> Option<String> { fn parse_ime_char(&self, wparam: WPARAM) -> Option<String> {
let src = [wparam.0 as u16]; let src = [wparam.0 as u16];
@ -771,6 +793,7 @@ impl WindowsWindowInner {
}; };
input_handler.replace_text_in_range(None, &ime_char); input_handler.replace_text_in_range(None, &ime_char);
self.input_handler.set(Some(input_handler)); self.input_handler.set(Some(input_handler));
*self.last_ime_input.borrow_mut() = None;
self.invalidate_client_area(); self.invalidate_client_area();
Some(0) Some(0)
} }