Add IME support for native (#2046)
This commit is contained in:
parent
c5495d69fb
commit
0605bcfca7
3 changed files with 64 additions and 11 deletions
|
@ -361,6 +361,8 @@ mod glow_integration {
|
|||
let theme = system_theme.unwrap_or(self.native_options.default_theme);
|
||||
integration.egui_ctx.set_visuals(theme.egui_visuals());
|
||||
|
||||
gl_window.window().set_ime_allowed(true);
|
||||
|
||||
{
|
||||
let event_loop_proxy = self.repaint_proxy.clone();
|
||||
integration.egui_ctx.set_request_repaint_callback(move || {
|
||||
|
@ -729,6 +731,8 @@ mod wgpu_integration {
|
|||
let theme = system_theme.unwrap_or(self.native_options.default_theme);
|
||||
integration.egui_ctx.set_visuals(theme.egui_visuals());
|
||||
|
||||
window.set_ime_allowed(true);
|
||||
|
||||
{
|
||||
let event_loop_proxy = self.repaint_proxy.clone();
|
||||
integration.egui_ctx.set_request_repaint_callback(move || {
|
||||
|
|
|
@ -83,6 +83,9 @@ pub struct State {
|
|||
///
|
||||
/// Only one touch will be interpreted as pointer at any time.
|
||||
pointer_touch_id: Option<u64>,
|
||||
|
||||
/// track ime state
|
||||
input_method_editor_started: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
@ -109,6 +112,8 @@ impl State {
|
|||
|
||||
simulate_touch_screen: false,
|
||||
pointer_touch_id: None,
|
||||
|
||||
input_method_editor_started: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,6 +256,44 @@ impl State {
|
|||
consumed,
|
||||
}
|
||||
}
|
||||
WindowEvent::Ime(ime) => {
|
||||
// on Mac even Cmd-C is preessed during ime, a `c` is pushed to Preedit.
|
||||
// So no need to check is_mac_cmd.
|
||||
//
|
||||
// How winit produce `Ime::Enabled` and `Ime::Disabled` differs in MacOS
|
||||
// and Windows.
|
||||
//
|
||||
// - On Windows, before and after each Commit will produce an Enable/Disabled
|
||||
// event.
|
||||
// - On MacOS, only when user explicit enable/disable ime. No Disabled
|
||||
// after Commit.
|
||||
//
|
||||
// We use input_method_editor_started to mannualy insert CompositionStart
|
||||
// between Commits.
|
||||
match ime {
|
||||
winit::event::Ime::Enabled | winit::event::Ime::Disabled => (),
|
||||
winit::event::Ime::Commit(text) => {
|
||||
self.input_method_editor_started = false;
|
||||
self.egui_input
|
||||
.events
|
||||
.push(egui::Event::CompositionEnd(text.clone()));
|
||||
}
|
||||
winit::event::Ime::Preedit(text, ..) => {
|
||||
if !self.input_method_editor_started {
|
||||
self.input_method_editor_started = true;
|
||||
self.egui_input.events.push(egui::Event::CompositionStart);
|
||||
}
|
||||
self.egui_input
|
||||
.events
|
||||
.push(egui::Event::CompositionUpdate(text.clone()));
|
||||
}
|
||||
};
|
||||
|
||||
EventResponse {
|
||||
repaint: true,
|
||||
consumed: egui_ctx.wants_keyboard_input(),
|
||||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput { input, .. } => {
|
||||
self.on_keyboard_input(input);
|
||||
let consumed = egui_ctx.wants_keyboard_input()
|
||||
|
@ -317,7 +360,6 @@ impl State {
|
|||
| WindowEvent::CloseRequested
|
||||
| WindowEvent::CursorEntered { .. }
|
||||
| WindowEvent::Destroyed
|
||||
| WindowEvent::Ime(_)
|
||||
| WindowEvent::Occluded(_)
|
||||
| WindowEvent::Resized(_)
|
||||
| WindowEvent::ThemeChanged(_)
|
||||
|
|
|
@ -618,7 +618,13 @@ impl<'t> TextEdit<'t> {
|
|||
if interactive {
|
||||
// eframe web uses `text_cursor_pos` when showing IME,
|
||||
// so only set it when text is editable and visible!
|
||||
ui.ctx().output().text_cursor_pos = Some(cursor_pos.left_top());
|
||||
// But `winit` and `egui_web` differs in how to set the
|
||||
// position of IME.
|
||||
if cfg!(target_arch = "wasm32") {
|
||||
ui.ctx().output().text_cursor_pos = Some(cursor_pos.left_top());
|
||||
} else {
|
||||
ui.ctx().output().text_cursor_pos = Some(cursor_pos.left_bottom());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -816,11 +822,14 @@ fn events(
|
|||
}
|
||||
|
||||
Event::CompositionUpdate(text_mark) => {
|
||||
if !text_mark.is_empty() && text_mark != "\n" && text_mark != "\r" && state.has_ime
|
||||
{
|
||||
// empty prediction can be produced when user press backspace
|
||||
// or escape during ime. We should clear current text.
|
||||
if text_mark != "\n" && text_mark != "\r" && state.has_ime {
|
||||
let mut ccursor = delete_selected(text, &cursor_range);
|
||||
let start_cursor = ccursor;
|
||||
insert_text(&mut ccursor, text, text_mark);
|
||||
if !text_mark.is_empty() {
|
||||
insert_text(&mut ccursor, text, text_mark);
|
||||
}
|
||||
Some(CCursorRange::two(start_cursor, ccursor))
|
||||
} else {
|
||||
None
|
||||
|
@ -828,14 +837,12 @@ fn events(
|
|||
}
|
||||
|
||||
Event::CompositionEnd(prediction) => {
|
||||
if !prediction.is_empty()
|
||||
&& prediction != "\n"
|
||||
&& prediction != "\r"
|
||||
&& state.has_ime
|
||||
{
|
||||
if prediction != "\n" && prediction != "\r" && state.has_ime {
|
||||
state.has_ime = false;
|
||||
let mut ccursor = delete_selected(text, &cursor_range);
|
||||
insert_text(&mut ccursor, text, prediction);
|
||||
if !prediction.is_empty() {
|
||||
insert_text(&mut ccursor, text, prediction);
|
||||
}
|
||||
Some(CCursorRange::one(ccursor))
|
||||
} else {
|
||||
None
|
||||
|
|
Loading…
Reference in a new issue