diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 22a5623f077..12077b93292 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -940,6 +940,7 @@ fn events( if !text_mark.is_empty() { text.insert_text_at(&mut ccursor, text_mark, char_limit); } + state.ime_cursor_range = cursor_range; Some(CCursorRange::two(start_cursor, ccursor)) } else { None @@ -947,12 +948,16 @@ fn events( } Event::CompositionEnd(prediction) => { - // CompositionEnd only characters may be typed into TextEdit without trigger CompositionStart first, so do not check `state.has_ime = true` in the following statement. + // CompositionEnd only characters may be typed into TextEdit without trigger CompositionStart first, + // so do not check `state.has_ime = true` in the following statement. if prediction != "\n" && prediction != "\r" { state.has_ime = false; - let mut ccursor = text.delete_selected(&cursor_range); - if !prediction.is_empty() { + let mut ccursor; + if !prediction.is_empty() && cursor_range == state.ime_cursor_range { + ccursor = text.delete_selected(&cursor_range); text.insert_text_at(&mut ccursor, prediction, char_limit); + } else { + ccursor = cursor_range.primary.ccursor; } Some(CCursorRange::one(ccursor)) } else { diff --git a/crates/egui/src/widgets/text_edit/state.rs b/crates/egui/src/widgets/text_edit/state.rs index 819688289c9..8901fd56f27 100644 --- a/crates/egui/src/widgets/text_edit/state.rs +++ b/crates/egui/src/widgets/text_edit/state.rs @@ -44,6 +44,10 @@ pub struct TextEditState { #[cfg_attr(feature = "serde", serde(skip))] pub(crate) has_ime: bool, + // cursor range for IME candidate. + #[cfg_attr(feature = "serde", serde(skip))] + pub(crate) ime_cursor_range: CursorRange, + // Visual offset when editing singleline text bigger than the width. #[cfg_attr(feature = "serde", serde(skip))] pub(crate) singleline_offset: f32,