mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 05:40:03 -04:00
Feat(eframe/web): add best-effort support for IME preedit visulas for browsers
This commit is contained in:
@@ -62,14 +62,56 @@ impl TextAgent {
|
|||||||
input.blur().ok();
|
input.blur().ok();
|
||||||
input.focus().ok();
|
input.focus().ok();
|
||||||
}
|
}
|
||||||
// if `is_composing` is true, then user is using IME, for example: emoji, pinyin, kanji, hangul, etc.
|
|
||||||
// In that case, the browser emits both `input` and `compositionupdate` events,
|
if event.is_composing() {
|
||||||
// and we need to ignore the `input` event.
|
// if `is_composing` is true, then user is using IME, for
|
||||||
if !text.is_empty() && !event.is_composing() {
|
// example: emoji, pinyin, kanji, hangul, etc. In that case,
|
||||||
input.set_value("");
|
// the browser emits both `input` and `compositionupdate`
|
||||||
let event = egui::Event::Text(text);
|
// events.
|
||||||
|
// We handle the composition update here instead of in the
|
||||||
|
// `compositionupdate` event because the selection range
|
||||||
|
// has not yet been updated when `compositionupdate` fires.
|
||||||
|
|
||||||
|
let Some(text) = event.data() else { return };
|
||||||
|
let selection_start = input
|
||||||
|
.selection_start()
|
||||||
|
.unwrap_or(None)
|
||||||
|
.map(|pos| pos as usize);
|
||||||
|
let selection_end = input
|
||||||
|
.selection_end()
|
||||||
|
.unwrap_or(None)
|
||||||
|
.map(|pos| pos as usize);
|
||||||
|
let active_range_chars = if let Some(selection_start) = selection_start
|
||||||
|
&& let Some(selection_end) = selection_end
|
||||||
|
{
|
||||||
|
let text_utf16 = text.encode_utf16().collect::<Vec<u16>>();
|
||||||
|
let text_before_selection =
|
||||||
|
String::from_utf16_lossy(&text_utf16[..selection_start]);
|
||||||
|
let text_in_selection =
|
||||||
|
String::from_utf16_lossy(&text_utf16[selection_start..selection_end]);
|
||||||
|
let count_before_selection = text_before_selection.chars().count();
|
||||||
|
let count_in_selection = text_in_selection.chars().count();
|
||||||
|
Some(count_before_selection..count_before_selection + count_in_selection)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let event = egui::Event::Ime(egui::ImeEvent::Preedit {
|
||||||
|
text,
|
||||||
|
active_range_chars,
|
||||||
|
});
|
||||||
runner.input.raw.events.push(event);
|
runner.input.raw.events.push(event);
|
||||||
runner.needs_repaint.repaint_asap();
|
runner.needs_repaint.repaint_asap();
|
||||||
|
} else {
|
||||||
|
if text.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !event.is_composing() {
|
||||||
|
input.set_value("");
|
||||||
|
let event = egui::Event::Text(text);
|
||||||
|
runner.input.raw.events.push(event);
|
||||||
|
runner.needs_repaint.repaint_asap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -82,19 +124,6 @@ impl TextAgent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let on_composition_update = {
|
|
||||||
move |event: web_sys::CompositionEvent, runner: &mut AppRunner| {
|
|
||||||
let Some(text) = event.data() else { return };
|
|
||||||
let event = egui::Event::Ime(egui::ImeEvent::Preedit {
|
|
||||||
text,
|
|
||||||
// TODO(umajho): implement this.
|
|
||||||
active_range_chars: None,
|
|
||||||
});
|
|
||||||
runner.input.raw.events.push(event);
|
|
||||||
runner.needs_repaint.repaint_asap();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let on_composition_end = {
|
let on_composition_end = {
|
||||||
let input = input.clone();
|
let input = input.clone();
|
||||||
move |event: web_sys::CompositionEvent, runner: &mut AppRunner| {
|
move |event: web_sys::CompositionEvent, runner: &mut AppRunner| {
|
||||||
@@ -108,7 +137,6 @@ impl TextAgent {
|
|||||||
|
|
||||||
runner_ref.add_event_listener(&input, "input", on_input)?;
|
runner_ref.add_event_listener(&input, "input", on_input)?;
|
||||||
runner_ref.add_event_listener(&input, "compositionstart", on_composition_start)?;
|
runner_ref.add_event_listener(&input, "compositionstart", on_composition_start)?;
|
||||||
runner_ref.add_event_listener(&input, "compositionupdate", on_composition_update)?;
|
|
||||||
runner_ref.add_event_listener(&input, "compositionend", on_composition_end)?;
|
runner_ref.add_event_listener(&input, "compositionend", on_composition_end)?;
|
||||||
|
|
||||||
// The canvas doesn't get keydown/keyup events when the text agent is focused,
|
// The canvas doesn't get keydown/keyup events when the text agent is focused,
|
||||||
|
|||||||
Reference in New Issue
Block a user