IME: Handle composition events to show suggestion on web (#278)

* Handle composition message to show suggestion.

* CI check

* Apply suggestions from code review

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>

* Some minor changes

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
Lin Han 2021-04-13 02:57:14 +08:00 committed by GitHub
parent 0353f40dd5
commit 20bf09560e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 8 deletions

View file

@ -116,6 +116,13 @@ pub enum Event {
///
/// On touch-up first send `PointerButton{pressed: false, …}` followed by `PointerLeft`.
PointerGone,
/// IME composition start.
CompositionStart,
/// A new IME candidate is being suggested.
CompositionUpdate(String),
/// IME composition ended with this final result.
CompositionEnd(String),
}
/// Mouse button (or similar for touch input)

View file

@ -9,6 +9,10 @@ pub(crate) struct State {
#[cfg_attr(feature = "persistence", serde(skip))]
undoer: Undoer<(CCursorPair, String)>,
// If IME candidate window is shown on this text edit.
#[cfg_attr(feature = "persistence", serde(skip))]
has_ime: bool,
}
#[derive(Clone, Copy, Debug, Default)]
@ -503,6 +507,41 @@ impl<'t> TextEdit<'t> {
modifiers,
} => on_key_press(&mut cursorp, text, &galley, *key, modifiers),
Event::CompositionStart => {
state.has_ime = true;
None
}
Event::CompositionUpdate(text_mark) => {
if !text_mark.is_empty()
&& text_mark != "\n"
&& text_mark != "\r"
&& state.has_ime
{
let mut ccursor = delete_selected(text, &cursorp);
let start_cursor = ccursor;
insert_text(&mut ccursor, text, text_mark);
Some(CCursorPair::two(start_cursor, ccursor))
} else {
None
}
}
Event::CompositionEnd(prediction) => {
if !prediction.is_empty()
&& prediction != "\n"
&& prediction != "\r"
&& state.has_ime
{
state.has_ime = false;
let mut ccursor = delete_selected(text, &cursorp);
insert_text(&mut ccursor, text, prediction);
Some(CCursorPair::one(ccursor))
} else {
None
}
}
_ => None,
};

View file

@ -708,22 +708,27 @@ fn install_text_agent(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
let input_clone = input.clone();
let runner_ref = runner_ref.clone();
let on_compositionend = Closure::wrap(Box::new(move |event: web_sys::CompositionEvent| {
match event.type_().as_ref() {
let mut runner_lock = runner_ref.0.lock();
let opt_event = match event.type_().as_ref() {
"compositionstart" => {
is_composing.set(true);
input_clone.set_value("");
Some(egui::Event::CompositionStart)
}
"compositionend" => {
is_composing.set(false);
input_clone.set_value("");
if let Some(text) = event.data() {
let mut runner_lock = runner_ref.0.lock();
runner_lock.input.raw.events.push(egui::Event::Text(text));
runner_lock.needs_repaint.set_true();
}
event.data().map(egui::Event::CompositionEnd)
}
"compositionupdate" => {}
_s => panic!("Unknown type"),
"compositionupdate" => event.data().map(egui::Event::CompositionUpdate),
s => {
console_error(format!("Unknown composition event type: {:?}", s));
None
}
};
if let Some(event) = opt_event {
runner_lock.input.raw.events.push(event);
runner_lock.needs_repaint.set_true();
}
}) as Box<dyn FnMut(_)>);
let f = on_compositionend.as_ref().unchecked_ref();