164 lines
5.3 KiB
Rust
164 lines
5.3 KiB
Rust
use {
|
|
crate::{
|
|
backend::KeyState,
|
|
client::{Client, ClientError},
|
|
clientmem::{ClientMem, ClientMemError},
|
|
ifs::{
|
|
wl_seat::{
|
|
WlSeatGlobal,
|
|
wl_keyboard::{self, WlKeyboard},
|
|
},
|
|
wl_surface::WlSurface,
|
|
},
|
|
kbvm::KbvmError,
|
|
keyboard::KeyboardState,
|
|
leaks::Tracker,
|
|
object::{Object, Version},
|
|
wire::{ZwpVirtualKeyboardV1Id, zwp_virtual_keyboard_v1::*},
|
|
},
|
|
std::{cell::RefCell, rc::Rc},
|
|
thiserror::Error,
|
|
};
|
|
|
|
pub struct ZwpVirtualKeyboardV1 {
|
|
pub id: ZwpVirtualKeyboardV1Id,
|
|
pub client: Rc<Client>,
|
|
pub seat: Rc<WlSeatGlobal>,
|
|
pub tracker: Tracker<Self>,
|
|
pub version: Version,
|
|
pub kb_state: Rc<RefCell<KeyboardState>>,
|
|
}
|
|
|
|
impl ZwpVirtualKeyboardV1 {
|
|
fn for_each_kb<F>(&self, mut f: F)
|
|
where
|
|
F: FnMut(u64, &WlSurface, &Rc<WlKeyboard>),
|
|
{
|
|
let Some(surface) = self.seat.keyboard_node.get().node_into_surface() else {
|
|
return;
|
|
};
|
|
let serial = surface.client.next_serial();
|
|
self.seat.surface_kb_event(Version::ALL, &surface, |kb| {
|
|
f(serial, &surface, kb);
|
|
});
|
|
}
|
|
}
|
|
|
|
impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
|
|
type Error = ZwpVirtualKeyboardV1Error;
|
|
|
|
fn keymap(&self, req: Keymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
if req.format != wl_keyboard::XKB_V1 {
|
|
return Err(ZwpVirtualKeyboardV1Error::UnsupportedFormat(req.format));
|
|
}
|
|
if req.size == 0 {
|
|
return Err(ZwpVirtualKeyboardV1Error::InvalidKeymap);
|
|
}
|
|
const MAX_SIZE: u32 = 1024 * 1024;
|
|
if req.size > MAX_SIZE {
|
|
return Err(ZwpVirtualKeyboardV1Error::OversizedKeymap);
|
|
}
|
|
let client_mem = ClientMem::new_private(
|
|
&req.fd,
|
|
req.size as usize - 1,
|
|
true,
|
|
Some(&self.client),
|
|
None,
|
|
)
|
|
.map(Rc::new)
|
|
.map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?;
|
|
let mut map = vec![];
|
|
client_mem
|
|
.offset(0)
|
|
.read(&mut map)
|
|
.map_err(ZwpVirtualKeyboardV1Error::ReadKeymap)?;
|
|
let map = self
|
|
.client
|
|
.state
|
|
.kb_ctx
|
|
.parse_keymap(&map)
|
|
.map_err(ZwpVirtualKeyboardV1Error::ParseKeymap)?;
|
|
*self.kb_state.borrow_mut() = KeyboardState {
|
|
id: self.client.state.keyboard_state_ids.next(),
|
|
map: map.clone(),
|
|
pressed_keys: Default::default(),
|
|
mods: Default::default(),
|
|
leds: Default::default(),
|
|
leds_changed: Default::default(),
|
|
};
|
|
Ok(())
|
|
}
|
|
|
|
fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
let kb_state = &mut *self.kb_state.borrow_mut();
|
|
let contains = kb_state.pressed_keys.contains(&req.key);
|
|
let (state, valid) = match req.state {
|
|
wl_keyboard::RELEASED => (KeyState::Released, contains),
|
|
wl_keyboard::PRESSED => (KeyState::Pressed, !contains),
|
|
_ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)),
|
|
};
|
|
if valid {
|
|
self.for_each_kb(|serial, surface, kb| {
|
|
kb.on_key(serial, req.time, req.key, state, surface.id, kb_state);
|
|
});
|
|
match req.state {
|
|
wl_keyboard::RELEASED => kb_state.pressed_keys.remove(&req.key),
|
|
_ => kb_state.pressed_keys.insert(req.key),
|
|
};
|
|
self.seat.latest_kb_state_id.set(kb_state.id);
|
|
self.seat.latest_kb_state.set(self.kb_state.clone());
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn modifiers(&self, req: Modifiers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
let kb_state = &mut *self.kb_state.borrow_mut();
|
|
kb_state.mods.mods_pressed.0 = req.mods_depressed;
|
|
kb_state.mods.mods_latched.0 = req.mods_latched;
|
|
kb_state.mods.mods_locked.0 = req.mods_locked;
|
|
kb_state.mods.group_locked.0 = req.group;
|
|
kb_state.mods.update_effective();
|
|
kb_state.update_leds();
|
|
self.for_each_kb(|serial, surface, kb| {
|
|
kb.on_mods_changed(serial, surface.id, &kb_state);
|
|
});
|
|
self.seat.latest_kb_state_id.set(kb_state.id);
|
|
self.seat.latest_kb_state.set(self.kb_state.clone());
|
|
Ok(())
|
|
}
|
|
|
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
self.client.remove_obj(self)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
object_base! {
|
|
self = ZwpVirtualKeyboardV1;
|
|
version = self.version;
|
|
}
|
|
|
|
impl Object for ZwpVirtualKeyboardV1 {}
|
|
|
|
simple_add_obj!(ZwpVirtualKeyboardV1);
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum ZwpVirtualKeyboardV1Error {
|
|
#[error(transparent)]
|
|
ClientError(Box<ClientError>),
|
|
#[error("Unknown key state {0}")]
|
|
UnknownState(u32),
|
|
#[error("Unsupported keymap format {0}")]
|
|
UnsupportedFormat(u32),
|
|
#[error("Keymap is invalid")]
|
|
InvalidKeymap,
|
|
#[error("Keymap is too large")]
|
|
OversizedKeymap,
|
|
#[error("Could not map the keymap")]
|
|
MapKeymap(#[source] ClientMemError),
|
|
#[error("Could not read the keymap")]
|
|
ReadKeymap(#[source] ClientMemError),
|
|
#[error("Could not parse the keymap")]
|
|
ParseKeymap(#[source] KbvmError),
|
|
}
|
|
efrom!(ZwpVirtualKeyboardV1Error, ClientError);
|