Skip to content

Commit

Permalink
Add IME support for native (#2046)
Browse files Browse the repository at this point in the history
  • Loading branch information
SheldonNico authored Sep 15, 2022
1 parent c5495d6 commit 0605bcf
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
4 changes: 4 additions & 0 deletions crates/eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 || {
Expand Down Expand Up @@ -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 || {
Expand Down
44 changes: 43 additions & 1 deletion crates/egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -109,6 +112,8 @@ impl State {

simulate_touch_screen: false,
pointer_touch_id: None,

input_method_editor_started: false,
}
}

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -317,7 +360,6 @@ impl State {
| WindowEvent::CloseRequested
| WindowEvent::CursorEntered { .. }
| WindowEvent::Destroyed
| WindowEvent::Ime(_)
| WindowEvent::Occluded(_)
| WindowEvent::Resized(_)
| WindowEvent::ThemeChanged(_)
Expand Down
27 changes: 17 additions & 10 deletions crates/egui/src/widgets/text_edit/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
}
}
Expand Down Expand Up @@ -816,26 +822,27 @@ 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
}
}

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
Expand Down

0 comments on commit 0605bcf

Please sign in to comment.