Skip to content

Commit

Permalink
chore: impl xkb base
Browse files Browse the repository at this point in the history
  • Loading branch information
Decodetalkers committed Jul 21, 2024
1 parent d7f8271 commit d912259
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 6 deletions.
4 changes: 4 additions & 0 deletions iced_layershell/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ tracing = "0.1.40"
thiserror = "1.0.56"
layershellev.workspace = true
futures = "0.3.30"

memmap2 = "0.9.4"
once_cell = "1.19.0"
xkbcommon-dl = "0.4.2"
4 changes: 4 additions & 0 deletions layershellev/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ rwh_06.workspace = true
bitflags.workspace = true

sctk.workspace = true

memmap2 = "0.9.4"
once_cell = "1.19.0"
xkbcommon-dl = "0.4.2"
125 changes: 125 additions & 0 deletions layershellev/src/keyboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use std::{ffi::c_char, ops::Deref, os::fd::OwnedFd, ptr::NonNull};

use memmap2::MmapOptions;
use once_cell::sync::Lazy;

use xkbcommon_dl::{self as xkb, xkbcommon_handle, XkbCommon};

use xkb::{
xkb_context, xkb_context_flags, xkb_keymap, xkb_keymap_compile_flags, xkb_state,
xkb_state_component,
};

static XKBH: Lazy<&'static XkbCommon> = Lazy::new(xkbcommon_handle);

#[derive(Debug)]
pub struct XkbKeymap {
keymap: NonNull<xkb_keymap>,
}

impl XkbKeymap {
pub fn from_fd(context: &XkbContext, fd: OwnedFd, size: usize) -> Option<Self> {
let map = MmapOptions::new().len(size).map_raw_read_only(&fd).ok()?;
let keymap = unsafe {
let keymap = (XKBH.xkb_keymap_new_from_string)(
(*context).as_ptr(),
map.as_ptr() as *const _,
xkb::xkb_keymap_format::XKB_KEYMAP_FORMAT_TEXT_V1,
xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS,
);

NonNull::new(keymap)?
};
Some(Self { keymap })
}
}

impl Drop for XkbKeymap {
fn drop(&mut self) {
unsafe { (XKBH.xkb_keymap_unref)(self.keymap.as_ptr()) }
}
}

impl Deref for XkbKeymap {
type Target = NonNull<xkb_keymap>;
fn deref(&self) -> &Self::Target {
&self.keymap
}
}

#[derive(Debug)]
pub struct XkbContext {
context: NonNull<xkb_context>,
}

impl Drop for XkbContext {
fn drop(&mut self) {
unsafe { (XKBH.xkb_context_unref)(self.context.as_ptr()) }
}
}

impl Deref for XkbContext {
type Target = NonNull<xkb_context>;
fn deref(&self) -> &Self::Target {
&self.context
}
}

impl XkbContext {
pub fn new() -> Self {
let context = unsafe { (XKBH.xkb_context_new)(xkb_context_flags::XKB_CONTEXT_NO_FLAGS) };
let context = NonNull::new(context).unwrap();
Self { context }
}
}

#[derive(Debug)]
pub struct XkbState {
state: NonNull<xkb_state>,
modifiers: ModifiersState,
}

impl XkbState {
pub fn new_wayland(keymap: &XkbKeymap) -> Option<Self> {
let state = NonNull::new(unsafe { (XKBH.xkb_state_new)(keymap.as_ptr()) })?;
Some(Self::new_inner(state))
}

fn new_inner(state: NonNull<xkb_state>) -> Self {
let modifiers = ModifiersState::default();
let mut this = Self { state, modifiers };
this.reload_modifiers();
this
}
// NOTE: read here
/// Check if the modifier is active within xkb.
fn mod_name_is_active(&mut self, name: &[u8]) -> bool {
unsafe {
(XKBH.xkb_state_mod_name_is_active)(
self.state.as_ptr(),
name.as_ptr() as *const c_char,
xkb_state_component::XKB_STATE_MODS_EFFECTIVE,
) > 0
}
}
fn reload_modifiers(&mut self) {
self.modifiers.ctrl = self.mod_name_is_active(xkb::XKB_MOD_NAME_CTRL);
self.modifiers.alt = self.mod_name_is_active(xkb::XKB_MOD_NAME_ALT);
self.modifiers.shift = self.mod_name_is_active(xkb::XKB_MOD_NAME_SHIFT);
self.modifiers.caps_lock = self.mod_name_is_active(xkb::XKB_MOD_NAME_CAPS);
println!("caps: {}", self.modifiers.caps_lock);
self.modifiers.logo = self.mod_name_is_active(xkb::XKB_MOD_NAME_LOGO);
self.modifiers.num_lock = self.mod_name_is_active(xkb::XKB_MOD_NAME_NUM);
}
}

#[derive(Debug, Default)]
pub struct ModifiersState {
ctrl: bool,
alt: bool,
shift: bool,
caps_lock: bool,
logo: bool,
num_lock: bool,
}

22 changes: 16 additions & 6 deletions layershellev/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
//!
mod events;
mod keyboard;
mod strtoshape;

use std::fmt::Debug;
Expand All @@ -181,7 +182,7 @@ use wayland_client::{
wl_buffer::WlBuffer,
wl_compositor::WlCompositor,
wl_display::WlDisplay,
wl_keyboard::{self, WlKeyboard},
wl_keyboard::{self, KeymapFormat, WlKeyboard},
wl_output::{self, WlOutput},
wl_pointer::{self, WlPointer},
wl_registry,
Expand Down Expand Up @@ -823,9 +824,20 @@ impl<T: Debug> Dispatch<wl_keyboard::WlKeyboard, ()> for WindowState<T> {
event: <wl_keyboard::WlKeyboard as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &wayland_client::QueueHandle<Self>,
_qhandle: &QueueHandle<Self>,
) {
use keyboard::*;
match event {
wl_keyboard::Event::Keymap { format, fd, size } => {
if !matches!(format, WEnum::Value(KeymapFormat::XkbV1)) {
return;
}
println!("it is {format:?}, {fd:?}, {size}");
let context = XkbContext::new();
let keymap = XkbKeymap::from_fd(&context, fd, size as usize).unwrap();
let state = XkbState::new_wayland(&keymap).unwrap();
println!("{state:?}");
}
wl_keyboard::Event::Key {
state: keystate,
serial,
Expand Down Expand Up @@ -1641,11 +1653,9 @@ impl<T: Debug + 'static> WindowState<T> {

WaylandSource::new(connection.clone(), event_queue)
.insert(event_loop.handle())
.unwrap();
.expect("Failed to init wayland source");
'out: loop {
event_loop
.dispatch(Duration::from_millis(1), &mut self)
.unwrap();
event_loop.dispatch(Duration::from_millis(1), &mut self)?;

let mut messages = Vec::new();
std::mem::swap(&mut messages, &mut self.message);
Expand Down

0 comments on commit d912259

Please sign in to comment.