1
0
Fork 0
forked from wry/wry
wry/src/ifs/wl_seat/wl_keyboard.rs
2025-10-16 21:18:26 +02:00

231 lines
6.2 KiB
Rust

use {
crate::{
backend::KeyState,
client::ClientError,
ifs::wl_seat::WlSeat,
keyboard::{KeyboardError, KeyboardState, KeyboardStateId},
leaks::Tracker,
object::{Object, Version},
utils::{errorfmt::ErrorFmt, vecset::VecSet},
wire::{WlKeyboardId, WlSurfaceId, wl_keyboard::*},
},
kbvm::Components,
std::{
cell::{Cell, RefCell},
rc::Rc,
},
thiserror::Error,
};
pub const REPEAT_INFO_SINCE: Version = Version(4);
pub const REPEATED_SINCE: Version = Version(10);
#[expect(dead_code)]
const NO_KEYMAP: u32 = 0;
pub const XKB_V1: u32 = 1;
pub const RELEASED: u32 = 0;
pub const PRESSED: u32 = 1;
pub const REPEATED: u32 = 2;
pub struct WlKeyboard {
id: WlKeyboardId,
seat: Rc<WlSeat>,
kb_state_id: Cell<KeyboardStateId>,
pressed_keys: RefCell<VecSet<u32>>,
pub tracker: Tracker<Self>,
}
impl WlKeyboard {
pub fn new(id: WlKeyboardId, seat: &Rc<WlSeat>) -> Self {
Self {
id,
seat: seat.clone(),
kb_state_id: Cell::new(KeyboardStateId::from_raw(0)),
pressed_keys: Default::default(),
tracker: Default::default(),
}
}
pub fn kb_state_id(&self) -> KeyboardStateId {
self.kb_state_id.get()
}
fn send_kb_state(
&self,
serial: u64,
kb_state: &KeyboardState,
surface_id: WlSurfaceId,
send_leave: bool,
) {
self.kb_state_id.set(kb_state.id);
if send_leave {
self.send_leave(serial, surface_id);
}
self.send_keymap(kb_state);
self.send_enter(serial, surface_id, &kb_state.pressed_keys);
self.send_modifiers(serial, &kb_state.mods);
}
fn send_keymap(&self, state: &KeyboardState) {
let fd = match self.seat.keymap_fd(state) {
Ok(fd) => fd,
Err(e) => {
log::error!(
"Could not creat a file descriptor to transfer the keymap to client {}: {}",
self.seat.client.id,
ErrorFmt(e)
);
return;
}
};
self.seat.client.event(Keymap {
self_id: self.id,
format: XKB_V1,
fd: fd.map,
size: fd.len as _,
});
}
pub fn enter(&self, serial: u64, surface: WlSurfaceId, kb_state: &KeyboardState) {
if kb_state.id != self.kb_state_id.get() {
self.send_kb_state(serial, kb_state, surface, false);
} else {
self.send_enter(serial, surface, &kb_state.pressed_keys);
self.send_modifiers(serial, &kb_state.mods);
}
}
fn send_enter(&self, serial: u64, surface: WlSurfaceId, keys: &[u32]) {
{
let pk = &mut self.pressed_keys.borrow_mut();
pk.clear();
pk.extend(keys);
}
self.seat.client.event(Enter {
self_id: self.id,
serial: serial as _,
surface,
keys,
})
}
pub fn send_leave(&self, serial: u64, surface: WlSurfaceId) {
self.seat.client.event(Leave {
self_id: self.id,
serial: serial as _,
surface,
})
}
pub fn on_key(
&self,
serial: u64,
time: u32,
key: u32,
state: KeyState,
surface: WlSurfaceId,
kb_state: &KeyboardState,
) {
if self.kb_state_id.get() != kb_state.id {
self.send_kb_state(serial, kb_state, surface, true);
}
self.send_key(serial, time, key, state);
}
fn send_key(&self, serial: u64, time: u32, key: u32, state: KeyState) {
if state == KeyState::Repeated && self.seat.version < REPEATED_SINCE {
return;
}
{
let pk = &mut self.pressed_keys.borrow_mut();
match state {
KeyState::Released => {
if !pk.remove(&key) {
return;
}
}
KeyState::Pressed => {
if !pk.insert(key) {
return;
}
}
KeyState::Repeated => {
if !pk.contains(&key) {
return;
}
}
}
}
self.seat.client.event(Key {
self_id: self.id,
serial: serial as _,
time,
key,
state: match state {
KeyState::Released => RELEASED,
KeyState::Pressed => PRESSED,
KeyState::Repeated => REPEATED,
},
})
}
pub fn on_mods_changed(&self, serial: u64, surface: WlSurfaceId, kb_state: &KeyboardState) {
if self.kb_state_id.get() != kb_state.id {
self.send_kb_state(serial, kb_state, surface, true);
} else {
self.send_modifiers(serial, &kb_state.mods);
}
}
fn send_modifiers(&self, serial: u64, mods: &Components) {
self.seat.client.event(Modifiers {
self_id: self.id,
serial: serial as _,
mods_depressed: mods.mods_pressed.0,
mods_latched: mods.mods_latched.0,
mods_locked: mods.mods_locked.0,
group: mods.group.0,
})
}
pub fn send_repeat_info(self: &Rc<Self>, mut rate: i32, mut delay: i32) {
if self.seat.version >= REPEATED_SINCE {
rate = 0;
delay = 0;
}
self.seat.client.event(RepeatInfo {
self_id: self.id,
rate,
delay,
})
}
}
impl WlKeyboardRequestHandler for WlKeyboard {
type Error = WlKeyboardError;
fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.seat.keyboards.remove(&self.id);
self.seat.client.remove_obj(self)?;
Ok(())
}
}
object_base! {
self = WlKeyboard;
version = self.seat.version;
}
impl Object for WlKeyboard {}
simple_add_obj!(WlKeyboard);
#[derive(Debug, Error)]
pub enum WlKeyboardError {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error(transparent)]
KeyboardError(#[from] KeyboardError),
}
efrom!(WlKeyboardError, ClientError);