From 76e13be006dd7651b816ea04106d4279564b9312 Mon Sep 17 00:00:00 2001 From: XDeme Date: Sat, 11 May 2024 17:44:01 -0300 Subject: [PATCH 1/9] Wayland: Implement text_input_v3 --- .../gpui/src/platform/linux/wayland/client.rs | 105 +++++++++++++++++- .../gpui/src/platform/linux/wayland/serial.rs | 1 + .../gpui/src/platform/linux/wayland/window.rs | 64 +++++++++++ 3 files changed, 168 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index b5aed4e941a2..46edb1b29057 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -41,6 +41,12 @@ use wayland_protocols::wp::cursor_shape::v1::client::{ use wayland_protocols::wp::fractional_scale::v1::client::{ wp_fractional_scale_manager_v1, wp_fractional_scale_v1, }; +use wayland_protocols::wp::text_input::zv3::client::zwp_text_input_v3::{ + ContentHint, ContentPurpose, +}; +use wayland_protocols::wp::text_input::zv3::client::{ + zwp_text_input_manager_v3, zwp_text_input_v3, +}; use wayland_protocols::wp::viewporter::client::{wp_viewport, wp_viewporter}; use wayland_protocols::xdg::activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1}; use wayland_protocols::xdg::decoration::zv1::client::{ @@ -85,6 +91,7 @@ pub struct Globals { Option, pub decoration_manager: Option, pub blur_manager: Option, + pub text_input_manager: Option, pub executor: ForegroundExecutor, } @@ -118,6 +125,7 @@ impl Globals { fractional_scale_manager: globals.bind(&qh, 1..=1, ()).ok(), decoration_manager: globals.bind(&qh, 1..=1, ()).ok(), blur_manager: globals.bind(&qh, 1..=1, ()).ok(), + text_input_manager: globals.bind(&qh, 1..=1, ()).ok(), executor, qh, } @@ -131,6 +139,8 @@ pub(crate) struct WaylandClientState { wl_pointer: Option, cursor_shape_device: Option, data_device: Option, + text_input: Option, + pre_edit_text: Option, // Surface to Window mapping windows: HashMap, // Output to scale mapping @@ -233,6 +243,9 @@ impl Drop for WaylandClient { if let Some(data_device) = &state.data_device { data_device.release(); } + if let Some(text_input) = &state.text_input { + text_input.destroy(); + } } } @@ -321,6 +334,8 @@ impl WaylandClient { wl_pointer: None, cursor_shape_device: None, data_device, + text_input: None, + pre_edit_text: None, output_scales: outputs, windows: HashMap::default(), common, @@ -564,6 +579,7 @@ delegate_noop!(WaylandClientStatePtr: ignore wl_region::WlRegion); delegate_noop!(WaylandClientStatePtr: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1); delegate_noop!(WaylandClientStatePtr: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1); delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur_manager::OrgKdeKwinBlurManager); +delegate_noop!(WaylandClientStatePtr: ignore zwp_text_input_manager_v3::ZwpTextInputManagerV3); delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur::OrgKdeKwinBlur); delegate_noop!(WaylandClientStatePtr: ignore wp_viewporter::WpViewporter); delegate_noop!(WaylandClientStatePtr: ignore wp_viewport::WpViewport); @@ -740,12 +756,17 @@ impl Dispatch for WaylandClientStatePtr { capabilities: WEnum::Value(capabilities), } = event { + let client = state.get_client(); + let mut state = client.borrow_mut(); if capabilities.contains(wl_seat::Capability::Keyboard) { seat.get_keyboard(qh, ()); + state.text_input = state + .globals + .text_input_manager + .as_ref() + .map(|text_input_manager| text_input_manager.get_text_input(&seat, qh, ())); } if capabilities.contains(wl_seat::Capability::Pointer) { - let client = state.get_client(); - let mut state = client.borrow_mut(); let pointer = seat.get_pointer(qh, ()); state.cursor_shape_device = state .globals @@ -919,6 +940,86 @@ impl Dispatch for WaylandClientStatePtr { } } } +impl Dispatch for WaylandClientStatePtr { + fn event( + this: &mut Self, + text_input: &zwp_text_input_v3::ZwpTextInputV3, + event: ::Event, + data: &(), + conn: &Connection, + qhandle: &QueueHandle, + ) { + let client = this.get_client(); + let mut state = client.borrow_mut(); + match event { + zwp_text_input_v3::Event::Enter { surface } => { + text_input.enable(); + text_input.set_content_type(ContentHint::None, ContentPurpose::Normal); + + if let Some(window) = state.keyboard_focused_window.clone() { + drop(state); + if let Some(area) = window.get_ime_area() { + text_input.set_cursor_rectangle( + area.origin.x.0 as i32, + area.origin.y.0 as i32, + area.size.width.0 as i32, + area.size.height.0 as i32, + ); + } + } + text_input.commit(); + } + zwp_text_input_v3::Event::Leave { surface } => { + text_input.disable(); + text_input.commit(); + } + zwp_text_input_v3::Event::CommitString { text } => { + let Some(window) = state.keyboard_focused_window.clone() else { + return; + }; + + if let Some(commit_text) = text { + drop(state); + window.handle_ime_commit(commit_text); + } + } + zwp_text_input_v3::Event::PreeditString { + text, + cursor_begin, + cursor_end, + } => { + state.pre_edit_text = text; + } + zwp_text_input_v3::Event::Done { serial } => { + let last_serial = state.serial_tracker.get(SerialKind::InputMethod); + state.serial_tracker.update(SerialKind::InputMethod, serial); + let Some(window) = state.keyboard_focused_window.clone() else { + return; + }; + + if let Some(text) = state.pre_edit_text.take() { + drop(state); + window.handle_ime_preedit(text); + if let Some(area) = window.get_ime_area() { + text_input.set_cursor_rectangle( + area.origin.x.0 as i32, + area.origin.y.0 as i32, + area.size.width.0 as i32, + area.size.height.0 as i32, + ); + if last_serial == serial { + text_input.commit(); + } + } + } else { + drop(state); + window.handle_ime_delete(); + } + } + _ => {} + } + } +} fn linux_button_to_gpui(button: u32) -> Option { // These values are coming from . diff --git a/crates/gpui/src/platform/linux/wayland/serial.rs b/crates/gpui/src/platform/linux/wayland/serial.rs index 14d2dea3b33f..ff647615d120 100644 --- a/crates/gpui/src/platform/linux/wayland/serial.rs +++ b/crates/gpui/src/platform/linux/wayland/serial.rs @@ -5,6 +5,7 @@ use collections::HashMap; #[derive(Debug, Hash, PartialEq, Eq)] pub(crate) enum SerialKind { DataDevice, + InputMethod, MouseEnter, MousePress, KeyPress, diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 8924a322b544..b998a1a1de00 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -417,6 +417,70 @@ impl WaylandWindowStatePtr { } } + pub fn handle_ime_commit(&self, text: String) { + if let Some(ref mut fun) = self.callbacks.borrow_mut().input { + if !fun(PlatformInput::KeyUp(crate::KeyUpEvent { + keystroke: crate::Keystroke::default(), + })) + .propagate + { + return; + } + } + let mut state = self.state.borrow_mut(); + if let Some(mut input_handler) = state.input_handler.take() { + drop(state); + input_handler.replace_text_in_range(None, &text); + self.state.borrow_mut().input_handler = Some(input_handler); + } + } + + pub fn handle_ime_preedit(&self, text: String) { + if let Some(ref mut fun) = self.callbacks.borrow_mut().input { + if !fun(PlatformInput::KeyUp(crate::KeyUpEvent { + keystroke: crate::Keystroke::default(), + })) + .propagate + { + return; + } + } + let mut state = self.state.borrow_mut(); + if let Some(mut input_handler) = state.input_handler.take() { + drop(state); + input_handler.replace_and_mark_text_in_range( + None, + &text, + Some(0..text.chars().count()), + ); + self.state.borrow_mut().input_handler = Some(input_handler); + } + } + + pub fn handle_ime_delete(&self) { + let mut state = self.state.borrow_mut(); + if let Some(mut input_handler) = state.input_handler.take() { + drop(state); + if let Some(marked) = input_handler.marked_text_range() { + input_handler.replace_text_in_range(Some(marked), ""); + }; + self.state.borrow_mut().input_handler = Some(input_handler); + } + } + + pub fn get_ime_area(&self) -> Option> { + let mut state = self.state.borrow_mut(); + let mut bounds: Option> = None; + if let Some(mut input_handler) = state.input_handler.take() { + drop(state); + if let Some(range) = input_handler.marked_text_range() { + bounds = input_handler.bounds_for_range(range); + } + self.state.borrow_mut().input_handler = Some(input_handler); + } + bounds + } + pub fn set_size_and_scale( &self, width: Option, From 672f2f798789930fa277da762f018132ebb5ab45 Mon Sep 17 00:00:00 2001 From: XDeme Date: Sat, 11 May 2024 20:23:15 -0300 Subject: [PATCH 2/9] Small update --- crates/gpui/src/platform/linux/wayland/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index b998a1a1de00..2b4acfe360df 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -473,7 +473,7 @@ impl WaylandWindowStatePtr { let mut bounds: Option> = None; if let Some(mut input_handler) = state.input_handler.take() { drop(state); - if let Some(range) = input_handler.marked_text_range() { + if let Some(range) = input_handler.selected_text_range() { bounds = input_handler.bounds_for_range(range); } self.state.borrow_mut().input_handler = Some(input_handler); From 5191ba2c6167e13976ee979fbda212a361568a0b Mon Sep 17 00:00:00 2001 From: XDeme Date: Sun, 12 May 2024 14:18:49 -0300 Subject: [PATCH 3/9] Added support for xkb compose --- crates/gpui/src/platform/linux/platform.rs | 62 +++++++++++++++++++ .../gpui/src/platform/linux/wayland/client.rs | 60 +++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs index c1f6df1593bb..1fdc88c2448f 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/crates/gpui/src/platform/linux/platform.rs @@ -632,6 +632,68 @@ impl Keystroke { ime_key, } } + + /** + * Returns which symbol the dead key represents + * https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values#dead_keycodes_for_linux + */ + pub fn underlying_dead_key(keysym: Keysym) -> Option { + match keysym { + Keysym::dead_grave => Some("`".to_owned()), + Keysym::dead_acute => Some("´".to_owned()), + Keysym::dead_circumflex => Some("^".to_owned()), + Keysym::dead_tilde => Some("~".to_owned()), + Keysym::dead_perispomeni => Some("͂".to_owned()), + Keysym::dead_macron => Some("¯".to_owned()), + Keysym::dead_breve => Some("˘".to_owned()), + Keysym::dead_abovedot => Some("˙".to_owned()), + Keysym::dead_diaeresis => Some("¨".to_owned()), + Keysym::dead_abovering => Some("˚".to_owned()), + Keysym::dead_doubleacute => Some("˝".to_owned()), + Keysym::dead_caron => Some("ˇ".to_owned()), + Keysym::dead_cedilla => Some("¸".to_owned()), + Keysym::dead_ogonek => Some("˛".to_owned()), + Keysym::dead_iota => Some("ͅ".to_owned()), + Keysym::dead_voiced_sound => Some("゙".to_owned()), + Keysym::dead_semivoiced_sound => Some("゚".to_owned()), + Keysym::dead_belowdot => Some("̣̣".to_owned()), + Keysym::dead_hook => Some("̡".to_owned()), + Keysym::dead_horn => Some("̛".to_owned()), + Keysym::dead_stroke => Some("̶̶".to_owned()), + Keysym::dead_abovecomma => Some("̓̓".to_owned()), + Keysym::dead_psili => Some("᾿".to_owned()), + Keysym::dead_abovereversedcomma => Some("ʽ".to_owned()), + Keysym::dead_dasia => Some("῾".to_owned()), + Keysym::dead_doublegrave => Some("̏".to_owned()), + Keysym::dead_belowring => Some("˳".to_owned()), + Keysym::dead_belowmacron => Some("̱".to_owned()), + Keysym::dead_belowcircumflex => Some("ꞈ".to_owned()), + Keysym::dead_belowtilde => Some("̰".to_owned()), + Keysym::dead_belowbreve => Some("̮".to_owned()), + Keysym::dead_belowdiaeresis => Some("̤".to_owned()), + Keysym::dead_invertedbreve => Some("̯".to_owned()), + Keysym::dead_belowcomma => Some("̦".to_owned()), + Keysym::dead_currency => None, + Keysym::dead_lowline => None, + Keysym::dead_aboveverticalline => None, + Keysym::dead_belowverticalline => None, + Keysym::dead_longsolidusoverlay => None, + Keysym::dead_a => None, + Keysym::dead_A => None, + Keysym::dead_e => None, + Keysym::dead_E => None, + Keysym::dead_i => None, + Keysym::dead_I => None, + Keysym::dead_o => None, + Keysym::dead_O => None, + Keysym::dead_u => None, + Keysym::dead_U => None, + Keysym::dead_small_schwa => Some("ə".to_owned()), + Keysym::dead_capital_schwa => Some("Ə".to_owned()), + Keysym::dead_greek => None, + _ => None, + } + } } impl Modifiers { diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 46edb1b29057..eb1226cdfa6c 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -1,5 +1,6 @@ use core::hash; use std::cell::{RefCell, RefMut}; +use std::ffi::OsString; use std::os::fd::{AsRawFd, BorrowedFd}; use std::path::PathBuf; use std::rc::{Rc, Weak}; @@ -146,6 +147,7 @@ pub(crate) struct WaylandClientState { // Output to scale mapping output_scales: HashMap, keymap_state: Option, + compose_state: Option, drag: DragState, click: ClickState, repeat: KeyRepeat, @@ -340,6 +342,7 @@ impl WaylandClient { windows: HashMap::default(), common, keymap_state: None, + compose_state: None, drag: DragState { data_offer: None, window: None, @@ -806,9 +809,10 @@ impl Dispatch for WaylandClientStatePtr { wl_keyboard::KeymapFormat::XkbV1, "Unsupported keymap format" ); + let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); let keymap = unsafe { xkb::Keymap::new_from_fd( - &xkb::Context::new(xkb::CONTEXT_NO_FLAGS), + &xkb_context, fd, size as usize, XKB_KEYMAP_FORMAT_TEXT_V1, @@ -818,7 +822,21 @@ impl Dispatch for WaylandClientStatePtr { .flatten() .expect("Failed to create keymap") }; + let table = { + let locale = std::env::var_os("LC_CTYPE").unwrap_or(OsString::from("C")); + xkb::compose::Table::new_from_locale( + &xkb_context, + &locale, + xkb::compose::COMPILE_NO_FLAGS, + ) + .log_err() + .unwrap() + }; state.keymap_state = Some(xkb::State::new(&keymap)); + state.compose_state = Some(xkb::compose::State::new( + &table, + xkb::compose::STATE_NO_FLAGS, + )); } wl_keyboard::Event::Enter { surface, .. } => { state.keyboard_focused_window = get_window(&mut state, &surface.id()); @@ -882,8 +900,46 @@ impl Dispatch for WaylandClientStatePtr { match key_state { wl_keyboard::KeyState::Pressed if !keysym.is_modifier_key() => { + let mut keystroke = + Keystroke::from_xkb(&keymap_state, state.modifiers, keycode); + if let Some(mut compose) = state.compose_state.take() { + compose.feed(keysym); + match compose.status() { + xkb::Status::Composing => { + state.pre_edit_text = + compose.utf8().or(Keystroke::underlying_dead_key(keysym)); + let pre_edit = + state.pre_edit_text.clone().unwrap_or(String::default()); + drop(state); + focused_window.handle_ime_preedit(pre_edit); + state = client.borrow_mut(); + } + + xkb::Status::Composed => { + state.pre_edit_text.take(); + keystroke.ime_key = compose.utf8(); + keystroke.key = xkb::keysym_get_name(compose.keysym().unwrap()); + } + xkb::Status::Cancelled => { + let pre_edit = state.pre_edit_text.take(); + drop(state); + if let Some(pre_edit) = pre_edit { + focused_window.handle_ime_commit(pre_edit); + } + if let Some(current_key) = + Keystroke::underlying_dead_key(keysym) + { + focused_window.handle_ime_preedit(current_key); + } + compose.feed(keysym); + state = client.borrow_mut(); + } + _ => {} + } + state.compose_state = Some(compose); + } let input = PlatformInput::KeyDown(KeyDownEvent { - keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode), + keystroke: keystroke, is_held: false, // todo(linux) }); From e91f27b49f3c7d461b4ddeee58893bbaf8332d61 Mon Sep 17 00:00:00 2001 From: XDeme Date: Sun, 12 May 2024 19:42:40 -0300 Subject: [PATCH 4/9] Remove select text highlight --- crates/gpui/src/platform/linux/wayland/window.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 2b4acfe360df..ec77bbfd5634 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -448,11 +448,7 @@ impl WaylandWindowStatePtr { let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { drop(state); - input_handler.replace_and_mark_text_in_range( - None, - &text, - Some(0..text.chars().count()), - ); + input_handler.replace_and_mark_text_in_range(None, &text, None); self.state.borrow_mut().input_handler = Some(input_handler); } } From 65877810df43e903fef5932e3cbc5003e1c17891 Mon Sep 17 00:00:00 2001 From: XDeme Date: Sun, 12 May 2024 20:04:44 -0300 Subject: [PATCH 5/9] Reset compose state when keyboard focus is lost --- crates/gpui/src/platform/linux/wayland/client.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index eb1226cdfa6c..0ed6c993607a 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -853,7 +853,9 @@ impl Dispatch for WaylandClientStatePtr { state.enter_token.take(); if let Some(window) = keyboard_focused_window { + state.pre_edit_text.take(); drop(state); + window.handle_ime_delete(); window.set_focused(false); } } From 8dd27d397fee8ec5484ce0cf8e64d589c788a241 Mon Sep 17 00:00:00 2001 From: XDeme Date: Sun, 12 May 2024 22:03:53 -0300 Subject: [PATCH 6/9] Small update --- crates/gpui/src/platform/linux/wayland/client.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 0ed6c993607a..d8217632f725 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -853,6 +853,9 @@ impl Dispatch for WaylandClientStatePtr { state.enter_token.take(); if let Some(window) = keyboard_focused_window { + if let Some(ref mut compose) = state.compose_state { + compose.reset(); + } state.pre_edit_text.take(); drop(state); window.handle_ime_delete(); @@ -1197,6 +1200,13 @@ impl Dispatch for WaylandClientStatePtr { } match button_state { wl_pointer::ButtonState::Pressed => { + if let Some(pre_edit) = state.pre_edit_text.take() { + if let Some(window) = state.keyboard_focused_window.clone() { + drop(state); + window.handle_ime_commit(pre_edit); + state = client.borrow_mut(); + } + } let click_elapsed = state.click.last_click.elapsed(); if click_elapsed < DOUBLE_CLICK_INTERVAL From 32f133dd9bb54948592106556263bd925701aa55 Mon Sep 17 00:00:00 2001 From: XDeme Date: Mon, 13 May 2024 15:47:23 -0300 Subject: [PATCH 7/9] Reset compose state on pointer click --- crates/gpui/src/platform/linux/wayland/client.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index d8217632f725..55c3b848f1cd 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -1200,12 +1200,15 @@ impl Dispatch for WaylandClientStatePtr { } match button_state { wl_pointer::ButtonState::Pressed => { - if let Some(pre_edit) = state.pre_edit_text.take() { - if let Some(window) = state.keyboard_focused_window.clone() { - drop(state); - window.handle_ime_commit(pre_edit); - state = client.borrow_mut(); - } + if let (Some(window), Some(pre_edit), Some(compose_state)) = ( + state.keyboard_focused_window.clone(), + state.pre_edit_text.take(), + state.compose_state.as_mut(), + ) { + compose_state.reset(); + drop(state); + window.handle_ime_commit(pre_edit); + state = client.borrow_mut(); } let click_elapsed = state.click.last_click.elapsed(); From 9f70ff06bf76074ec9ced4b0ed5c1de69c4abebd Mon Sep 17 00:00:00 2001 From: XDeme Date: Tue, 14 May 2024 17:27:23 -0300 Subject: [PATCH 8/9] Remove Keyup Events --- .../gpui/src/platform/linux/wayland/window.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index ec77bbfd5634..0ba6f50ebc9a 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -418,15 +418,6 @@ impl WaylandWindowStatePtr { } pub fn handle_ime_commit(&self, text: String) { - if let Some(ref mut fun) = self.callbacks.borrow_mut().input { - if !fun(PlatformInput::KeyUp(crate::KeyUpEvent { - keystroke: crate::Keystroke::default(), - })) - .propagate - { - return; - } - } let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { drop(state); @@ -436,15 +427,6 @@ impl WaylandWindowStatePtr { } pub fn handle_ime_preedit(&self, text: String) { - if let Some(ref mut fun) = self.callbacks.borrow_mut().input { - if !fun(PlatformInput::KeyUp(crate::KeyUpEvent { - keystroke: crate::Keystroke::default(), - })) - .propagate - { - return; - } - } let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { drop(state); From 878f4d6c04afce77f83c3fcd8174db8961d69bda Mon Sep 17 00:00:00 2001 From: XDeme Date: Tue, 14 May 2024 20:43:40 -0300 Subject: [PATCH 9/9] Unify handle_ime --- .../gpui/src/platform/linux/wayland/client.rs | 21 +++++----- .../gpui/src/platform/linux/wayland/window.rs | 42 +++++++++---------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 55c3b848f1cd..a565c35609ed 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -59,7 +59,7 @@ use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1; use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS}; use super::super::{open_uri_internal, read_fd, DOUBLE_CLICK_INTERVAL}; -use super::window::{WaylandWindowState, WaylandWindowStatePtr}; +use super::window::{ImeInput, WaylandWindowState, WaylandWindowStatePtr}; use crate::platform::linux::is_within_click_distance; use crate::platform::linux::wayland::cursor::Cursor; use crate::platform::linux::wayland::serial::{SerialKind, SerialTracker}; @@ -858,7 +858,7 @@ impl Dispatch for WaylandClientStatePtr { } state.pre_edit_text.take(); drop(state); - window.handle_ime_delete(); + window.handle_ime(ImeInput::DeleteText); window.set_focused(false); } } @@ -916,7 +916,7 @@ impl Dispatch for WaylandClientStatePtr { let pre_edit = state.pre_edit_text.clone().unwrap_or(String::default()); drop(state); - focused_window.handle_ime_preedit(pre_edit); + focused_window.handle_ime(ImeInput::SetMarkedText(pre_edit)); state = client.borrow_mut(); } @@ -929,12 +929,13 @@ impl Dispatch for WaylandClientStatePtr { let pre_edit = state.pre_edit_text.take(); drop(state); if let Some(pre_edit) = pre_edit { - focused_window.handle_ime_commit(pre_edit); + focused_window.handle_ime(ImeInput::InsertText(pre_edit)); } if let Some(current_key) = Keystroke::underlying_dead_key(keysym) { - focused_window.handle_ime_preedit(current_key); + focused_window + .handle_ime(ImeInput::SetMarkedText(current_key)); } compose.feed(keysym); state = client.borrow_mut(); @@ -1041,7 +1042,7 @@ impl Dispatch for WaylandClientStatePtr { if let Some(commit_text) = text { drop(state); - window.handle_ime_commit(commit_text); + window.handle_ime(ImeInput::InsertText(commit_text)); } } zwp_text_input_v3::Event::PreeditString { @@ -1060,7 +1061,7 @@ impl Dispatch for WaylandClientStatePtr { if let Some(text) = state.pre_edit_text.take() { drop(state); - window.handle_ime_preedit(text); + window.handle_ime(ImeInput::SetMarkedText(text)); if let Some(area) = window.get_ime_area() { text_input.set_cursor_rectangle( area.origin.x.0 as i32, @@ -1074,7 +1075,7 @@ impl Dispatch for WaylandClientStatePtr { } } else { drop(state); - window.handle_ime_delete(); + window.handle_ime(ImeInput::DeleteText); } } _ => {} @@ -1200,14 +1201,14 @@ impl Dispatch for WaylandClientStatePtr { } match button_state { wl_pointer::ButtonState::Pressed => { - if let (Some(window), Some(pre_edit), Some(compose_state)) = ( + if let (Some(window), Some(text), Some(compose_state)) = ( state.keyboard_focused_window.clone(), state.pre_edit_text.take(), state.compose_state.as_mut(), ) { compose_state.reset(); drop(state); - window.handle_ime_commit(pre_edit); + window.handle_ime(ImeInput::InsertText(text)); state = client.borrow_mut(); } let click_elapsed = state.click.last_click.elapsed(); diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 0ba6f50ebc9a..0925c2a9f253 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -2,6 +2,7 @@ use std::any::Any; use std::cell::{Ref, RefCell, RefMut}; use std::ffi::c_void; use std::num::NonZeroU32; +use std::ops::Range; use std::ptr::NonNull; use std::rc::{Rc, Weak}; use std::sync::Arc; @@ -159,6 +160,11 @@ impl WaylandWindowState { } pub(crate) struct WaylandWindow(pub WaylandWindowStatePtr); +pub enum ImeInput { + InsertText(String), + SetMarkedText(String), + DeleteText, +} impl Drop for WaylandWindow { fn drop(&mut self) { @@ -417,31 +423,23 @@ impl WaylandWindowStatePtr { } } - pub fn handle_ime_commit(&self, text: String) { - let mut state = self.state.borrow_mut(); - if let Some(mut input_handler) = state.input_handler.take() { - drop(state); - input_handler.replace_text_in_range(None, &text); - self.state.borrow_mut().input_handler = Some(input_handler); - } - } - - pub fn handle_ime_preedit(&self, text: String) { - let mut state = self.state.borrow_mut(); - if let Some(mut input_handler) = state.input_handler.take() { - drop(state); - input_handler.replace_and_mark_text_in_range(None, &text, None); - self.state.borrow_mut().input_handler = Some(input_handler); - } - } - - pub fn handle_ime_delete(&self) { + pub fn handle_ime(&self, ime: ImeInput) { let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { drop(state); - if let Some(marked) = input_handler.marked_text_range() { - input_handler.replace_text_in_range(Some(marked), ""); - }; + match ime { + ImeInput::InsertText(text) => { + input_handler.replace_text_in_range(None, &text); + } + ImeInput::SetMarkedText(text) => { + input_handler.replace_and_mark_text_in_range(None, &text, None); + } + ImeInput::DeleteText => { + if let Some(marked) = input_handler.marked_text_range() { + input_handler.replace_text_in_range(Some(marked), ""); + } + } + } self.state.borrow_mut().input_handler = Some(input_handler); } }