Skip to content

Commit

Permalink
wayland: add missing keyboard input support. The only thing I didn't
Browse files Browse the repository at this point in the history
like was using the static global EVENTS to communicate with the
handlers. Unfortunately, I'm not able to store the event handler in
display, and cannot pass it as data since it happens where the seat is
attached.
  • Loading branch information
xxxxxxxxxxxxx authored and not-fl3 committed Jul 19, 2023
1 parent 604f9ac commit ec43ac1
Show file tree
Hide file tree
Showing 3 changed files with 313 additions and 19 deletions.
129 changes: 110 additions & 19 deletions src/native/linux_wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,30 @@

mod libwayland_client;
mod libwayland_egl;
mod libxkbcommon;

mod decorations;
mod extensions;
mod keycodes;
mod shm;

use libwayland_client::*;
use libwayland_egl::*;
use libxkbcommon::*;

use crate::{
event::EventHandler,
event::{EventHandler, KeyCode, KeyMods},
native::{egl, NativeDisplayData},
};

use std::collections::HashSet;

pub struct WaylandDisplay {
client: LibWaylandClient,
// this is libwayland-egl.so, a library with ~4 functions
// not the libEGL.so(which will be loaded, but not here)
egl: LibWaylandEgl,
xkb: LibXkbCommon,
compositor: *mut wl_compositor,
subcompositor: *mut wl_subcompositor,
xdg_toplevel: *mut extensions::xdg_shell::xdg_toplevel,
Expand All @@ -29,6 +35,9 @@ pub struct WaylandDisplay {
viewporter: *mut extensions::viewporter::wp_viewporter,
shm: *mut wl_shm,
seat: *mut wl_seat,
xkb_context: *mut xkb_context,
keymap: *mut xkb_keymap,
xkb_state: *mut xkb_state,

egl_window: *mut wl_egl_window,
pointer: *mut wl_pointer,
Expand Down Expand Up @@ -174,14 +183,16 @@ unsafe extern "C" fn seat_handle_capabilities(
);
assert!(!id.is_null());
// wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
(display.client.wl_proxy_add_listener)(
id,
&KEYBOARD_LISTENER as *const _ as _,
data,
);
(display.client.wl_proxy_add_listener)(id, &KEYBOARD_LISTENER as *const _ as _, data);
}
}

enum WaylandEvent {
KeyboardKey(KeyCode, bool),
}

static mut EVENTS: Vec<WaylandEvent> = Vec::new();

static mut KEYBOARD_LISTENER: wl_keyboard_listener = wl_keyboard_listener {
keymap: Some(keyboard_handle_keymap),
enter: Some(keyboard_handle_enter),
Expand All @@ -192,12 +203,33 @@ static mut KEYBOARD_LISTENER: wl_keyboard_listener = wl_keyboard_listener {
};

unsafe extern "C" fn keyboard_handle_keymap(
_data: *mut ::std::os::raw::c_void,
data: *mut ::std::os::raw::c_void,
_wl_keyboard: *mut wl_keyboard,
_format: u32,
_fd: i32,
_size: u32,
fd: i32,
size: u32,
) {
let display: &mut WaylandDisplay = &mut *(data as *mut _);
let map_shm = libc::mmap(
std::ptr::null_mut::<std::ffi::c_void>(),
size as usize,
libc::PROT_READ,
libc::MAP_PRIVATE,
fd,
0,
);
assert!(map_shm != libc::MAP_FAILED);
(display.xkb.xkb_keymap_unref)(display.keymap);
display.keymap = (display.xkb.xkb_keymap_new_from_string)(
display.xkb_context,
map_shm as *mut libc::FILE,
1,
0,
);
libc::munmap(map_shm, size as usize);
libc::close(fd);
(display.xkb.xkb_state_unref)(display.xkb_state);
display.xkb_state = (display.xkb.xkb_state_new)(display.keymap);
}
unsafe extern "C" fn keyboard_handle_enter(
_data: *mut ::std::os::raw::c_void,
Expand All @@ -215,23 +247,39 @@ unsafe extern "C" fn keyboard_handle_leave(
) {
}
unsafe extern "C" fn keyboard_handle_key(
_data: *mut ::std::os::raw::c_void,
data: *mut ::std::os::raw::c_void,
_wl_keyboard: *mut wl_keyboard,
_serial: u32,
_time: u32,
_key: u32,
_state: u32,
serial: u32,

Check warning on line 252 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, x86_64-unknown-linux-gnu)

unused variable: `serial`

Check warning on line 252 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, armv7-unknown-linux-gnueabihf)

unused variable: `serial`

Check warning on line 252 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, aarch64-unknown-linux-gnu)

unused variable: `serial`
time: u32,

Check warning on line 253 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, x86_64-unknown-linux-gnu)

