From 5b8475f1a3d518725bcfbac17e854b85d4fe44ac Mon Sep 17 00:00:00 2001 From: chlorospingus Date: Wed, 14 May 2025 22:05:31 -0700 Subject: [PATCH] Properly understand keys pressed and unpressed --- src/wayland/seat.rs | 8 +- src/wayland/wl_client.rs | 6 +- src/wayland/wl_shm.rs | 8 +- src/wayland/xkb.rs | 242 ++++++++++++++++++++++++--------------- 4 files changed, 158 insertions(+), 106 deletions(-) diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs index 97f5b96..fcdc6a9 100644 --- a/src/wayland/seat.rs +++ b/src/wayland/seat.rs @@ -60,7 +60,7 @@ impl WlClient { 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(); + let mut keymap = self.keymap.write().unwrap(); *keymap = xkb::gen_id_keysym_mapping(keymap_fd.as_ref().unwrap()); Ok(()) @@ -73,12 +73,12 @@ impl WlClient { let key = event.read_u32(&mut offset); let state = event.read_u32(&mut offset); - if let Some(keymap) = &*self.keymap.lock().unwrap() { + if let Some(keymap) = &*self.keymap.read().unwrap() { if let Some(keysym) = keymap.get(&(key + 8)) { - if keysym == "ESC" && state == 0 { + if keysym[0] == "Escape" && state == 0 { self.exit(); } - println!("Received key:\n\t{} {}", keysym, if state == 0 {'↑'} else {'↓'}); + println!("Received key:\n\t{} {}", keysym[0], if state == 0 {'↑'} else {'↓'}); } else { eprintln!("Unrecognized key!"); } diff --git a/src/wayland/wl_client.rs b/src/wayland/wl_client.rs index de2c6ea..10419b6 100644 --- a/src/wayland/wl_client.rs +++ b/src/wayland/wl_client.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, env::var, error::Error, fmt::Debug, io::{IoSliceMut, Write}, os::unix::net::{AncillaryData, SocketAncillary, UnixStream}, sync::{atomic::{AtomicU32, AtomicBool, Ordering}, mpsc, Arc, Mutex}, thread::{self}, time::Duration, u32}; +use std::{collections::HashMap, env::var, error::Error, fmt::Debug, io::{IoSliceMut, Write}, os::unix::net::{AncillaryData, SocketAncillary, UnixStream}, sync::{atomic::{AtomicBool, AtomicU32, Ordering}, mpsc, Arc, Mutex, RwLock}, thread::{self}, time::Duration, u32}; use crate::wayland::{shm, vec_utils::WlMessage}; @@ -31,7 +31,7 @@ pub struct WlClient { pub seat_id: AtomicU32, pub keyboard_id: AtomicU32, pub keymap_fd: Mutex>, - pub keymap: Mutex>> + pub keymap: RwLock>>> } impl WlClient { @@ -62,7 +62,7 @@ impl WlClient { layer_surface_id: AtomicU32::from(0), seat_id: AtomicU32::from(0), keyboard_id: AtomicU32::from(0), - keymap: Mutex::new(None), + keymap: RwLock::new(None), keymap_fd: Mutex::new(None), }); arc_wl_client.wl_display_get_registry(); diff --git a/src/wayland/wl_shm.rs b/src/wayland/wl_shm.rs index 1d6375b..78a6a93 100644 --- a/src/wayland/wl_shm.rs +++ b/src/wayland/wl_shm.rs @@ -16,11 +16,11 @@ impl WlClient { let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; self.shmpool_id.store(current_id, Ordering::Relaxed); - shm_pool.write(&vec![0xffff0000; width * height], 0); - let rect = Rectangle::new(100, 100, 200, 50, 25, 0xffffff); + // shm_pool.write(&vec![0xffff0000; width * height], 0); + let rect = Rectangle::new(100, 100, 200, 50, 20, 0xffffff); rect.draw(&mut shm_pool); - let circle = Circle::new(250, 150, 20, 0xff00ffff); - circle.draw(&mut shm_pool); + // let circle = Circle::new(250, 150, 20, 0xff00ffff); + // circle.draw(&mut shm_pool); let object = self.shm_id.load(Ordering::Relaxed); if object == 0 { diff --git a/src/wayland/xkb.rs b/src/wayland/xkb.rs index 69f6bae..00be777 100644 --- a/src/wayland/xkb.rs +++ b/src/wayland/xkb.rs @@ -1,115 +1,167 @@ use core::str; -use std::{collections::HashMap, string}; +use std::{collections::HashMap, fmt::{Debug, Display}, string::{self, ParseError}}; use super::shm::ShmPool; -#[derive(Debug)] -enum ParseMode { - Default, - Outer, - Inner, - Min, - Max, - Keysym, - Keycode, +enum Data<'a> { + Block(&'a str, Vec>), + Statement(&'a str), } -use ParseMode::*; +impl Debug for Data<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Block(header, data) => write!(f, "Block({}, {:#?})", header, data), + Statement(str) => write!(f, "Statement({})", str), + } + } +} +use Data::*; -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(); +fn parse_block(map: &str) -> Vec { + let mut begin = 0; + let mut stack = 0; + let mut is_statement = true; + let mut datas = Vec::new(); + for (i, byte) in map.bytes().enumerate() { + if stack == 0 { + if byte == '{' as u8 { + datas.push(Block( + map.get(begin..i).unwrap(), + parse_block(map.get(i+1..).unwrap()) + )); + is_statement = false; + } + else if byte == '}' as u8 { + return datas; + } + else if byte == ';' as u8 || byte == ',' as u8 || byte == ']' as u8 { + if is_statement { + datas.push(Statement(map.get(begin..i).unwrap())); } else { - word.push(ch); - } - if word == "xkb_keycodes" { - parse_mode = Outer; + is_statement = true; } + begin = i+1; } - Outer => { - if ch == '{' { - parse_mode = Inner; - } + else if byte == '[' as u8 { + begin = i+1; } - 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 byte == '{' as u8 { + stack += 1; + } + else if byte == '}' as u8 { + stack -= 1; + } + }; - 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; + datas +} + +fn xkb_symbols(xkb_map: &Data) -> Result>, ()> { + let mut map_symbols: Option<&Vec> = None; + if let Block(header, subdata) = xkb_map { + if header.find("xkb_keymap").is_some() { + for subdata in subdata { + if let Block(header, subdata) = subdata { + if header.find("xkb_symbols").is_some() { + map_symbols = Some(&subdata); } - keycode.clear(); - keysym.clear(); - parse_mode = Inner; - } else if ch.is_digit(10) { - keycode.push(ch); } } } } + let map_symbols: &Vec = map_symbols.ok_or(())?; + let mut res = HashMap::new(); + for map_symbols in map_symbols { + if let Block(header, map_symbols) = map_symbols { + if header.find("key").is_some() { + let keysym = header.get( + header.find('<').ok_or(())?+1.. + header.find('>').ok_or(())? + ).ok_or(())?.to_string(); + let mut symbols = Vec::new(); + for map_symbol in map_symbols { + if let Statement(map_symbol) = &map_symbol { + let mut symbol = String::new(); + for ch in map_symbol.chars() { + if !ch.is_whitespace() { + symbol.push(ch); + } + } + symbols.push(symbol); + } + } + res.insert(keysym, symbols); + } + } + } + + Ok(res) +} + +fn first_non_whitespace(s: &str) -> Option { + for ch in s.chars() { + if !ch.is_whitespace() { + return Some(ch); + } + } + return None; +} + +fn xkb_keycodes(xkb_map: &Data) -> Result, ()> { + let mut keycodes: Option<&Vec> = None; + if let Block(header, subdata) = xkb_map { + if header.find("xkb_keymap").is_some() { + for subdata in subdata { + if let Block(header, subdata) = subdata { + if header.find("xkb_keycodes").is_some() { + keycodes = Some(&subdata); + } + } + } + } + } + + let mut res = HashMap::new(); + let keycodes = keycodes.ok_or(())?; + for map_keycode in keycodes { + if let Statement(map_keycode) = map_keycode { + if Some('<') != first_non_whitespace(map_keycode) { + continue; + } + let keysym = map_keycode.get( + map_keycode.find('<').ok_or(())?+1.. + map_keycode.find('>').ok_or(())? + ).ok_or(())?; + let mut keycode = String::new(); + for ch in map_keycode.get(map_keycode.find('=').ok_or(())?..).ok_or(())?.chars() { + if ch.is_digit(10) { + keycode.push(ch); + } + } + let keycode: u32 = keycode.parse().or(Err(()))?; + res.insert(keycode, keysym.to_string()); + } + } + + + Ok(res) +} + +pub fn gen_id_keysym_mapping(xkb_map: &ShmPool) -> Option>> { + let xkb_map = unsafe {str::from_raw_parts(xkb_map.addr as *const u8, xkb_map.size)}; + let mut res = HashMap::new(); + let data = parse_block(xkb_map); + let mut symbols = xkb_symbols(&data[0]).ok()?; + let keycodes = xkb_keycodes(&data[0]).ok()?; + for keycode in keycodes { + let symbol = symbols.remove(&keycode.1); + if let Some(symbol) = symbol { + res.insert(keycode.0, symbol); + } + } + Some(res) }