Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-add IME support #762

Merged
merged 14 commits into from
Nov 30, 2024
54 changes: 32 additions & 22 deletions masonry/src/passes/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ use std::collections::HashSet;
use cursor_icon::CursorIcon;
use tracing::{info_span, trace};

use crate::passes::event::run_on_pointer_event_pass;
use crate::passes::event::{run_on_pointer_event_pass, run_on_text_event_pass};
use crate::passes::{enter_span, enter_span_if, merge_state_up, recurse_on_children};
use crate::render_root::{RenderRoot, RenderRootSignal, RenderRootState};
use crate::tree_arena::ArenaMut;
use crate::{
PointerEvent, QueryCtx, RegisterCtx, Update, UpdateCtx, Widget, WidgetId, WidgetState,
PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget, WidgetId,
WidgetState,
};

// --- MARK: HELPERS ---
Expand Down Expand Up @@ -402,6 +403,19 @@ pub(crate) fn run_update_focus_pass(root: &mut RenderRoot) {
}

let prev_focused = root.global_state.focused_widget;
let was_ime_active = root.global_state.is_ime_active;

let disable_ime = was_ime_active && prev_focused != root.global_state.next_focused_widget;
if disable_ime {
// IME was active, but the next focused widget is going to receive the Ime::Disabled event
// sent by the platform. Synthesize an Ime::Disabled event here and send it to the widget
// about to be unfocused.
run_on_text_event_pass(root, &TextEvent::Ime(winit::event::Ime::Disabled));
root.global_state.emit_signal(RenderRootSignal::EndIme);
}

// Note: handling of the Ime::Disabled event sent above may have changed the next focused
// widget.
let next_focused = root.global_state.next_focused_widget;

// "Focused path" means the focused widget, and all its parents.
Expand Down Expand Up @@ -458,15 +472,10 @@ pub(crate) fn run_update_focus_pass(root: &mut RenderRoot) {
}
}

if prev_focused != next_focused {
let was_ime_active = root.global_state.is_ime_active;
let is_ime_active = if let Some(id) = next_focused {
root.widget_arena.get_state(id).item.accepts_text_input
} else {
false
};
root.global_state.is_ime_active = is_ime_active;

// Refocus if the focused widget changed. Or, if the focused widget was going to change, the
// handling of the synthesized Ime::Disabled event above may have changed the focus back to the
// original widget. In that case, also refocus. This is messy.
if prev_focused != next_focused || disable_ime {
// We send FocusChange event to widget that lost and the widget that gained focus.
// We also request accessibility, because build_access_node() depends on the focus state.
if let Some(prev_focused) = prev_focused {
Expand All @@ -485,23 +494,24 @@ pub(crate) fn run_update_focus_pass(root: &mut RenderRoot) {
ctx.widget_state.request_accessibility = true;
ctx.widget_state.needs_accessibility = true;
});
}

if prev_focused.is_some() && was_ime_active {
root.global_state.emit_signal(RenderRootSignal::EndIme);
}
if next_focused.is_some() && is_ime_active {
root.global_state.emit_signal(RenderRootSignal::StartIme);
}
let widget_state = root.widget_arena.get_state(next_focused).item;

root.global_state.is_ime_active = widget_state.accepts_text_input;
if widget_state.accepts_text_input {
root.global_state.emit_signal(RenderRootSignal::StartIme);
}

if let Some(id) = next_focused {
let ime_area = root.widget_arena.get_state(id).item.get_ime_area();
root.global_state
.emit_signal(RenderRootSignal::new_ime_moved_signal(ime_area));
.emit_signal(RenderRootSignal::new_ime_moved_signal(
widget_state.get_ime_area(),
));
} else {
root.global_state.is_ime_active = false;
}
}

root.global_state.focused_widget = root.global_state.next_focused_widget;
root.global_state.focused_widget = next_focused;
root.global_state.focused_path = next_focused_path;
}

Expand Down
Loading