diff --git a/Cargo.toml b/Cargo.toml index 239be28533..6750586755 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,8 +85,8 @@ features = [ ] [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] -wayland-client = { version = "0.29", default_features = false, features = ["use_system_lib"], optional = true } -wayland-protocols = { version = "0.29", features = [ "staging_protocols"], optional = true } +wayland-client = { version = "0.29.4", default_features = false, features = ["use_system_lib"], optional = true } +wayland-protocols = { version = "0.29.4", features = [ "staging_protocols"], optional = true } sctk = { package = "smithay-client-toolkit", version = "0.15.1", default_features = false, features = ["calloop"], optional = true } mio = { version = "0.8", features = ["os-ext"], optional = true } x11-dl = { version = "2.18.5", optional = true } diff --git a/src/platform_impl/linux/wayland/seat/text_input/handlers.rs b/src/platform_impl/linux/wayland/seat/text_input/handlers.rs index 4ba13d6715..d3f0201428 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/handlers.rs @@ -5,11 +5,11 @@ use sctk::reexports::protocols::unstable::text_input::v3::client::zwp_text_input Event as TextInputEvent, ZwpTextInputV3, }; -use crate::event::WindowEvent; +use crate::event::{WindowEvent, IME}; use crate::platform_impl::wayland; use crate::platform_impl::wayland::event_loop::WinitState; -use super::{TextInputHandler, TextInputInner}; +use super::{Preedit, TextInputHandler, TextInputInner}; #[inline] pub(super) fn handle_text_input( @@ -38,6 +38,7 @@ pub(super) fn handle_text_input( text_input: text_input.detach(), }; window_handle.text_input_entered(text_input_handler); + event_sink.push_window_event(WindowEvent::IME(IME::Enabled), window_id); } TextInputEvent::Leave { surface } => { // Always issue a disable. @@ -58,19 +59,41 @@ pub(super) fn handle_text_input( text_input: text_input.detach(), }; window_handle.text_input_left(text_input_handler); + event_sink.push_window_event(WindowEvent::IME(IME::Disabled), window_id); + } + TextInputEvent::PreeditString { + text, + cursor_begin, + cursor_end, + } => { + let cursor_begin = usize::try_from(cursor_begin).ok(); + let cursor_end = usize::try_from(cursor_end).ok(); + let text = text.unwrap_or_default(); + inner.pending_preedit = Some(Preedit { + text, + cursor_begin, + cursor_end, + }); } TextInputEvent::CommitString { text } => { - // Update currenly commited string. - inner.commit_string = text; + // Update currenly commited string and reset previous preedit. + inner.pending_preedit = None; + inner.pending_commit = Some(text.unwrap_or_default()); } TextInputEvent::Done { .. } => { - let (window_id, text) = match (inner.target_window_id, inner.commit_string.take()) { - (Some(window_id), Some(text)) => (window_id, text), + let window_id = match inner.target_window_id { + Some(window_id) => window_id, _ => return, }; - for ch in text.chars() { - event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); + if let Some(text) = inner.pending_commit.take() { + event_sink.push_window_event(WindowEvent::IME(IME::Commit(text)), window_id); + } + + // Push preedit string we've got after latest commit. + if let Some(preedit) = inner.pending_preedit.take() { + let event = IME::Preedit(preedit.text, preedit.cursor_begin, preedit.cursor_end); + event_sink.push_window_event(WindowEvent::IME(event), window_id); } } _ => (), diff --git a/src/platform_impl/linux/wayland/seat/text_input/mod.rs b/src/platform_impl/linux/wayland/seat/text_input/mod.rs index 77f4ff0827..12ae7463e4 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/mod.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/mod.rs @@ -52,15 +52,25 @@ struct TextInputInner { /// Currently focused surface. target_window_id: Option, - /// Pending string to commit. - commit_string: Option, + /// Pending commit event which will be dispatched on `text_input_v3::Done`. + pending_commit: Option, + + /// Pending preedit event which will be dispatched on `text_input_v3::Done`. + pending_preedit: Option, +} + +struct Preedit { + text: String, + cursor_begin: Option, + cursor_end: Option, } impl TextInputInner { fn new() -> Self { Self { target_window_id: None, - commit_string: None, + pending_commit: None, + pending_preedit: None, } } }