mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
feat: support pre-edit text display for IME (#35535)
* feat: support pre-edit text display for IME Signed-off-by: DK Liao <dklassic@gmail.com> * enable ime by show_ime Signed-off-by: DK Liao <dklassic@gmail.com> --------- Signed-off-by: DK Liao <dklassic@gmail.com>
This commit is contained in:
parent
42e873e9d9
commit
720bc725b0
6 changed files with 91 additions and 4 deletions
|
@ -2652,8 +2652,6 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
event.type_() == atom!("compositionend")) &&
|
event.type_() == atom!("compositionend")) &&
|
||||||
self.input_type().is_textual_or_password()
|
self.input_type().is_textual_or_password()
|
||||||
{
|
{
|
||||||
// TODO: Update DOM on start and continue
|
|
||||||
// and generally do proper CompositionEvent handling.
|
|
||||||
if let Some(compositionevent) = event.downcast::<CompositionEvent>() {
|
if let Some(compositionevent) = event.downcast::<CompositionEvent>() {
|
||||||
if event.type_() == atom!("compositionend") {
|
if event.type_() == atom!("compositionend") {
|
||||||
let _ = self
|
let _ = self
|
||||||
|
@ -2661,6 +2659,12 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.handle_compositionend(compositionevent);
|
.handle_compositionend(compositionevent);
|
||||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
} else if event.type_() == atom!("compositionupdate") {
|
||||||
|
let _ = self
|
||||||
|
.textinput
|
||||||
|
.borrow_mut()
|
||||||
|
.handle_compositionupdate(compositionevent);
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
}
|
}
|
||||||
event.mark_as_handled();
|
event.mark_as_handled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -668,8 +668,6 @@ impl VirtualMethods for HTMLTextAreaElement {
|
||||||
event.type_() == atom!("compositionupdate") ||
|
event.type_() == atom!("compositionupdate") ||
|
||||||
event.type_() == atom!("compositionend")
|
event.type_() == atom!("compositionend")
|
||||||
{
|
{
|
||||||
// TODO: Update DOM on start and continue
|
|
||||||
// and generally do proper CompositionEvent handling.
|
|
||||||
if let Some(compositionevent) = event.downcast::<CompositionEvent>() {
|
if let Some(compositionevent) = event.downcast::<CompositionEvent>() {
|
||||||
if event.type_() == atom!("compositionend") {
|
if event.type_() == atom!("compositionend") {
|
||||||
let _ = self
|
let _ = self
|
||||||
|
@ -677,6 +675,12 @@ impl VirtualMethods for HTMLTextAreaElement {
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.handle_compositionend(compositionevent);
|
.handle_compositionend(compositionevent);
|
||||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
} else if event.type_() == atom!("compositionupdate") {
|
||||||
|
let _ = self
|
||||||
|
.textinput
|
||||||
|
.borrow_mut()
|
||||||
|
.handle_compositionupdate(compositionevent);
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
}
|
}
|
||||||
event.mark_as_handled();
|
event.mark_as_handled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -988,6 +988,17 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn handle_compositionupdate(&mut self, event: &CompositionEvent) -> KeyReaction {
|
||||||
|
let start = self.selection_start_offset().0;
|
||||||
|
self.insert_string(event.data());
|
||||||
|
self.set_selection_range(
|
||||||
|
start as u32,
|
||||||
|
(start + event.data().len_utf8().0) as u32,
|
||||||
|
SelectionDirection::Forward,
|
||||||
|
);
|
||||||
|
KeyReaction::DispatchInput
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the content is empty.
|
/// Whether the content is empty.
|
||||||
pub(crate) fn is_empty(&self) -> bool {
|
pub(crate) fn is_empty(&self) -> bool {
|
||||||
self.lines.len() <= 1 && self.lines.first().map_or(true, |line| line.is_empty())
|
self.lines.len() <= 1 && self.lines.first().map_or(true, |line| line.is_empty())
|
||||||
|
|
|
@ -527,6 +527,22 @@ impl WebViewDelegate for RunningAppState {
|
||||||
};
|
};
|
||||||
let _ = haptic_stop_sender.send(stopped);
|
let _ = haptic_stop_sender.send(stopped);
|
||||||
}
|
}
|
||||||
|
fn show_ime(
|
||||||
|
&self,
|
||||||
|
_webview: WebView,
|
||||||
|
input_type: servo::InputMethodType,
|
||||||
|
text: Option<(String, i32)>,
|
||||||
|
multiline: bool,
|
||||||
|
position: servo::webrender_api::units::DeviceIntRect,
|
||||||
|
) {
|
||||||
|
self.inner()
|
||||||
|
.window
|
||||||
|
.show_ime(input_type, text, multiline, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide_ime(&self, _webview: WebView) {
|
||||||
|
self.inner().window.hide_ime();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|
|
@ -631,6 +631,35 @@ impl WindowPortsMethods for Window {
|
||||||
WindowEvent::Moved(_new_position) => {
|
WindowEvent::Moved(_new_position) => {
|
||||||
webview.notify_embedder_window_moved();
|
webview.notify_embedder_window_moved();
|
||||||
},
|
},
|
||||||
|
winit::event::WindowEvent::Ime(ime) => match ime {
|
||||||
|
winit::event::Ime::Enabled => {
|
||||||
|
webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Composition(
|
||||||
|
servo::CompositionEvent {
|
||||||
|
state: servo::CompositionState::Start,
|
||||||
|
data: String::new(),
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
winit::event::Ime::Preedit(text, _) => {
|
||||||
|
webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Composition(
|
||||||
|
servo::CompositionEvent {
|
||||||
|
state: servo::CompositionState::Update,
|
||||||
|
data: text,
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
winit::event::Ime::Commit(text) => {
|
||||||
|
webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Composition(
|
||||||
|
servo::CompositionEvent {
|
||||||
|
state: servo::CompositionState::End,
|
||||||
|
data: text,
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
winit::event::Ime::Disabled => {
|
||||||
|
webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Dismissed));
|
||||||
|
},
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -673,6 +702,19 @@ impl WindowPortsMethods for Window {
|
||||||
fn rendering_context(&self) -> Rc<dyn RenderingContext> {
|
fn rendering_context(&self) -> Rc<dyn RenderingContext> {
|
||||||
self.rendering_context.clone()
|
self.rendering_context.clone()
|
||||||
}
|
}
|
||||||
|
fn show_ime(
|
||||||
|
&self,
|
||||||
|
_input_type: servo::InputMethodType,
|
||||||
|
_text: Option<(String, i32)>,
|
||||||
|
_multiline: bool,
|
||||||
|
_position: servo::webrender_api::units::DeviceIntRect,
|
||||||
|
) {
|
||||||
|
self.winit_window.set_ime_allowed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide_ime(&self) {
|
||||||
|
self.winit_window.set_ime_allowed(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowMethods for Window {
|
impl WindowMethods for Window {
|
||||||
|
|
|
@ -47,4 +47,14 @@ pub trait WindowPortsMethods: WindowMethods {
|
||||||
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel>;
|
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel>;
|
||||||
fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>);
|
fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>);
|
||||||
fn rendering_context(&self) -> Rc<dyn RenderingContext>;
|
fn rendering_context(&self) -> Rc<dyn RenderingContext>;
|
||||||
|
fn show_ime(
|
||||||
|
&self,
|
||||||
|
_input_type: servo::InputMethodType,
|
||||||
|
_text: Option<(String, i32)>,
|
||||||
|
_multiline: bool,
|
||||||
|
_position: servo::webrender_api::units::DeviceIntRect,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide_ime(&self) {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue