From 594ed5cfbeec8c891406bd40349f64804f599397 Mon Sep 17 00:00:00 2001 From: KENZ Date: Sat, 28 Mar 2026 14:27:37 +0900 Subject: [PATCH] fix: Forward DeleteSurroundingText event in wayland backend --- .../wayland/event_loop/mod.rs | 1 + .../wayland/event_loop/state.rs | 1 + .../wayland/handlers/text_input.rs | 35 +++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 8cef290e..6c63f218 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -396,6 +396,7 @@ impl SctkEventLoop { pending_corner_radius: HashMap::new(), text_input: None, preedit: None, + pending_delete: None, pending_commit: None, }, _features: Default::default(), diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index aca83635..9c9a4e11 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -499,6 +499,7 @@ pub struct SctkState { pub(crate) text_input_manager: Option, pub(crate) text_input: Option>, pub(crate) preedit: Option, + pub(crate) pending_delete: Option<(usize, usize)>, pub(crate) pending_commit: Option, } diff --git a/winit/src/platform_specific/wayland/handlers/text_input.rs b/winit/src/platform_specific/wayland/handlers/text_input.rs index ed1ee8c9..bb0c38da 100644 --- a/winit/src/platform_specific/wayland/handlers/text_input.rs +++ b/winit/src/platform_specific/wayland/handlers/text_input.rs @@ -91,18 +91,47 @@ impl Dispatch for TextInputManager { cursor_begin.map(|b| (b, cursor_end.unwrap_or(b))); state.preedit = Some(Preedit { text, cursor_range }); } + TextInputEvent::DeleteSurroundingText { + before_length, + after_length, + } => { + state.pending_delete = Some(( + before_length.try_into().unwrap(), + after_length.try_into().unwrap(), + )); + } TextInputEvent::CommitString { text } => { state.preedit = None; state.pending_commit = text; } TextInputEvent::Done { .. } => { let id = WindowId::from_raw(kbd_focus.id().as_ptr() as usize); + + // Protocol says: + // https://wayland.app/protocols/text-input-unstable-v3#zwp_text_input_v3:event:done + // + // The application must proceed by evaluating the changes in the following order: + // + // 1. Replace existing preedit string with the cursor. state.sctk_events.push(SctkEvent::Winit( id, WindowEvent::Ime(Ime::Preedit(String::new(), None)), )); - // Commit string + // 2. Delete requested surrounding text. + if let Some((before_bytes, after_bytes)) = + state.pending_delete.take() + { + state.sctk_events.push(SctkEvent::Winit( + id, + WindowEvent::Ime(Ime::DeleteSurrounding { + before_bytes, + after_bytes, + }), + )); + } + + // 3. Insert commit string with the cursor at its end. if let Some(text) = state.pending_commit.take() { state.sctk_events.push(SctkEvent::Winit( id, @@ -110,7 +139,9 @@ impl Dispatch for TextInputManager { )); } - // Update preedit string + // 4. Calculate surrounding text to send. + // 5. Insert new preedit text in cursor position. + // 6. Place cursor inside preedit text. if let Some(preedit) = state.preedit.take() { state.sctk_events.push(SctkEvent::Winit( id,