Properly understand keys pressed and unpressed

This commit is contained in:
2025-05-14 22:05:31 -07:00
parent 9d0b9b97b5
commit 5b8475f1a3
4 changed files with 158 additions and 106 deletions

View File

@@ -60,7 +60,7 @@ impl WlClient {
let mut keymap_fd = self.keymap_fd.lock().unwrap(); let mut keymap_fd = self.keymap_fd.lock().unwrap();
*keymap_fd = Some(shm::ShmPool::from_fd(fd, size as usize)?); *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()); *keymap = xkb::gen_id_keysym_mapping(keymap_fd.as_ref().unwrap());
Ok(()) Ok(())
@@ -73,12 +73,12 @@ impl WlClient {
let key = event.read_u32(&mut offset); let key = event.read_u32(&mut offset);
let state = 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 let Some(keysym) = keymap.get(&(key + 8)) {
if keysym == "ESC" && state == 0 { if keysym[0] == "Escape" && state == 0 {
self.exit(); self.exit();
} }
println!("Received key:\n\t{} {}", keysym, if state == 0 {'↑'} else {'↓'}); println!("Received key:\n\t{} {}", keysym[0], if state == 0 {'↑'} else {'↓'});
} else { } else {
eprintln!("Unrecognized key!"); eprintln!("Unrecognized key!");
} }

View File

@@ -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}; use crate::wayland::{shm, vec_utils::WlMessage};
@@ -31,7 +31,7 @@ pub struct WlClient {
pub seat_id: AtomicU32, pub seat_id: AtomicU32,
pub keyboard_id: AtomicU32, pub keyboard_id: AtomicU32,
pub keymap_fd: Mutex<Option<shm::ShmPool>>, pub keymap_fd: Mutex<Option<shm::ShmPool>>,
pub keymap: Mutex<Option<HashMap<u32, String>>> pub keymap: RwLock<Option<HashMap<u32, Vec<String>>>>
} }
impl WlClient { impl WlClient {
@@ -62,7 +62,7 @@ impl WlClient {
layer_surface_id: AtomicU32::from(0), layer_surface_id: AtomicU32::from(0),
seat_id: AtomicU32::from(0), seat_id: AtomicU32::from(0),
keyboard_id: AtomicU32::from(0), keyboard_id: AtomicU32::from(0),
keymap: Mutex::new(None), keymap: RwLock::new(None),
keymap_fd: Mutex::new(None), keymap_fd: Mutex::new(None),
}); });
arc_wl_client.wl_display_get_registry(); arc_wl_client.wl_display_get_registry();

View File

@@ -16,11 +16,11 @@ impl WlClient {
let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1;
self.shmpool_id.store(current_id, Ordering::Relaxed); self.shmpool_id.store(current_id, Ordering::Relaxed);
shm_pool.write(&vec![0xffff0000; width * height], 0); // shm_pool.write(&vec![0xffff0000; width * height], 0);
let rect = Rectangle::new(100, 100, 200, 50, 25, 0xffffff); let rect = Rectangle::new(100, 100, 200, 50, 20, 0xffffff);
rect.draw(&mut shm_pool); rect.draw(&mut shm_pool);
let circle = Circle::new(250, 150, 20, 0xff00ffff); // let circle = Circle::new(250, 150, 20, 0xff00ffff);
circle.draw(&mut shm_pool); // circle.draw(&mut shm_pool);
let object = self.shm_id.load(Ordering::Relaxed); let object = self.shm_id.load(Ordering::Relaxed);
if object == 0 { if object == 0 {

View File

@@ -1,113 +1,165 @@
use core::str; use core::str;
use std::{collections::HashMap, string}; use std::{collections::HashMap, fmt::{Debug, Display}, string::{self, ParseError}};
use super::shm::ShmPool; use super::shm::ShmPool;
#[derive(Debug)] enum Data<'a> {
enum ParseMode { Block(&'a str, Vec<Data<'a>>),
Default, Statement(&'a str),
Outer,
Inner,
Min,
Max,
Keysym,
Keycode,
} }
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<HashMap<u32, String>> { fn parse_block(map: &str) -> Vec<Data> {
let mut word = String::new(); let mut begin = 0;
let mut keycodes: bool = false; let mut stack = 0;
let mut is_statement = true;
let mut parse_mode = ParseMode::Default; let mut datas = Vec::new();
for (i, byte) in map.bytes().enumerate() {
let mut max = 0; if stack == 0 {
let mut min = 0; if byte == '{' as u8 {
datas.push(Block(
let mut keycode: String = String::new(); map.get(begin..i).unwrap(),
let mut keysym: String = String::new(); parse_block(map.get(i+1..).unwrap())
));
let mut res: HashMap<u32, String> = HashMap::new(); is_statement = false;
}
// TODO: Make this not a nightmare if else tree else if byte == '}' as u8 {
for ch in unsafe {str::from_raw_parts(xkb_map.addr as *mut u8, xkb_map.size)}.chars() { return datas;
match parse_mode { }
Default => { else if byte == ';' as u8 || byte == ',' as u8 || byte == ']' as u8 {
if ch.is_whitespace() { if is_statement {
word.clear(); datas.push(Statement(map.get(begin..i).unwrap()));
} else { } else {
word.push(ch); is_statement = true;
} }
if word == "xkb_keycodes" { begin = i+1;
parse_mode = Outer;
} }
else if byte == '[' as u8 {
begin = i+1;
} }
Outer => {
if ch == '{' {
parse_mode = Inner;
}
}
Inner => {
if ch.is_whitespace() {
word.clear();
} else {
word.push(ch);
} }
if ch == '}' { if byte == '{' as u8 {
break; stack += 1;
} else if ch == '<' { }
parse_mode = Keysym; else if byte == '}' as u8 {
} else if ch == '=' { stack -= 1;
parse_mode = Keycode; }
};
datas
} }
if word == "minimum" { fn xkb_symbols(xkb_map: &Data) -> Result<HashMap<String, Vec<String>>, ()> {
parse_mode = Min; let mut map_symbols: Option<&Vec<Data>> = None;
} if let Block(header, subdata) = xkb_map {
else if word == "maximum" { if header.find("xkb_keymap").is_some() {
parse_mode = Max; for subdata in subdata {
if let Block(header, subdata) = subdata {
if header.find("xkb_symbols").is_some() {
map_symbols = Some(&subdata);
} }
} }
Min => { }
if ch == ';' { }
min = u32::from_str_radix(keycode.as_str(), 10).unwrap(); }
keycode.clear();
parse_mode = Inner; let map_symbols: &Vec<Data> = map_symbols.ok_or(())?;
} else if ch.is_digit(10) { 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<char> {
for ch in s.chars() {
if !ch.is_whitespace() {
return Some(ch);
}
}
return None;
}
fn xkb_keycodes(xkb_map: &Data) -> Result<HashMap<u32, String>, ()> {
let mut keycodes: Option<&Vec<Data>> = 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); keycode.push(ch);
} }
} }
Max => { let keycode: u32 = keycode.parse().or(Err(()))?;
if ch == ';' { res.insert(keycode, keysym.to_string());
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; Ok(res)
} 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);
}
} }
pub fn gen_id_keysym_mapping(xkb_map: &ShmPool) -> Option<HashMap<u32, Vec<String>>> {
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);
} }
} }