From 1efb3f661b81579bedd5223bcf2c7d438ae66b39 Mon Sep 17 00:00:00 2001 From: chlorospingus Date: Sun, 11 May 2025 18:20:15 -0700 Subject: [PATCH] Parse keysyms from xkb config and interpret key in wl_keyboard.key --- src/main.rs | 2 + src/wayland/mod.rs | 1 + src/wayland/seat.rs | 33 ++++++++--- src/wayland/shm.rs | 12 ++++ src/wayland/wl_client.rs | 8 +-- src/wayland/xkb.rs | 115 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 src/wayland/xkb.rs diff --git a/src/main.rs b/src/main.rs index 21fe521..2d670e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,6 @@ #![feature(unix_socket_ancillary_data)] +#![feature(str_from_raw_parts)] + use std::{error::Error, thread, time::Duration}; mod wayland; diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 6d654b5..2f27bc7 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -7,3 +7,4 @@ pub mod vec_utils; pub mod shm; pub mod wl_registry; pub mod seat; +pub mod xkb; diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs index a1c9fb0..a123eb7 100644 --- a/src/wayland/seat.rs +++ b/src/wayland/seat.rs @@ -4,6 +4,8 @@ use std::{error::Error, io::{IoSliceMut, Write}, os::unix::net::{AncillaryData, use crate::wayland::{shm, vec_utils::WlMessage, wl_client::WlClient, surface::UnsetErr}; +use super::xkb; + impl WlClient { pub fn wl_seat_capabilities(&self, event: &Vec) -> Result<(), Box> { @@ -56,23 +58,36 @@ impl WlClient { let format = event.read_u32(&mut offset); let size = event.read_u32(&mut offset); - *self.keymap.lock().unwrap() = Some(shm::ShmPool::from_fd(fd, size as usize)?); + let mut keymap_fd = self.keymap_fd.lock().unwrap(); + *keymap_fd = Some(shm::ShmPool::from_fd(fd, size as usize)?); + let mut keymap = self.keymap.lock().unwrap(); + *keymap = xkb::gen_id_keysym_mapping(keymap_fd.as_ref().unwrap()); Ok(()) } - pub fn wl_keyboard_key(&self, event: &Vec) { + pub fn wl_keyboard_key(&self, event: &Vec) -> Result<(), Box> { let mut offset: usize = 0; let serial = event.read_u32(&mut offset); let time = event.read_u32(&mut offset); let key = event.read_u32(&mut offset); let state = event.read_u32(&mut offset); - println!( - "Received key:\n\tSerial: {}\n\tTime: {}\n\tKey: {}\n\tState: {}", - serial, - time, - key, - state - ) + + if let Some(keymap) = &*self.keymap.lock().unwrap() { + if let Some(keysym) = keymap.get(&(key + 8)) { + println!("Received key:\n\t{} {}", keysym, if state == 0 {'↑'} else {'↓'}); + } else { + eprintln!("Unrecognized key!"); + } + } else { + println!( + "Received key:\n\tserial: {}\n\ttime: {}\n\tkey: {}\n\tstate: {}", + serial, + time, + key, + state + ); + } + Ok(()) } } diff --git a/src/wayland/shm.rs b/src/wayland/shm.rs index d647d4b..5ee7549 100644 --- a/src/wayland/shm.rs +++ b/src/wayland/shm.rs @@ -52,6 +52,18 @@ impl ShmPool { Ok(ShmPool {fd, addr, size, width: 0}) } + pub fn read_string(&self, offset: usize) -> std::io::Result { + let mut res: Vec = Vec::new(); + for i in offset..self.size { + let byte = unsafe {*(self.addr.offset(i as isize) as *const u8)}; + if byte == 0 { + break; + } + res.push(byte); + }; + Ok(String::from_utf8(res).unwrap()) + } + pub fn resize(&mut self, size: usize) -> std::io::Result<()> { if unsafe { ftruncate(self.fd, size as i64) } == -1 { return Err(std::io::Error::last_os_error()) diff --git a/src/wayland/wl_client.rs b/src/wayland/wl_client.rs index 57a6d4e..5621fcf 100644 --- a/src/wayland/wl_client.rs +++ b/src/wayland/wl_client.rs @@ -1,6 +1,4 @@ -#![feature(unix_socket_ancillary_data)] - -use std::{env::var, error::Error, fmt::Debug, io::{IoSliceMut, Read}, os::unix::net::{AncillaryData, SocketAncillary, UnixStream}, sync::{atomic::{AtomicU32, Ordering}, Arc, Mutex}, thread::{self, JoinHandle}, u32}; +use std::{collections::HashMap, env::var, error::Error, fmt::Debug, io::IoSliceMut, os::unix::net::{AncillaryData, SocketAncillary, UnixStream}, sync::{atomic::{AtomicU32, Ordering}, Arc, Mutex}, thread::{self}, u32}; use crate::wayland::shm; @@ -25,7 +23,8 @@ pub struct WlClient { pub layer_surface_id: AtomicU32, pub seat_id: AtomicU32, pub keyboard_id: AtomicU32, - pub keymap: Mutex>, + pub keymap_fd: Mutex>, + pub keymap: Mutex>> } impl WlClient { @@ -52,6 +51,7 @@ impl WlClient { seat_id: AtomicU32::from(0), keyboard_id: AtomicU32::from(0), keymap: Mutex::new(None), + keymap_fd: Mutex::new(None), }); let mut wl_client2 = wl_client.clone(); diff --git a/src/wayland/xkb.rs b/src/wayland/xkb.rs new file mode 100644 index 0000000..69f6bae --- /dev/null +++ b/src/wayland/xkb.rs @@ -0,0 +1,115 @@ +use core::str; +use std::{collections::HashMap, string}; + +use super::shm::ShmPool; + +#[derive(Debug)] +enum ParseMode { + Default, + Outer, + Inner, + Min, + Max, + Keysym, + Keycode, +} +use ParseMode::*; + +pub fn gen_id_keysym_mapping(xkb_map: &ShmPool) -> Option> { + let mut word = String::new(); + let mut keycodes: bool = false; + + let mut parse_mode = ParseMode::Default; + + let mut max = 0; + let mut min = 0; + + let mut keycode: String = String::new(); + let mut keysym: String = String::new(); + + let mut res: HashMap = HashMap::new(); + + // TODO: Make this not a nightmare if else tree + for ch in unsafe {str::from_raw_parts(xkb_map.addr as *mut u8, xkb_map.size)}.chars() { + match parse_mode { + Default => { + if ch.is_whitespace() { + word.clear(); + } else { + word.push(ch); + } + if word == "xkb_keycodes" { + parse_mode = Outer; + } + } + Outer => { + if ch == '{' { + parse_mode = Inner; + } + } + Inner => { + if ch.is_whitespace() { + word.clear(); + } else { + word.push(ch); + } + + if ch == '}' { + break; + } else if ch == '<' { + parse_mode = Keysym; + } else if ch == '=' { + parse_mode = Keycode; + } + + if word == "minimum" { + parse_mode = Min; + } + else if word == "maximum" { + parse_mode = Max; + } + } + Min => { + if ch == ';' { + min = u32::from_str_radix(keycode.as_str(), 10).unwrap(); + keycode.clear(); + parse_mode = Inner; + } else if ch.is_digit(10) { + keycode.push(ch); + } + } + Max => { + if ch == ';' { + max = u32::from_str_radix(keycode.as_str(), 10).unwrap(); + keycode.clear(); + parse_mode = Inner; + } else if ch.is_digit(10) { + keycode.push(ch); + } + } + Keysym => { + if ch == '>' { + parse_mode = Inner; + } else { + keysym.push(ch); + } + } + Keycode => { + if ch == ';' { + let code = u32::from_str_radix(keycode.as_str(), 10).unwrap(); + res.insert(code, keysym.clone()); + if u32::from_str_radix(keycode.as_str(), 10).unwrap() >= max { + break; + } + keycode.clear(); + keysym.clear(); + parse_mode = Inner; + } else if ch.is_digit(10) { + keycode.push(ch); + } + } + } + } + + Some(res) +}