Skip to content

Commit

Permalink
Add new IME event support for Wayland
Browse files Browse the repository at this point in the history
  • Loading branch information
kchibisov committed Feb 28, 2022
1 parent 8d63220 commit c152698
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 13 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Expand Up @@ -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 }
Expand Down
39 changes: 31 additions & 8 deletions src/platform_impl/linux/wayland/seat/text_input/handlers.rs
Expand Up @@ -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(
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
}
_ => (),
Expand Down
16 changes: 13 additions & 3 deletions src/platform_impl/linux/wayland/seat/text_input/mod.rs
Expand Up @@ -52,15 +52,25 @@ struct TextInputInner {
/// Currently focused surface.
target_window_id: Option<WindowId>,

/// Pending string to commit.
commit_string: Option<String>,
/// Pending commit event which will be dispatched on `text_input_v3::Done`.
pending_commit: Option<String>,

/// Pending preedit event which will be dispatched on `text_input_v3::Done`.
pending_preedit: Option<Preedit>,
}

struct Preedit {
text: String,
cursor_begin: Option<usize>,
cursor_end: Option<usize>,
}

impl TextInputInner {
fn new() -> Self {
Self {
target_window_id: None,
commit_string: None,
pending_commit: None,
pending_preedit: None,
}
}
}

0 comments on commit c152698

Please sign in to comment.