From 2b56c43f2d2172d0a8dcaadd9096280eaa7d2de7 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sun, 18 Feb 2024 22:25:42 -0700 Subject: [PATCH] Wayland: Keyboard input improvements (#7989) Release Notes: - N/A --- Right now the Wayland backend is using `xkb::State::key_get_utf8` as the `key`, when it should be used as the `ime_key`. It also manages pressing/releasing modifiers manually when this should be managed by the display server. This allows modifier combinations to work in more cases, making it an alternative to https://github.com/zed-industries/zed/pull/7975, which interprets what is now only used as the `ime_key` value as a `key` value. --- .../gpui/src/platform/linux/wayland/client.rs | 114 ++++++------------ .../gpui/src/platform/linux/wayland/window.rs | 8 +- 2 files changed, 41 insertions(+), 81 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 0f739af76d..0a20dfd871 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -27,7 +27,6 @@ use xkbcommon::xkb::{Keycode, KEYMAP_COMPILE_NO_FLAGS}; use crate::platform::linux::client::Client; use crate::platform::linux::wayland::window::WaylandWindow; use crate::platform::{LinuxPlatformInner, PlatformWindow}; -use crate::PlatformInput::KeyDown; use crate::ScrollDelta; use crate::{ platform::linux::wayland::window::WaylandWindowState, AnyWindowHandle, DisplayId, KeyDownEvent, @@ -394,14 +393,16 @@ impl Dispatch for WaylandClientState { group, .. } => { - state.keymap_state.as_mut().unwrap().update_mask( - mods_depressed, - mods_latched, - mods_locked, - 0, - 0, - group, - ); + let keymap_state = state.keymap_state.as_mut().unwrap(); + keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group); + state.modifiers.shift = + keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE); + state.modifiers.alt = + keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE); + state.modifiers.control = + keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE); + state.modifiers.command = + keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE); } wl_keyboard::Event::Key { key, @@ -409,81 +410,44 @@ impl Dispatch for WaylandClientState { .. } => { let keymap_state = state.keymap_state.as_ref().unwrap(); - let key_utf8 = keymap_state.key_get_utf8(Keycode::from(key + MIN_KEYCODE)); - let key_sym = keymap_state.key_get_one_sym(Keycode::from(key + MIN_KEYCODE)); + let keycode = Keycode::from(key + MIN_KEYCODE); + let key_utf32 = keymap_state.key_get_utf32(keycode); + let key_utf8 = keymap_state.key_get_utf8(keycode); + let key_sym = keymap_state.key_get_one_sym(keycode); + let key = xkb::keysym_get_name(key_sym).to_lowercase(); - let key = if matches!( - key_sym, - xkb::Keysym::BackSpace - | xkb::Keysym::Left - | xkb::Keysym::Right - | xkb::Keysym::Down - | xkb::Keysym::Up - | xkb::Keysym::Super_L - | xkb::Keysym::Super_R - ) { - xkb::keysym_get_name(key_sym).to_lowercase() - } else { - key_utf8.clone() - }; + // Ignore control characters (and DEL) for the purposes of ime_key, + // but if key_utf32 is 0 then assume it isn't one + let ime_key = + (key_utf32 == 0 || (key_utf32 >= 32 && key_utf32 != 127)).then_some(key_utf8); let focused_window = &state.keyboard_focused_window; if let Some(focused_window) = focused_window { match key_state { wl_keyboard::KeyState::Pressed => { - if key_sym == xkb::Keysym::Shift_L || key_sym == xkb::Keysym::Shift_R { - state.modifiers.shift = true; - } else if key_sym == xkb::Keysym::Control_L - || key_sym == xkb::Keysym::Control_R - { - state.modifiers.control = true; - } else if key_sym == xkb::Keysym::Alt_L || key_sym == xkb::Keysym::Alt_R - { - state.modifiers.alt = true; - } else { - focused_window.handle_input(KeyDown(KeyDownEvent { - keystroke: Keystroke { - modifiers: state.modifiers, - key, - ime_key: None, - }, - is_held: false, // todo!(linux) - })); - } + focused_window.handle_input(PlatformInput::KeyDown(KeyDownEvent { + keystroke: Keystroke { + modifiers: state.modifiers, + key, + ime_key, + }, + is_held: false, // todo!(linux) + })); } wl_keyboard::KeyState::Released => { - if key_sym == xkb::Keysym::Shift_L || key_sym == xkb::Keysym::Shift_R { - state.modifiers.shift = false; - } else if key_sym == xkb::Keysym::Control_L - || key_sym == xkb::Keysym::Control_R - { - state.modifiers.control = false; - } else if key_sym == xkb::Keysym::Alt_L || key_sym == xkb::Keysym::Alt_R - { - state.modifiers.alt = false; - } else { - focused_window.handle_input(PlatformInput::KeyUp(KeyUpEvent { - keystroke: Keystroke { - modifiers: state.modifiers, - key, - ime_key: None, - }, - })); - } + focused_window.handle_input(PlatformInput::KeyUp(KeyUpEvent { + keystroke: Keystroke { + modifiers: state.modifiers, + key, + ime_key, + }, + })); } _ => {} } } } - wl_keyboard::Event::Leave { .. } => { - state.modifiers = Modifiers { - control: false, - alt: false, - shift: false, - command: false, - function: false, - }; - } + wl_keyboard::Event::Leave { .. } => {} _ => {} } } @@ -568,13 +532,7 @@ impl Dispatch for WaylandClientState { focused_window.handle_input(PlatformInput::MouseUp(MouseUpEvent { button: linux_button_to_gpui(button), position: *mouse_location, - modifiers: Modifiers { - shift: false, - control: false, - alt: false, - function: false, - command: false, - }, + modifiers: Modifiers::default(), click_count: 1, })); } diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 3ebce8f21b..6cc8d2015e 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -71,8 +71,8 @@ impl WaylandWindowInner { bounds: Bounds, ) -> Self { let raw = RawWindow { - window: wl_surf.id().as_ptr() as *mut _, - display: conn.backend().display_ptr() as *mut _, + window: wl_surf.id().as_ptr().cast::(), + display: conn.backend().display_ptr().cast::(), }; let gpu = Arc::new( unsafe { @@ -204,7 +204,9 @@ impl WaylandWindowState { if let PlatformInput::KeyDown(event) = input { let mut inner = self.inner.lock(); if let Some(ref mut input_handler) = inner.input_handler { - input_handler.replace_text_in_range(None, &event.keystroke.key); + if let Some(ime_key) = &event.keystroke.ime_key { + input_handler.replace_text_in_range(None, ime_key); + } } } }