Skip to content

Commit

Permalink
x11: basic keyboard input
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Feb 15, 2024
1 parent 54ca332 commit 3f70aa6
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 12 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/gpui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,8 @@ objc = "0.2"

[target.'cfg(target_os = "linux")'.dependencies]
flume = "0.11"

# todo!(linux) - Technically do not use `randr`, but it doesn't compile otherwise
xcb = { version = "1.3", features = ["as-raw-xcb-connection", "present", "randr"] }
xcb = { version = "1.3", features = ["as-raw-xcb-connection", "present", "randr", "xkb"] }
wayland-client= { version = "0.31.2" }
wayland-protocols = { version = "0.31.2", features = ["client"] }
wayland-backend = { version = "0.3.3", features = ["client_system"] }
Expand All @@ -108,3 +107,4 @@ blade-graphics = { git = "https://github.com/kvark/blade", rev = "c4f951a88b3457
blade-macros = { git = "https://github.com/kvark/blade", rev = "c4f951a88b345724cb952e920ad30e39851f7760" }
bytemuck = "1"
cosmic-text = "0.10.0"
xkbcommon = { version = "0.7", features = ["x11"] }
18 changes: 15 additions & 3 deletions crates/gpui/src/platform/linux/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,21 @@ impl LinuxPlatform {
callbacks: Mutex<Callbacks>,
state: Mutex<LinuxPlatformState>,
) -> Self {
let (xcb_connection, x_root_index) =
xcb::Connection::connect_with_extensions(None, &[xcb::Extension::Present], &[])
.unwrap();
let (xcb_connection, x_root_index) = xcb::Connection::connect_with_extensions(
None,
&[xcb::Extension::Present, xcb::Extension::Xkb],
&[],
)
.unwrap();

let xkb_ver = xcb_connection
.wait_for_reply(xcb_connection.send_request(&xcb::xkb::UseExtension {
wanted_major: xcb::xkb::MAJOR_VERSION as u16,
wanted_minor: xcb::xkb::MINOR_VERSION as u16,
}))
.unwrap();
assert!(xkb_ver.supported());

let atoms = XcbAtoms::intern_all(&xcb_connection).unwrap();
let xcb_connection = Arc::new(xcb_connection);
let client_dispatcher: Arc<dyn ClientDispatcher + Send + Sync> =
Expand Down
55 changes: 53 additions & 2 deletions crates/gpui/src/platform/linux/x11/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{rc::Rc, sync::Arc};

use parking_lot::Mutex;
use xcb::{x, Xid as _};
use xkbcommon::xkb;

use collections::HashMap;

Expand All @@ -15,6 +16,7 @@ use crate::{

pub(crate) struct X11ClientState {
pub(crate) windows: HashMap<x::Window, Rc<X11WindowState>>,
xkb: xkbcommon::xkb::State,
}

pub(crate) struct X11Client {
Expand All @@ -32,13 +34,25 @@ impl X11Client {
x_root_index: i32,
atoms: XcbAtoms,
) -> Self {
let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let xkb_device_id = xkb::x11::get_core_keyboard_device_id(&xcb_connection);
let xkb_keymap = xkb::x11::keymap_new_from_device(
&xkb_context,
&xcb_connection,
xkb_device_id,
xkb::KEYMAP_COMPILE_NO_FLAGS,
);
let xkb_state =
xkb::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id);

Self {
platform_inner: inner,
xcb_connection,
x_root_index,
atoms,
state: Mutex::new(X11ClientState {
windows: HashMap::default(),
xkb: xkb_state,
}),
}
}
Expand Down Expand Up @@ -92,6 +106,43 @@ impl Client for X11Client {
window.request_refresh();
}
xcb::Event::Present(xcb::present::Event::IdleNotify(_ev)) => {}
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 code = ev.detail().into();
let mut state = self.state.lock();
let key = state.xkb.key_get_utf8(code);
state.xkb.update_key(code, xkb::KeyDirection::Down);
key
};
window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent {
keystroke: crate::Keystroke {
modifiers,
key,
ime_key: None,
},
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 code = ev.detail().into();
let mut state = self.state.lock();
let key = state.xkb.key_get_utf8(code);
state.xkb.update_key(code, xkb::KeyDirection::Up);
key
};
window.handle_input(PlatformInput::KeyUp(crate::KeyUpEvent {
keystroke: crate::Keystroke {
modifiers,
key,
ime_key: None,
},
}));
}
xcb::Event::X(x::Event::ButtonPress(ev)) => {
let window = self.get_window(ev.event());
let modifiers = super::modifiers_from_state(ev.state());
Expand All @@ -103,7 +154,7 @@ impl Client for X11Client {
position,
modifiers,
click_count: 1,
}))
}));
} else {
log::warn!("Unknown button press: {ev:?}");
}
Expand All @@ -119,7 +170,7 @@ impl Client for X11Client {
position,
modifiers,
click_count: 1,
}))
}));
}
}
_ => {}
Expand Down
16 changes: 11 additions & 5 deletions crates/gpui/src/platform/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ impl X11WindowState {
| x::EventMask::BUTTON3_MOTION
| x::EventMask::BUTTON4_MOTION
| x::EventMask::BUTTON5_MOTION
| x::EventMask::BUTTON_MOTION
| x::EventMask::KEYMAP_STATE,
| x::EventMask::BUTTON_MOTION,
),
];

Expand Down Expand Up @@ -327,9 +326,16 @@ impl X11WindowState {
}

pub fn handle_input(&self, input: PlatformInput) {
let mut callbacks = self.callbacks.lock();
if let Some(ref mut fun) = callbacks.input {
fun(input);
if let Some(ref mut fun) = self.callbacks.lock().input {
if fun(input.clone()) {
return;
}
}
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);
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions script/linux
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ if [[ -n $apt ]]; then
libfontconfig-dev
vulkan-validationlayers*
libwayland-dev
libxkbcommon-x11-dev
)
$maysudo "$apt" install -y "${deps[@]}"
exit 0
Expand All @@ -26,6 +27,7 @@ if [[ -n $dnf ]]; then
fontconfig-devel
vulkan-validation-layers
wayland-devel
libxkbcommon-x11-devel
)
$maysudo "$dnf" install -y "${deps[@]}"
exit 0
Expand All @@ -40,6 +42,7 @@ if [[ -n $pacman ]]; then
fontconfig
vulkan-validation-layers
wayland
libxkbcommon-x11
)
$maysudo "$pacman" -S --needed --noconfirm "${deps[@]}"
exit 0
Expand Down

0 comments on commit 3f70aa6

Please sign in to comment.