Linux/x11 input handling (#7811)

Implements the basics of keyboard and mouse handling.
Some keys will need special treatment, like Backspace/Delete. In this
PR, all keys are treated as append-only. Leaving this for a follow-up.

I used @gabydd 's branch as a reference (thank you!) as well as
https://github.com/xkbcommon/libxkbcommon/blob/master/doc/quick-guide.md
For future work, I'll also use
https://github.com/xkbcommon/libxkbcommon/blob/master/tools/interactive-x11.c

All commits are separately compileable and reviewable.

Release Notes:
- N/A

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
Dzmitry Malyshau 2024-02-15 11:58:47 -08:00 committed by GitHub
parent aa319ccfd0
commit a41fb29e01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 253 additions and 53 deletions

View file

@ -13,15 +13,12 @@ use std::{
use blade_graphics as gpu;
use parking_lot::Mutex;
use raw_window_handle as rwh;
use xcb::{
x::{self, StackMode},
Xid as _,
};
use xcb::{x, Xid as _};
use crate::platform::linux::blade_renderer::BladeRenderer;
use crate::{
Bounds, GlobalPixels, Pixels, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
Size, WindowAppearance, WindowBounds, WindowOptions, X11Display,
Bounds, GlobalPixels, Pixels, PlatformDisplay, PlatformInput, PlatformInputHandler,
PlatformWindow, Point, Size, WindowAppearance, WindowBounds, WindowOptions, X11Display,
};
#[derive(Default)]
@ -52,6 +49,7 @@ struct LinuxWindowInner {
bounds: Bounds<i32>,
scale_factor: f32,
renderer: BladeRenderer,
input_handler: Option<PlatformInputHandler>,
}
impl LinuxWindowInner {
@ -152,7 +150,19 @@ impl X11WindowState {
let xcb_values = [
x::Cw::BackPixel(screen.white_pixel()),
x::Cw::EventMask(
x::EventMask::EXPOSURE | x::EventMask::STRUCTURE_NOTIFY | x::EventMask::KEY_PRESS,
x::EventMask::EXPOSURE
| x::EventMask::STRUCTURE_NOTIFY
| x::EventMask::KEY_PRESS
| x::EventMask::KEY_RELEASE
| x::EventMask::BUTTON_PRESS
| x::EventMask::BUTTON_RELEASE
| x::EventMask::POINTER_MOTION
| x::EventMask::BUTTON1_MOTION
| x::EventMask::BUTTON2_MOTION
| x::EventMask::BUTTON3_MOTION
| x::EventMask::BUTTON4_MOTION
| x::EventMask::BUTTON5_MOTION
| x::EventMask::BUTTON_MOTION,
),
];
@ -238,7 +248,7 @@ impl X11WindowState {
// Note: this has to be done after the GPU init, or otherwise
// the sizes are immediately invalidated.
let gpu_extent = query_render_extent(&xcb_connection, x_window);
let gpu_extent = query_render_extent(xcb_connection, x_window);
Self {
xcb_connection: Arc::clone(xcb_connection),
@ -250,6 +260,7 @@ impl X11WindowState {
bounds,
scale_factor: 1.0,
renderer: BladeRenderer::new(gpu, gpu_extent),
input_handler: None,
}),
}
}
@ -313,6 +324,20 @@ impl X11WindowState {
})
.unwrap();
}
pub fn handle_input(&self, input: PlatformInput) {
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);
}
}
}
}
impl PlatformWindow for X11Window {
@ -356,12 +381,12 @@ impl PlatformWindow for X11Window {
self
}
//todo!(linux)
fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {}
fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
self.0.inner.lock().input_handler = Some(input_handler);
}
//todo!(linux)
fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
None
self.0.inner.lock().input_handler.take()
}
//todo!(linux)
@ -378,7 +403,7 @@ impl PlatformWindow for X11Window {
fn activate(&self) {
self.0.xcb_connection.send_request(&x::ConfigureWindow {
window: self.0.x_window,
value_list: &[x::ConfigWindow::StackMode(StackMode::Above)],
value_list: &[x::ConfigWindow::StackMode(x::StackMode::Above)],
});
}