From cd640a87a9b0b4787c7a1a94667fa25c13df93b7 Mon Sep 17 00:00:00 2001 From: gmorenz Date: Tue, 20 Feb 2024 19:04:52 -0500 Subject: [PATCH] Improve key handling on x11, sharing wayland implementation (#8094) Makes keyboard shortcuts work on x11. Release Notes: - N/A --- crates/gpui/src/platform/linux.rs | 1 + crates/gpui/src/platform/linux/util.rs | 28 ++++++++++++++ .../gpui/src/platform/linux/wayland/client.rs | 37 ++++++------------- crates/gpui/src/platform/linux/x11/client.rs | 28 +++++--------- crates/gpui/src/platform/linux/x11/window.rs | 4 +- 5 files changed, 53 insertions(+), 45 deletions(-) create mode 100644 crates/gpui/src/platform/linux/util.rs diff --git a/crates/gpui/src/platform/linux.rs b/crates/gpui/src/platform/linux.rs index f8d398587d..be908eb0b9 100644 --- a/crates/gpui/src/platform/linux.rs +++ b/crates/gpui/src/platform/linux.rs @@ -3,6 +3,7 @@ mod client_dispatcher; mod dispatcher; mod platform; mod text_system; +mod util; mod wayland; mod x11; diff --git a/crates/gpui/src/platform/linux/util.rs b/crates/gpui/src/platform/linux/util.rs new file mode 100644 index 0000000000..6791ffee36 --- /dev/null +++ b/crates/gpui/src/platform/linux/util.rs @@ -0,0 +1,28 @@ +use xkbcommon::xkb::{self, Keycode, Keysym, State}; + +use crate::{Keystroke, Modifiers}; + +impl Keystroke { + pub(super) fn from_xkb(state: &State, modifiers: Modifiers, keycode: Keycode) -> Self { + let key_utf32 = state.key_get_utf32(keycode); + let key_utf8 = state.key_get_utf8(keycode); + let key_sym = state.key_get_one_sym(keycode); + + let key = match key_sym { + Keysym::Return => "enter".to_owned(), + Keysym::Prior => "pageup".to_owned(), + Keysym::Next => "pagedown".to_owned(), + _ => xkb::keysym_get_name(key_sym).to_lowercase(), + }; + + // 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); + + Keystroke { + modifiers, + key, + ime_key, + } + } +} diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 20cea45843..1579a5098b 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -24,8 +24,7 @@ use wayland_protocols::xdg::decoration::zv1::client::{ }; use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base}; use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1; -use xkbcommon::xkb::{self, Keysym}; -use xkbcommon::xkb::{Keycode, KEYMAP_COMPILE_NO_FLAGS}; +use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS}; use crate::platform::linux::client::Client; use crate::platform::linux::wayland::window::{WaylandDecorationState, WaylandWindow}; @@ -453,41 +452,27 @@ impl Dispatch for WaylandClientState { } => { let keymap_state = state.keymap_state.as_ref().unwrap(); 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 = match key_sym { - Keysym::Return => "enter".to_owned(), - Keysym::Prior => "pageup".to_owned(), - Keysym::Next => "pagedown".to_owned(), - _ => xkb::keysym_get_name(key_sym).to_lowercase(), - }; - - // 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 => { focused_window.handle_input(PlatformInput::KeyDown(KeyDownEvent { - keystroke: Keystroke { - modifiers: state.modifiers, - key, - ime_key, - }, + keystroke: Keystroke::from_xkb( + keymap_state, + state.modifiers, + keycode, + ), is_held: false, // todo!(linux) })); } wl_keyboard::KeyState::Released => { focused_window.handle_input(PlatformInput::KeyUp(KeyUpEvent { - keystroke: Keystroke { - modifiers: state.modifiers, - key, - ime_key, - }, + keystroke: Keystroke::from_xkb( + keymap_state, + state.modifiers, + keycode, + ), })); } _ => {} diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 6243851dc7..1428654d8d 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -118,39 +118,31 @@ impl Client for X11Client { xcb::Event::X(x::Event::KeyPress(ev)) => { let window = self.get_window(ev.event()); let modifiers = super::modifiers_from_state(ev.state()); - let key = { + let keystroke = { let code = ev.detail().into(); let mut state = self.state.lock(); - let key = state.xkb.key_get_utf8(code); + let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code); state.xkb.update_key(code, xkb::KeyDirection::Down); - key + keystroke }; + window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent { - keystroke: crate::Keystroke { - modifiers, - key, - ime_key: None, - }, + keystroke, is_held: false, })); } xcb::Event::X(x::Event::KeyRelease(ev)) => { let window = self.get_window(ev.event()); let modifiers = super::modifiers_from_state(ev.state()); - let key = { + let keystroke = { let code = ev.detail().into(); let mut state = self.state.lock(); - let key = state.xkb.key_get_utf8(code); + let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code); state.xkb.update_key(code, xkb::KeyDirection::Up); - key + keystroke }; - window.handle_input(PlatformInput::KeyUp(crate::KeyUpEvent { - keystroke: crate::Keystroke { - modifiers, - key, - ime_key: None, - }, - })); + + window.handle_input(PlatformInput::KeyUp(crate::KeyUpEvent { keystroke })); } xcb::Event::X(x::Event::ButtonPress(ev)) => { let window = self.get_window(ev.event()); diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index b511099af5..e4293d7b9d 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -338,7 +338,9 @@ impl X11WindowState { 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); + } } } }