unused variable: `time`

Check warning on line 253 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, armv7-unknown-linux-gnueabihf)

unused variable: `time`

Check warning on line 253 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, aarch64-unknown-linux-gnu)

unused variable: `time`
key: u32,
state: u32,
) {
let display: &mut WaylandDisplay = &mut *(data as *mut _);
// https://wayland-book.com/seat/keyboard.html
// To translate this to an XKB scancode, you must add 8 to the evdev scancode.
let keysym = (display.xkb.xkb_state_key_get_one_sym)(display.xkb_state, key + 8);
let keycode = keycodes::translate(keysym);
EVENTS.push(WaylandEvent::KeyboardKey(keycode, state == 1));
}
unsafe extern "C" fn keyboard_handle_modifiers(
_data: *mut ::std::os::raw::c_void,
data: *mut ::std::os::raw::c_void,
_wl_keyboard: *mut wl_keyboard,
_serial: u32,
_mods_depressed: u32,
_mods_latched: u32,
_mods_locked: u32,
_group: u32,
mods_depressed: u32,
mods_latched: u32,
mods_locked: u32,
group: u32,
) {
let display: &mut WaylandDisplay = &mut *(data as *mut _);
(display.xkb.xkb_state_update_mask)(
display.xkb_state,
mods_depressed,
mods_latched,
mods_locked,
0,
0,
group,
);
}
unsafe extern "C" fn keyboard_handle_repeat_info(
_data: *mut ::std::os::raw::c_void,
Expand Down Expand Up @@ -408,6 +456,7 @@ where
unsafe {
let client = LibWaylandClient::try_load()?;
let egl = LibWaylandEgl::try_load()?;
let xkb = LibXkbCommon::try_load()?;

let wdisplay = (client.wl_display_connect)(std::ptr::null_mut());
if wdisplay.is_null() {
Expand All @@ -428,9 +477,12 @@ where
global_remove: Some(registry_remove_object),
};

let xkb_context = (xkb.xkb_context_new)(0);

let mut display = WaylandDisplay {
client: client.clone(),
egl,
xkb,
compositor: std::ptr::null_mut(),
subcompositor: std::ptr::null_mut(),
xdg_toplevel: std::ptr::null_mut(),
Expand All @@ -440,6 +492,9 @@ where
viewporter: std::ptr::null_mut(),
shm: std::ptr::null_mut(),
seat: std::ptr::null_mut(),
xkb_context,
keymap: std::ptr::null_mut(),
xkb_state: std::ptr::null_mut(),
egl_window: std::ptr::null_mut(),
pointer: std::ptr::null_mut(),
keyboard: std::ptr::null_mut(),
Expand All @@ -460,6 +515,8 @@ where
assert!(display.xdg_wm_base.is_null() == false);
assert!(display.subcompositor.is_null() == false);
assert!(display.seat.is_null() == false);
//assert!(display.keymap.is_null() == false);
//assert!(display.xkb_state.is_null() == false);

if display.decoration_manager.is_null() && conf.platform.wayland_use_fallback_decorations {
eprintln!("Decoration manager not found, will draw fallback decorations");
Expand Down Expand Up @@ -584,10 +641,44 @@ where
let event_handler = (f.take().unwrap())();
payload.event_handler = Some(event_handler);

let mut keymods = KeyMods {
shift: false,
ctrl: false,
alt: false,
logo: false,
};
let mut repeated_keys: HashSet<KeyCode> = HashSet::new();

while tl_display::with(|d| d.closed == false) {
(client.wl_display_dispatch_pending)(wdisplay);

if let Some(ref mut event_handler) = payload.event_handler {
for keycode in &repeated_keys {
event_handler.key_down_event(keycode.clone(), keymods, true);
}

for event in EVENTS.drain(..) {
match event {
WaylandEvent::KeyboardKey(keycode, state) => {
match keycode {
KeyCode::LeftShift | KeyCode::RightShift => keymods.shift = state,
KeyCode::LeftControl | KeyCode::RightControl => keymods.ctrl = state,
KeyCode::LeftAlt | KeyCode::RightAlt => keymods.alt = state,
KeyCode::LeftSuper | KeyCode::RightSuper => keymods.logo = state,
_ => {}
}

if state {
event_handler.key_down_event(keycode, keymods, false);
repeated_keys.insert(keycode);
} else {
event_handler.key_up_event(keycode, keymods);
repeated_keys.remove(&keycode);
}
}
}
}

event_handler.update();
event_handler.draw();
}
Expand Down
126 changes: 126 additions & 0 deletions src/native/linux_wayland/keycodes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use crate::event::KeyCode;

pub fn translate(keysym: u32) -> KeyCode {
match keysym {
65307 => return KeyCode::Escape,
65289 => return KeyCode::Tab,
65505 => return KeyCode::LeftShift,
65506 => return KeyCode::RightShift,
65507 => return KeyCode::LeftControl,
65508 => return KeyCode::RightControl,
65511 | 65513 => return KeyCode::LeftAlt,
65406 | 65027 | 65512 | 65514 => return KeyCode::RightAlt,
65515 => return KeyCode::LeftSuper,
65516 => return KeyCode::RightSuper,
65383 => return KeyCode::Menu,
65407 => return KeyCode::NumLock,
65509 => return KeyCode::CapsLock,
65377 => return KeyCode::PrintScreen,
65300 => return KeyCode::ScrollLock,
65299 => return KeyCode::Pause,
65535 => return KeyCode::Delete,
65288 => return KeyCode::Backspace,
65293 => return KeyCode::Enter,
65360 => return KeyCode::Home,
65367 => return KeyCode::End,
65365 => return KeyCode::PageUp,
65366 => return KeyCode::PageDown,
65379 => return KeyCode::Insert,
65361 => return KeyCode::Left,
65363 => return KeyCode::Right,
65364 => return KeyCode::Down,
65362 => return KeyCode::Up,
65470 => return KeyCode::F1,
65471 => return KeyCode::F2,
65472 => return KeyCode::F3,
65473 => return KeyCode::F4,
65474 => return KeyCode::F5,
65475 => return KeyCode::F6,
65476 => return KeyCode::F7,
65477 => return KeyCode::F8,
65478 => return KeyCode::F9,
65479 => return KeyCode::F10,
65480 => return KeyCode::F11,
65481 => return KeyCode::F12,
65482 => return KeyCode::F13,
65483 => return KeyCode::F14,
65484 => return KeyCode::F15,
65485 => return KeyCode::F16,
65486 => return KeyCode::F17,
65487 => return KeyCode::F18,
65488 => return KeyCode::F19,
65489 => return KeyCode::F20,
65490 => return KeyCode::F21,
65491 => return KeyCode::F22,
65492 => return KeyCode::F23,
65493 => return KeyCode::F24,
65494 => return KeyCode::F25,
65455 => return KeyCode::KpDivide,
65450 => return KeyCode::KpMultiply,
65453 => return KeyCode::KpSubtract,
65451 => return KeyCode::KpAdd,
65438 => return KeyCode::Kp0,
65436 => return KeyCode::Kp1,
65433 => return KeyCode::Kp2,
65435 => return KeyCode::Kp3,
65430 => return KeyCode::Kp4,
65437 => return KeyCode::Kp5,
65432 => return KeyCode::Kp6,
65429 => return KeyCode::Kp7,
65431 => return KeyCode::Kp8,
65434 => return KeyCode::Kp9,
65439 => return KeyCode::KpDecimal,
65469 => return KeyCode::KpEqual,
65421 => return KeyCode::KpEnter,
97 => return KeyCode::A,
98 => return KeyCode::B,
99 => return KeyCode::C,
100 => return KeyCode::D,
101 => return KeyCode::E,
102 => return KeyCode::F,
103 => return KeyCode::G,
104 => return KeyCode::H,
105 => return KeyCode::I,
106 => return KeyCode::J,
107 => return KeyCode::K,
108 => return KeyCode::L,
109 => return KeyCode::M,
110 => return KeyCode::N,
111 => return KeyCode::O,
112 => return KeyCode::P,
113 => return KeyCode::Q,
114 => return KeyCode::R,
115 => return KeyCode::S,
116 => return KeyCode::T,
117 => return KeyCode::U,
118 => return KeyCode::V,
119 => return KeyCode::W,
120 => return KeyCode::X,
121 => return KeyCode::Y,
122 => return KeyCode::Z,
49 => return KeyCode::Key1,
50 => return KeyCode::Key2,
51 => return KeyCode::Key3,
52 => return KeyCode::Key4,
53 => return KeyCode::Key5,
54 => return KeyCode::Key6,
55 => return KeyCode::Key7,
56 => return KeyCode::Key8,
57 => return KeyCode::Key9,
48 => return KeyCode::Key0,
32 => return KeyCode::Space,
45 => return KeyCode::Minus,
61 => return KeyCode::Equal,
91 => return KeyCode::LeftBracket,
93 => return KeyCode::RightBracket,
92 => return KeyCode::Backslash,
59 => return KeyCode::Semicolon,
39 => return KeyCode::Apostrophe,
96 => return KeyCode::GraveAccent,
44 => return KeyCode::Comma,
46 => return KeyCode::Period,
47 => return KeyCode::Slash,
60 => return KeyCode::World1,
_ => return KeyCode::Unknown,
};
}
Loading

0 comments on commit ec43ac1

Please sign in to comment.