seat: add KeyboardState and dynamically switch between states
This commit is contained in:
parent
134e3cc316
commit
5e2cdef388
15 changed files with 406 additions and 222 deletions
|
|
@ -230,6 +230,7 @@ fn start_compositor2(
|
|||
subsurface_ids: Default::default(),
|
||||
wait_for_sync_obj: Rc::new(WaitForSyncObj::new(&ring, &engine)),
|
||||
explicit_sync_enabled: Cell::new(true),
|
||||
keyboard_state_ids: Default::default(),
|
||||
});
|
||||
state.tracker.register(ClientId::from_raw(0));
|
||||
create_dummy_output(&state);
|
||||
|
|
|
|||
|
|
@ -309,13 +309,12 @@ impl ConfigProxyHandler {
|
|||
keymap: Keymap,
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
if keymap.is_invalid() {
|
||||
dev.keymap_id.set(None);
|
||||
dev.keymap.set(None);
|
||||
let map = if keymap.is_invalid() {
|
||||
None
|
||||
} else {
|
||||
let map = self.get_keymap(keymap)?;
|
||||
dev.set_keymap(&map);
|
||||
Some(self.get_keymap(keymap)?)
|
||||
};
|
||||
dev.set_keymap(map);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -548,7 +547,7 @@ impl ConfigProxyHandler {
|
|||
Some(self.get_seat(seat)?)
|
||||
};
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.seat.set(seat);
|
||||
dev.set_seat(seat);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
self.or_error(|| {
|
||||
let seat = self.seat(req.seat)?;
|
||||
let dev = self.device(req.id)?;
|
||||
dev.seat.set(Some(seat));
|
||||
dev.set_seat(Some(seat));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -333,7 +333,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn detach(&self, req: Detach, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.seat.set(None);
|
||||
dev.set_seat(None);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -374,7 +374,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn set_device_keymap(&self, req: SetDeviceKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.set_keymap_impl(&req.keymap, req.keymap_len, |map| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.set_keymap(&map);
|
||||
dev.set_keymap(Some(map.clone()));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ use {
|
|||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
rect::Rect,
|
||||
state::State,
|
||||
state::{DeviceHandlerData, State},
|
||||
time::now_usec,
|
||||
tree::{
|
||||
generic_node_visitor, ContainerNode, ContainerSplit, Direction, FloatNode, FoundNode,
|
||||
|
|
@ -58,14 +58,14 @@ use {
|
|||
utils::{
|
||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt, linkedlist::LinkedNode, numcell::NumCell, rc_eq::rc_eq,
|
||||
smallmap::SmallMap, transform_ext::TransformExt, vecset::VecSet,
|
||||
smallmap::SmallMap, transform_ext::TransformExt,
|
||||
},
|
||||
wire::{
|
||||
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
||||
WlSeatId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
|
||||
ZwpRelativePointerV1Id,
|
||||
},
|
||||
xkbcommon::{KeymapId, XkbKeymap, XkbState},
|
||||
xkbcommon::{DynKeyboardState, KeyboardState, KeymapId, XkbKeymap, XkbState},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
jay_config::keyboard::mods::Modifiers,
|
||||
|
|
@ -75,7 +75,7 @@ use {
|
|||
collections::hash_map::Entry,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
rc::Rc,
|
||||
rc::{Rc, Weak},
|
||||
},
|
||||
thiserror::Error,
|
||||
uapi::{c, Errno, OwnedFd},
|
||||
|
|
@ -130,7 +130,6 @@ pub struct WlSeatGlobal {
|
|||
pointer_stack_modified: Cell<bool>,
|
||||
found_tree: RefCell<Vec<FoundNode>>,
|
||||
keyboard_node: CloneCell<Rc<dyn Node>>,
|
||||
pressed_keys: RefCell<VecSet<u32>>,
|
||||
bindings: RefCell<AHashMap<ClientId, AHashMap<WlSeatId, Rc<WlSeat>>>>,
|
||||
x_data_devices: SmallMap<XIpcDeviceId, Rc<XIpcDevice>, 1>,
|
||||
data_devices: RefCell<AHashMap<ClientId, AHashMap<WlDataDeviceId, Rc<WlDataDevice>>>>,
|
||||
|
|
@ -144,10 +143,9 @@ pub struct WlSeatGlobal {
|
|||
CopyHashMap<(ClientId, ZwlrDataControlDeviceV1Id), Rc<ZwlrDataControlDeviceV1>>,
|
||||
repeat_rate: Cell<(i32, i32)>,
|
||||
seat_kb_map: CloneCell<Rc<XkbKeymap>>,
|
||||
seat_kb_map_id: Cell<KeymapId>,
|
||||
effective_kb_map: CloneCell<Rc<XkbKeymap>>,
|
||||
effective_kb_map_id: Cell<KeymapId>,
|
||||
kb_state: RefCell<XkbState>,
|
||||
seat_xkb_state: CloneCell<Rc<RefCell<XkbState>>>,
|
||||
latest_kb_state: CloneCell<Rc<dyn DynKeyboardState>>,
|
||||
xkb_states: CopyHashMap<KeymapId, Weak<RefCell<XkbState>>>,
|
||||
cursor: CloneCell<Option<Rc<dyn Cursor>>>,
|
||||
tree_changed: Rc<AsyncEvent>,
|
||||
selection: CloneCell<Option<Rc<dyn DynDataSource>>>,
|
||||
|
|
@ -168,7 +166,6 @@ pub struct WlSeatGlobal {
|
|||
constraint: CloneCell<Option<Rc<SeatConstraint>>>,
|
||||
idle_notifications: CopyHashMap<(ClientId, ExtIdleNotificationV1Id), Rc<ExtIdleNotificationV1>>,
|
||||
last_input_usec: Cell<u64>,
|
||||
keymap_version: NumCell<u32>,
|
||||
}
|
||||
|
||||
const CHANGE_CURSOR_MOVED: u32 = 1 << 0;
|
||||
|
|
@ -182,6 +179,13 @@ impl Drop for WlSeatGlobal {
|
|||
|
||||
impl WlSeatGlobal {
|
||||
pub fn new(name: GlobalName, seat_name: &str, state: &Rc<State>) -> Rc<Self> {
|
||||
let seat_xkb_state = state
|
||||
.default_keymap
|
||||
.state(state.keyboard_state_ids.next())
|
||||
.map(|s| Rc::new(RefCell::new(s)))
|
||||
.unwrap();
|
||||
let xkb_states = CopyHashMap::new();
|
||||
xkb_states.set(state.default_keymap.id, Rc::downgrade(&seat_xkb_state));
|
||||
let slf = Rc::new(Self {
|
||||
id: state.seat_ids.next(),
|
||||
name,
|
||||
|
|
@ -196,17 +200,15 @@ impl WlSeatGlobal {
|
|||
pointer_stack_modified: Cell::new(false),
|
||||
found_tree: RefCell::new(vec![]),
|
||||
keyboard_node: CloneCell::new(state.root.clone()),
|
||||
pressed_keys: RefCell::new(Default::default()),
|
||||
bindings: Default::default(),
|
||||
x_data_devices: Default::default(),
|
||||
data_devices: RefCell::new(Default::default()),
|
||||
primary_selection_devices: RefCell::new(Default::default()),
|
||||
repeat_rate: Cell::new((25, 250)),
|
||||
seat_kb_map: CloneCell::new(state.default_keymap.clone()),
|
||||
seat_kb_map_id: Cell::new(state.default_keymap.id),
|
||||
effective_kb_map: CloneCell::new(state.default_keymap.clone()),
|
||||
effective_kb_map_id: Cell::new(state.default_keymap.id),
|
||||
kb_state: RefCell::new(state.default_keymap.state().unwrap()),
|
||||
seat_xkb_state: CloneCell::new(seat_xkb_state.clone()),
|
||||
latest_kb_state: CloneCell::new(seat_xkb_state.clone()),
|
||||
xkb_states,
|
||||
cursor: Default::default(),
|
||||
tree_changed: Default::default(),
|
||||
selection: Default::default(),
|
||||
|
|
@ -228,7 +230,6 @@ impl WlSeatGlobal {
|
|||
idle_notifications: Default::default(),
|
||||
last_input_usec: Cell::new(now_usec()),
|
||||
wlr_data_devices: Default::default(),
|
||||
keymap_version: NumCell::new(1),
|
||||
});
|
||||
state.add_cursor_size(*DEFAULT_CURSOR_SIZE);
|
||||
let seat = slf.clone();
|
||||
|
|
@ -516,25 +517,49 @@ impl WlSeatGlobal {
|
|||
}
|
||||
|
||||
pub fn set_seat_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
||||
let Some(xkb_state) = self.get_xkb_state(keymap) else {
|
||||
return;
|
||||
};
|
||||
self.seat_kb_map.set(keymap.clone());
|
||||
self.seat_kb_map_id.set(keymap.id);
|
||||
let old = self.seat_xkb_state.set(xkb_state.clone());
|
||||
if !rc_eq(&old, &xkb_state) {
|
||||
self.handle_xkb_state_change(&old.borrow(), &xkb_state.borrow());
|
||||
}
|
||||
}
|
||||
|
||||
fn set_effective_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
||||
let state = match keymap.state() {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
log::error!("Could not create keymap state: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
fn handle_xkb_state_change(&self, old: &XkbState, new: &XkbState) {
|
||||
let Some(surface) = self.keyboard_node.get().node_into_surface() else {
|
||||
return;
|
||||
};
|
||||
self.keyboard_node.get().node_on_unfocus(self);
|
||||
self.effective_kb_map.set(keymap.clone());
|
||||
self.effective_kb_map_id.set(keymap.id);
|
||||
*self.kb_state.borrow_mut() = state;
|
||||
self.keymap_version.fetch_add(1);
|
||||
self.pressed_keys.borrow_mut().clear();
|
||||
self.keyboard_node.get().node_on_focus(self);
|
||||
let serial = surface.client.next_serial();
|
||||
self.surface_kb_event(Version::ALL, &surface, |kb| {
|
||||
if kb.kb_state_id() == old.kb_state.id {
|
||||
kb.send_leave(serial, surface.id);
|
||||
kb.enter(serial, surface.id, &new.kb_state);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_xkb_state(&self, keymap: &Rc<XkbKeymap>) -> Option<Rc<RefCell<XkbState>>> {
|
||||
if let Some(weak) = self.xkb_states.get(&keymap.id) {
|
||||
if let Some(state) = weak.upgrade() {
|
||||
return Some(state);
|
||||
}
|
||||
}
|
||||
self.xkb_states
|
||||
.lock()
|
||||
.retain(|_, state| state.strong_count() > 0);
|
||||
match keymap.state(self.state.keyboard_state_ids.next()) {
|
||||
Ok(s) => {
|
||||
let s = Rc::new(RefCell::new(s));
|
||||
self.xkb_states.set(keymap.id, Rc::downgrade(&s));
|
||||
Some(s)
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not create xkb state: {}", ErrorFmt(e));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_for_lock(self: &Rc<Self>) {
|
||||
|
|
@ -1146,19 +1171,19 @@ impl WlSeat {
|
|||
self.global.move_(node);
|
||||
}
|
||||
|
||||
pub fn keymap_fd(&self, keymap: &XkbKeymap) -> Result<Rc<OwnedFd>, WlKeyboardError> {
|
||||
pub fn keymap_fd(&self, state: &KeyboardState) -> Result<Rc<OwnedFd>, WlKeyboardError> {
|
||||
if self.version >= READ_ONLY_KEYMAP_SINCE {
|
||||
return Ok(keymap.map.clone());
|
||||
return Ok(state.map.clone());
|
||||
}
|
||||
let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) {
|
||||
Ok(fd) => fd,
|
||||
Err(e) => return Err(WlKeyboardError::KeymapMemfd(e.into())),
|
||||
};
|
||||
let target = keymap.map_len as c::off_t;
|
||||
let target = state.map_len as c::off_t;
|
||||
let mut pos = 0;
|
||||
while pos < target {
|
||||
let rem = target - pos;
|
||||
let res = uapi::sendfile(fd.raw(), keymap.map.raw(), Some(&mut pos), rem as usize);
|
||||
let res = uapi::sendfile(fd.raw(), state.map.raw(), Some(&mut pos), rem as usize);
|
||||
match res {
|
||||
Ok(_) | Err(Errno(c::EINTR)) => {}
|
||||
Err(e) => return Err(WlKeyboardError::KeymapCopy(e.into())),
|
||||
|
|
@ -1184,11 +1209,13 @@ impl WlSeatRequestHandler for WlSeat {
|
|||
track!(self.client, p);
|
||||
self.client.add_client_obj(&p)?;
|
||||
self.keyboards.set(req.id, p.clone());
|
||||
p.send_keymap();
|
||||
if let Some(surface) = self.global.keyboard_node.get().node_into_surface() {
|
||||
if surface.client.id == self.client.id {
|
||||
let serial = self.client.next_serial();
|
||||
p.send_enter(serial, surface.id, &self.global.pressed_keys.borrow())
|
||||
p.enter(
|
||||
self.client.next_serial(),
|
||||
surface.id,
|
||||
&self.global.seat_xkb_state.get().borrow().kb_state,
|
||||
);
|
||||
}
|
||||
}
|
||||
if self.version >= REPEAT_INFO_SINCE {
|
||||
|
|
@ -1269,3 +1296,51 @@ pub fn collect_kb_foci(node: Rc<dyn Node>) -> SmallVec<[Rc<WlSeatGlobal>; 3]> {
|
|||
collect_kb_foci2(node, &mut res);
|
||||
res
|
||||
}
|
||||
|
||||
impl DeviceHandlerData {
|
||||
pub fn set_seat(&self, seat: Option<Rc<WlSeatGlobal>>) {
|
||||
let old = self.seat.set(seat.clone());
|
||||
if let Some(old) = old {
|
||||
if let Some(new) = seat {
|
||||
if old.id() == new.id() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let xkb_state = self.get_effective_xkb_state(&old);
|
||||
let xkb_state = &mut *xkb_state.borrow_mut();
|
||||
xkb_state.reset();
|
||||
old.handle_xkb_state_change(xkb_state, xkb_state);
|
||||
}
|
||||
self.update_xkb_state();
|
||||
}
|
||||
|
||||
pub fn set_keymap(&self, keymap: Option<Rc<XkbKeymap>>) {
|
||||
self.keymap.set(keymap);
|
||||
self.update_xkb_state();
|
||||
}
|
||||
|
||||
fn get_effective_xkb_state(&self, seat: &WlSeatGlobal) -> Rc<RefCell<XkbState>> {
|
||||
match self.xkb_state.get() {
|
||||
Some(s) => s,
|
||||
_ => seat.seat_xkb_state.get(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_xkb_state(&self) {
|
||||
let Some(seat) = self.seat.get() else {
|
||||
self.xkb_state.take();
|
||||
return;
|
||||
};
|
||||
let old = self.get_effective_xkb_state(&seat);
|
||||
self.xkb_state.take();
|
||||
if let Some(keymap) = self.keymap.get() {
|
||||
if let Some(state) = seat.get_xkb_state(&keymap) {
|
||||
self.xkb_state.set(Some(state));
|
||||
}
|
||||
}
|
||||
let new = self.get_effective_xkb_state(&seat);
|
||||
if !rc_eq(&old, &new) {
|
||||
seat.handle_xkb_state_change(&old.borrow(), &new.borrow());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,15 +32,16 @@ use {
|
|||
tree::{Direction, FloatNode, Node, ToplevelNode},
|
||||
utils::{bitflags::BitflagsExt, smallmap::SmallMap},
|
||||
wire::WlDataOfferId,
|
||||
xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||
},
|
||||
isnt::std_1::primitive::IsntSlice2Ext,
|
||||
jay_config::keyboard::{
|
||||
mods::{Modifiers, CAPS, NUM},
|
||||
syms::KeySym,
|
||||
ModifiedKeySym,
|
||||
},
|
||||
smallvec::SmallVec,
|
||||
std::rc::Rc,
|
||||
std::{cell::RefCell, rc::Rc},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -196,20 +197,7 @@ impl WlSeatGlobal {
|
|||
time_usec,
|
||||
key,
|
||||
state,
|
||||
} => {
|
||||
let desired_kb_map_id = match dev.keymap_id.get() {
|
||||
Some(id) => id,
|
||||
None => self.seat_kb_map_id.get(),
|
||||
};
|
||||
if desired_kb_map_id != self.effective_kb_map_id.get() {
|
||||
let map = match dev.keymap.get() {
|
||||
Some(map) => map,
|
||||
None => self.seat_kb_map.get(),
|
||||
};
|
||||
self.set_effective_keymap(&map);
|
||||
}
|
||||
self.key_event(time_usec, key, state)
|
||||
}
|
||||
} => self.key_event(time_usec, key, state, || dev.get_effective_xkb_state(self)),
|
||||
InputEvent::ConnectorPosition {
|
||||
time_usec,
|
||||
connector,
|
||||
|
|
@ -356,18 +344,27 @@ impl WlSeatGlobal {
|
|||
self.pointer_owner.button(self, time_usec, button, state);
|
||||
}
|
||||
|
||||
pub(super) fn key_event(&self, time_usec: u64, key: u32, key_state: KeyState) {
|
||||
pub(super) fn key_event<F>(
|
||||
&self,
|
||||
time_usec: u64,
|
||||
key: u32,
|
||||
key_state: KeyState,
|
||||
mut get_state: F,
|
||||
) where
|
||||
F: FnMut() -> Rc<RefCell<XkbState>>,
|
||||
{
|
||||
let mut xkb_state_rc = get_state();
|
||||
let mut xkb_state = xkb_state_rc.borrow_mut();
|
||||
let (state, xkb_dir) = {
|
||||
let mut pk = self.pressed_keys.borrow_mut();
|
||||
match key_state {
|
||||
KeyState::Released => {
|
||||
if !pk.remove(&key) {
|
||||
if xkb_state.kb_state.pressed_keys.not_contains(&key) {
|
||||
return;
|
||||
}
|
||||
(wl_keyboard::RELEASED, XKB_KEY_UP)
|
||||
}
|
||||
KeyState::Pressed => {
|
||||
if !pk.insert(key) {
|
||||
if xkb_state.kb_state.pressed_keys.contains(&key) {
|
||||
return;
|
||||
}
|
||||
(wl_keyboard::PRESSED, XKB_KEY_DOWN)
|
||||
|
|
@ -377,10 +374,9 @@ impl WlSeatGlobal {
|
|||
let mut shortcuts = SmallVec::<[_; 1]>::new();
|
||||
let new_mods;
|
||||
{
|
||||
let mut kb_state = self.kb_state.borrow_mut();
|
||||
if !self.state.lock.locked.get() && state == wl_keyboard::PRESSED {
|
||||
let old_mods = kb_state.mods();
|
||||
let keysyms = kb_state.unmodified_keysyms(key);
|
||||
let old_mods = xkb_state.mods();
|
||||
let keysyms = xkb_state.unmodified_keysyms(key);
|
||||
for &sym in keysyms {
|
||||
let mods = old_mods.mods_effective & !(CAPS.0 | NUM.0);
|
||||
if let Some(mods) = self.shortcuts.get(&(mods, sym)) {
|
||||
|
|
@ -391,44 +387,42 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
}
|
||||
new_mods = kb_state.update(key, xkb_dir);
|
||||
new_mods = xkb_state.update(key, xkb_dir);
|
||||
}
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_key(self.id, time_usec, key, key_state);
|
||||
});
|
||||
let node = self.keyboard_node.get();
|
||||
if shortcuts.is_empty() {
|
||||
node.node_on_key(self, time_usec, key, state);
|
||||
node.node_on_key(self, time_usec, key, state, &xkb_state.kb_state);
|
||||
} else if let Some(config) = self.state.config.get() {
|
||||
let id = xkb_state.kb_state.id;
|
||||
drop(xkb_state);
|
||||
for shortcut in shortcuts {
|
||||
config.invoke_shortcut(self.id(), &shortcut);
|
||||
}
|
||||
xkb_state_rc = get_state();
|
||||
xkb_state = xkb_state_rc.borrow_mut();
|
||||
if id != xkb_state.kb_state.id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if let Some(mods) = new_mods {
|
||||
if new_mods {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_modifiers(self.id, &mods);
|
||||
t.send_modifiers(self.id, &xkb_state.kb_state.mods);
|
||||
});
|
||||
node.node_on_mods(self, mods);
|
||||
node.node_on_mods(self, &xkb_state.kb_state);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_modifiers(
|
||||
&self,
|
||||
mods_depressed: u32,
|
||||
mods_latched: u32,
|
||||
mods_locked: u32,
|
||||
group: u32,
|
||||
) {
|
||||
let new_mods =
|
||||
self.kb_state
|
||||
.borrow_mut()
|
||||
.set(mods_depressed, mods_latched, mods_locked, group);
|
||||
if let Some(mods) = new_mods {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_modifiers(self.id, &mods);
|
||||
});
|
||||
self.keyboard_node.get().node_on_mods(self, mods);
|
||||
match key_state {
|
||||
KeyState::Released => {
|
||||
xkb_state.kb_state.pressed_keys.remove(&key);
|
||||
}
|
||||
KeyState::Pressed => {
|
||||
xkb_state.kb_state.pressed_keys.insert(key);
|
||||
}
|
||||
}
|
||||
drop(xkb_state);
|
||||
self.latest_kb_state.set(xkb_state_rc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -578,7 +572,7 @@ impl WlSeatGlobal {
|
|||
});
|
||||
}
|
||||
|
||||
fn surface_kb_event<F>(&self, ver: Version, surface: &WlSurface, mut f: F)
|
||||
pub fn surface_kb_event<F>(&self, ver: Version, surface: &WlSurface, mut f: F)
|
||||
where
|
||||
F: FnMut(&Rc<WlKeyboard>),
|
||||
{
|
||||
|
|
@ -774,21 +768,11 @@ impl WlSeatGlobal {
|
|||
// Focus callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn focus_surface(&self, surface: &WlSurface) {
|
||||
let pressed_keys = &*self.pressed_keys.borrow();
|
||||
let kb_state = self.latest_kb_state.get();
|
||||
let kb_state = &*kb_state.borrow();
|
||||
let serial = surface.client.next_serial();
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_enter(serial, surface.id, pressed_keys)
|
||||
});
|
||||
let ModifierState {
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
..
|
||||
} = self.kb_state.borrow().mods();
|
||||
let serial = surface.client.next_serial();
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_modifiers(serial, mods_depressed, mods_latched, mods_locked, group)
|
||||
k.enter(serial, surface.id, kb_state);
|
||||
});
|
||||
|
||||
if self.keyboard_node.get().node_client_id() != Some(surface.client.id) {
|
||||
|
|
@ -806,27 +790,28 @@ impl WlSeatGlobal {
|
|||
|
||||
// Key callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn key_surface(&self, surface: &WlSurface, time_usec: u64, key: u32, state: u32) {
|
||||
pub fn key_surface(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
time_usec: u64,
|
||||
key: u32,
|
||||
state: u32,
|
||||
kb_state: &KeyboardState,
|
||||
) {
|
||||
let serial = surface.client.next_serial();
|
||||
let time = (time_usec / 1000) as _;
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_key(serial, time, key, state)
|
||||
k.on_key(serial, time, key, state, surface.id, kb_state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Modifiers callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn mods_surface(&self, surface: &WlSurface, mods: ModifierState) {
|
||||
pub fn mods_surface(&self, surface: &WlSurface, kb_state: &KeyboardState) {
|
||||
let serial = surface.client.next_serial();
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_modifiers(
|
||||
serial,
|
||||
mods.mods_depressed,
|
||||
mods.mods_latched,
|
||||
mods.mods_locked,
|
||||
mods.group,
|
||||
)
|
||||
k.on_mods_changed(serial, surface.id, kb_state)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ use {
|
|||
ifs::wl_seat::WlSeat,
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
utils::{errorfmt::ErrorFmt, numcell::NumCell, oserror::OsError},
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsError},
|
||||
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
||||
xkbcommon::{KeyboardState, KeyboardStateId, ModifierState},
|
||||
},
|
||||
std::rc::Rc,
|
||||
std::{cell::Cell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ pub const PRESSED: u32 = 1;
|
|||
pub struct WlKeyboard {
|
||||
id: WlKeyboardId,
|
||||
seat: Rc<WlSeat>,
|
||||
pub(super) keymap_version: NumCell<u32>,
|
||||
kb_state_id: Cell<KeyboardStateId>,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
|
|
@ -32,14 +33,33 @@ impl WlKeyboard {
|
|||
Self {
|
||||
id,
|
||||
seat: seat.clone(),
|
||||
keymap_version: NumCell::new(0),
|
||||
kb_state_id: Cell::new(KeyboardStateId::from_raw(0)),
|
||||
tracker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_keymap(&self) {
|
||||
let map = self.seat.global.effective_kb_map.get();
|
||||
let fd = match self.seat.keymap_fd(&map) {
|
||||
pub fn kb_state_id(&self) -> KeyboardStateId {
|
||||
self.kb_state_id.get()
|
||||
}
|
||||
|
||||
fn send_kb_state(
|
||||
&self,
|
||||
serial: u32,
|
||||
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!(
|
||||
|
|
@ -54,16 +74,20 @@ impl WlKeyboard {
|
|||
self_id: self.id,
|
||||
format: XKB_V1,
|
||||
fd,
|
||||
size: map.map_len as _,
|
||||
size: state.map_len as _,
|
||||
});
|
||||
self.keymap_version
|
||||
.set(self.seat.global.keymap_version.get());
|
||||
}
|
||||
|
||||
pub fn send_enter(self: &Rc<Self>, serial: u32, surface: WlSurfaceId, keys: &[u32]) {
|
||||
if self.keymap_version.get() != self.seat.global.keymap_version.get() {
|
||||
self.send_keymap();
|
||||
pub fn enter(&self, serial: u32, 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: u32, surface: WlSurfaceId, keys: &[u32]) {
|
||||
self.seat.client.event(Enter {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
@ -72,7 +96,7 @@ impl WlKeyboard {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn send_leave(self: &Rc<Self>, serial: u32, surface: WlSurfaceId) {
|
||||
pub fn send_leave(&self, serial: u32, surface: WlSurfaceId) {
|
||||
self.seat.client.event(Leave {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
@ -80,7 +104,22 @@ impl WlKeyboard {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn send_key(self: &Rc<Self>, serial: u32, time: u32, key: u32, state: u32) {
|
||||
pub fn on_key(
|
||||
&self,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
key: u32,
|
||||
state: u32,
|
||||
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: u32, time: u32, key: u32, state: u32) {
|
||||
self.seat.client.event(Key {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
@ -90,21 +129,22 @@ impl WlKeyboard {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn send_modifiers(
|
||||
self: &Rc<Self>,
|
||||
serial: u32,
|
||||
mods_depressed: u32,
|
||||
mods_latched: u32,
|
||||
mods_locked: u32,
|
||||
group: u32,
|
||||
) {
|
||||
pub fn on_mods_changed(&self, serial: u32, 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: u32, mods: &ModifierState) {
|
||||
self.seat.client.event(Modifiers {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
mods_depressed: mods.mods_depressed,
|
||||
mods_latched: mods.mods_latched,
|
||||
mods_locked: mods.mods_locked,
|
||||
group: mods.group,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ use {
|
|||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_virtual_keyboard_manager_v1::*, ZwpVirtualKeyboardManagerV1Id},
|
||||
xkbcommon::KeyboardState,
|
||||
},
|
||||
std::rc::Rc,
|
||||
std::{cell::RefCell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
|
@ -76,14 +77,20 @@ impl ZwpVirtualKeyboardManagerV1RequestHandler for ZwpVirtualKeyboardManagerV1 {
|
|||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let seat = self.client.lookup(req.seat)?;
|
||||
let seat_keymap = seat.global.seat_kb_map.get();
|
||||
let kb = Rc::new(ZwpVirtualKeyboardV1 {
|
||||
id: req.id,
|
||||
client: self.client.clone(),
|
||||
seat: seat.global.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
keymap_id: Default::default(),
|
||||
keymap: Default::default(),
|
||||
kb_state: Rc::new(RefCell::new(KeyboardState {
|
||||
id: self.client.state.keyboard_state_ids.next(),
|
||||
map: seat_keymap.map.clone(),
|
||||
map_len: seat_keymap.map_len,
|
||||
pressed_keys: Default::default(),
|
||||
mods: Default::default(),
|
||||
})),
|
||||
});
|
||||
track!(self.client, kb);
|
||||
self.client.add_client_obj(&kb)?;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::KeyState,
|
||||
client::{Client, ClientError},
|
||||
clientmem::{ClientMem, ClientMemError},
|
||||
ifs::wl_seat::{wl_keyboard, WlSeatGlobal},
|
||||
ifs::{
|
||||
wl_seat::{
|
||||
wl_keyboard::{self, WlKeyboard},
|
||||
WlSeatGlobal,
|
||||
},
|
||||
wl_surface::WlSurface,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
utils::clonecell::CloneCell,
|
||||
wire::{zwp_virtual_keyboard_v1::*, ZwpVirtualKeyboardV1Id},
|
||||
xkbcommon::{KeymapId, XkbCommonError, XkbKeymap},
|
||||
xkbcommon::{KeyboardState, XkbCommonError},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
std::{cell::RefCell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
|
@ -20,21 +24,21 @@ pub struct ZwpVirtualKeyboardV1 {
|
|||
pub seat: Rc<WlSeatGlobal>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub keymap_id: Cell<Option<KeymapId>>,
|
||||
pub keymap: CloneCell<Option<Rc<XkbKeymap>>>,
|
||||
pub kb_state: Rc<RefCell<KeyboardState>>,
|
||||
}
|
||||
|
||||
impl ZwpVirtualKeyboardV1 {
|
||||
fn ensure_keymap(&self) {
|
||||
if let Some(id) = self.keymap_id.get() {
|
||||
if id == self.seat.effective_kb_map_id.get() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let Some(keymap) = self.keymap.get() else {
|
||||
fn for_each_kb<F>(&self, mut f: F)
|
||||
where
|
||||
F: FnMut(u32, &WlSurface, &WlKeyboard),
|
||||
{
|
||||
let Some(surface) = self.seat.keyboard_node.get().node_into_surface() else {
|
||||
return;
|
||||
};
|
||||
self.seat.set_effective_keymap(&keymap);
|
||||
let serial = surface.client.next_serial();
|
||||
self.seat.surface_kb_event(Version::ALL, &surface, |kb| {
|
||||
f(serial, &surface, kb);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,31 +70,48 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
|
|||
.xkb_ctx
|
||||
.keymap_from_str(&map)
|
||||
.map_err(ZwpVirtualKeyboardV1Error::ParseKeymap)?;
|
||||
self.keymap_id.set(Some(map.id));
|
||||
self.keymap.set(Some(map));
|
||||
*self.kb_state.borrow_mut() = KeyboardState {
|
||||
id: self.client.state.keyboard_state_ids.next(),
|
||||
map: map.map.clone(),
|
||||
map_len: map.map_len,
|
||||
pressed_keys: Default::default(),
|
||||
mods: Default::default(),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.ensure_keymap();
|
||||
let time_usec = (req.time as u64) * 1000;
|
||||
let state = match req.state {
|
||||
wl_keyboard::RELEASED => KeyState::Released,
|
||||
wl_keyboard::PRESSED => KeyState::Pressed,
|
||||
let kb_state = &mut *self.kb_state.borrow_mut();
|
||||
let contains = kb_state.pressed_keys.contains(&req.key);
|
||||
let valid = match req.state {
|
||||
wl_keyboard::RELEASED => contains,
|
||||
wl_keyboard::PRESSED => !contains,
|
||||
_ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)),
|
||||
};
|
||||
self.seat.key_event(time_usec, req.key, state);
|
||||
if valid {
|
||||
self.for_each_kb(|serial, surface, kb| {
|
||||
kb.on_key(serial, req.time, req.key, req.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.set(self.kb_state.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modifiers(&self, req: Modifiers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.ensure_keymap();
|
||||
self.seat.set_modifiers(
|
||||
req.mods_depressed,
|
||||
req.mods_latched,
|
||||
req.mods_locked,
|
||||
req.group,
|
||||
);
|
||||
let kb_state = &mut *self.kb_state.borrow_mut();
|
||||
kb_state.mods.mods_depressed = req.mods_depressed;
|
||||
kb_state.mods.mods_latched = req.mods_latched;
|
||||
kb_state.mods.mods_locked = req.mods_locked;
|
||||
kb_state.mods.mods_effective = req.mods_depressed | req.mods_latched | req.mods_locked;
|
||||
kb_state.mods.group = req.group;
|
||||
self.for_each_kb(|serial, surface, kb| {
|
||||
kb.on_mods_changed(serial, surface.id, &kb_state);
|
||||
});
|
||||
self.seat.latest_kb_state.set(self.kb_state.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ use {
|
|||
wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id,
|
||||
ZwpLinuxDmabufFeedbackV1Id,
|
||||
},
|
||||
xkbcommon::ModifierState,
|
||||
xkbcommon::KeyboardState,
|
||||
xwayland::XWaylandEvent,
|
||||
},
|
||||
ahash::AHashMap,
|
||||
|
|
@ -1376,12 +1376,19 @@ impl Node for WlSurface {
|
|||
self.toplevel.get()
|
||||
}
|
||||
|
||||
fn node_on_key(&self, seat: &WlSeatGlobal, time_usec: u64, key: u32, state: u32) {
|
||||
seat.key_surface(self, time_usec, key, state);
|
||||
fn node_on_key(
|
||||
&self,
|
||||
seat: &WlSeatGlobal,
|
||||
time_usec: u64,
|
||||
key: u32,
|
||||
state: u32,
|
||||
kb_state: &KeyboardState,
|
||||
) {
|
||||
seat.key_surface(self, time_usec, key, state, kb_state);
|
||||
}
|
||||
|
||||
fn node_on_mods(&self, seat: &WlSeatGlobal, mods: ModifierState) {
|
||||
seat.mods_surface(self, mods);
|
||||
fn node_on_mods(&self, seat: &WlSeatGlobal, kb_state: &KeyboardState) {
|
||||
seat.mods_surface(self, kb_state);
|
||||
}
|
||||
|
||||
fn node_on_button(
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
mods.mods_locked,
|
||||
mods.group
|
||||
),
|
||||
(0, 0, 0, 0)
|
||||
(0, 0, 0, 1)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
12
src/state.rs
12
src/state.rs
|
|
@ -74,7 +74,7 @@ use {
|
|||
ExtForeignToplevelListV1Id, JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId,
|
||||
ZwpLinuxDmabufFeedbackV1Id,
|
||||
},
|
||||
xkbcommon::{KeymapId, XkbContext, XkbKeymap},
|
||||
xkbcommon::{KeyboardStateIds, XkbContext, XkbKeymap, XkbState},
|
||||
xwayland::{self, XWaylandEvent},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
|
|
@ -175,6 +175,7 @@ pub struct State {
|
|||
pub subsurface_ids: SubsurfaceIds,
|
||||
pub wait_for_sync_obj: Rc<WaitForSyncObj>,
|
||||
pub explicit_sync_enabled: Cell<bool>,
|
||||
pub keyboard_state_ids: KeyboardStateIds,
|
||||
}
|
||||
|
||||
// impl Drop for State {
|
||||
|
|
@ -244,15 +245,8 @@ pub struct DeviceHandlerData {
|
|||
pub device: Rc<dyn InputDevice>,
|
||||
pub syspath: Option<String>,
|
||||
pub devnode: Option<String>,
|
||||
pub keymap_id: Cell<Option<KeymapId>>,
|
||||
pub keymap: CloneCell<Option<Rc<XkbKeymap>>>,
|
||||
}
|
||||
|
||||
impl DeviceHandlerData {
|
||||
pub fn set_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
||||
self.keymap_id.set(Some(keymap.id));
|
||||
self.keymap.set(Some(keymap.clone()));
|
||||
}
|
||||
pub xkb_state: CloneCell<Option<Rc<RefCell<XkbState>>>>,
|
||||
}
|
||||
|
||||
pub struct ConnectorData {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
|
|||
device: dev.clone(),
|
||||
syspath: props.syspath,
|
||||
devnode: props.devnode,
|
||||
keymap_id: Default::default(),
|
||||
keymap: Default::default(),
|
||||
xkb_state: Default::default(),
|
||||
});
|
||||
let ae = Rc::new(AsyncEvent::default());
|
||||
let oh = DeviceHandler {
|
||||
|
|
@ -58,7 +58,7 @@ impl DeviceHandler {
|
|||
}
|
||||
for seat in self.state.globals.seats.lock().values() {
|
||||
if seat.seat_name() == DEFAULT_SEAT_NAME {
|
||||
self.data.seat.set(Some(seat.clone()));
|
||||
self.data.set_seat(Some(seat.clone()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
16
src/tree.rs
16
src/tree.rs
|
|
@ -10,7 +10,7 @@ use {
|
|||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
utils::numcell::NumCell,
|
||||
xkbcommon::ModifierState,
|
||||
xkbcommon::KeyboardState,
|
||||
},
|
||||
jay_config::Direction as JayDirection,
|
||||
std::{
|
||||
|
|
@ -158,16 +158,24 @@ pub trait Node: 'static {
|
|||
|
||||
// EVENT HANDLERS
|
||||
|
||||
fn node_on_key(&self, seat: &WlSeatGlobal, time_usec: u64, key: u32, state: u32) {
|
||||
fn node_on_key(
|
||||
&self,
|
||||
seat: &WlSeatGlobal,
|
||||
time_usec: u64,
|
||||
key: u32,
|
||||
state: u32,
|
||||
kb_state: &KeyboardState,
|
||||
) {
|
||||
let _ = seat;
|
||||
let _ = time_usec;
|
||||
let _ = key;
|
||||
let _ = state;
|
||||
let _ = kb_state;
|
||||
}
|
||||
|
||||
fn node_on_mods(&self, seat: &WlSeatGlobal, mods: ModifierState) {
|
||||
fn node_on_mods(&self, seat: &WlSeatGlobal, kb_state: &KeyboardState) {
|
||||
let _ = seat;
|
||||
let _ = mods;
|
||||
let _ = kb_state;
|
||||
}
|
||||
|
||||
fn node_on_button(
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ impl<T> Deref for VecSet<T> {
|
|||
}
|
||||
|
||||
impl<T> VecSet<T> {
|
||||
#[allow(dead_code)]
|
||||
pub fn clear(&mut self) {
|
||||
self.vec.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,18 @@ pub use consts::*;
|
|||
use {
|
||||
bstr::{BStr, ByteSlice},
|
||||
isnt::std_1::primitive::IsntConstPtrExt,
|
||||
std::{ffi::CStr, io::Write, ops::Deref, ptr, rc::Rc},
|
||||
std::{
|
||||
cell::{Ref, RefCell},
|
||||
ffi::CStr,
|
||||
io::Write,
|
||||
ops::Deref,
|
||||
ptr,
|
||||
rc::Rc,
|
||||
},
|
||||
};
|
||||
|
||||
use {
|
||||
crate::utils::{ptr_ext::PtrExt, trim::AsciiTrim},
|
||||
crate::utils::{errorfmt::ErrorFmt, ptr_ext::PtrExt, trim::AsciiTrim, vecset::VecSet},
|
||||
thiserror::Error,
|
||||
uapi::{c, OwnedFd},
|
||||
};
|
||||
|
|
@ -202,7 +209,7 @@ pub struct XkbKeymap {
|
|||
}
|
||||
|
||||
impl XkbKeymap {
|
||||
pub fn state(self: &Rc<Self>) -> Result<XkbState, XkbCommonError> {
|
||||
pub fn state(self: &Rc<Self>, id: KeyboardStateId) -> Result<XkbState, XkbCommonError> {
|
||||
let res = unsafe { xkb_state_new(self.keymap) };
|
||||
if res.is_null() {
|
||||
return Err(XkbCommonError::CreateState);
|
||||
|
|
@ -210,12 +217,12 @@ impl XkbKeymap {
|
|||
Ok(XkbState {
|
||||
map: self.clone(),
|
||||
state: res,
|
||||
mods: ModifierState {
|
||||
mods_depressed: 0,
|
||||
mods_latched: 0,
|
||||
mods_locked: 0,
|
||||
mods_effective: 0,
|
||||
group: 0,
|
||||
kb_state: KeyboardState {
|
||||
id,
|
||||
map: self.map.clone(),
|
||||
map_len: self.map_len,
|
||||
pressed_keys: Default::default(),
|
||||
mods: Default::default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -247,7 +254,7 @@ impl Drop for XkbKeymapStr {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct ModifierState {
|
||||
pub mods_depressed: u32,
|
||||
pub mods_latched: u32,
|
||||
|
|
@ -256,51 +263,90 @@ pub struct ModifierState {
|
|||
pub group: u32,
|
||||
}
|
||||
|
||||
linear_ids!(KeyboardStateIds, KeyboardStateId, u64);
|
||||
|
||||
pub struct KeyboardState {
|
||||
pub id: KeyboardStateId,
|
||||
pub map: Rc<OwnedFd>,
|
||||
pub map_len: usize,
|
||||
pub pressed_keys: VecSet<u32>,
|
||||
pub mods: ModifierState,
|
||||
}
|
||||
|
||||
pub trait DynKeyboardState {
|
||||
fn borrow(&self) -> Ref<'_, KeyboardState>;
|
||||
}
|
||||
|
||||
impl DynKeyboardState for RefCell<KeyboardState> {
|
||||
fn borrow(&self) -> Ref<'_, KeyboardState> {
|
||||
self.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XkbState {
|
||||
map: Rc<XkbKeymap>,
|
||||
state: *mut xkb_state,
|
||||
mods: ModifierState,
|
||||
pub kb_state: KeyboardState,
|
||||
}
|
||||
|
||||
impl DynKeyboardState for RefCell<XkbState> {
|
||||
fn borrow(&self) -> Ref<'_, KeyboardState> {
|
||||
Ref::map(self.borrow(), |v| &v.kb_state)
|
||||
}
|
||||
}
|
||||
|
||||
impl XkbState {
|
||||
pub fn mods(&self) -> ModifierState {
|
||||
self.mods
|
||||
self.kb_state.mods
|
||||
}
|
||||
|
||||
fn fetch(&mut self, changes: xkb_state_component) -> Option<ModifierState> {
|
||||
fn fetch(&mut self, changes: xkb_state_component) -> bool {
|
||||
unsafe {
|
||||
if changes != 0 {
|
||||
self.mods.mods_depressed =
|
||||
self.kb_state.mods.mods_depressed =
|
||||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_DEPRESSED.raw() as _);
|
||||
self.mods.mods_latched =
|
||||
self.kb_state.mods.mods_latched =
|
||||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LATCHED.raw() as _);
|
||||
self.mods.mods_locked =
|
||||
self.kb_state.mods.mods_locked =
|
||||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LOCKED.raw() as _);
|
||||
self.mods.mods_effective =
|
||||
self.mods.mods_depressed | self.mods.mods_latched | self.mods.mods_locked;
|
||||
self.mods.group =
|
||||
self.kb_state.mods.mods_effective = self.kb_state.mods.mods_depressed
|
||||
| self.kb_state.mods.mods_latched
|
||||
| self.kb_state.mods.mods_locked;
|
||||
self.kb_state.mods.group =
|
||||
xkb_state_serialize_layout(self.state, XKB_STATE_LAYOUT_EFFECTIVE.raw() as _);
|
||||
Some(self.mods)
|
||||
true
|
||||
} else {
|
||||
None
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, key: u32, direction: XkbKeyDirection) -> Option<ModifierState> {
|
||||
pub fn update(&mut self, key: u32, direction: XkbKeyDirection) -> bool {
|
||||
unsafe {
|
||||
let changes = xkb_state_update_key(self.state, key + 8, direction.raw() as _);
|
||||
self.fetch(changes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
let new_state = match self.map.state(self.kb_state.id) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
log::error!("Could not reset XKB state: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
};
|
||||
*self = new_state;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set(
|
||||
&mut self,
|
||||
mods_depressed: u32,
|
||||
mods_latched: u32,
|
||||
mods_locked: u32,
|
||||
group: u32,
|
||||
) -> Option<ModifierState> {
|
||||
) -> bool {
|
||||
unsafe {
|
||||
let changes = xkb_state_update_mask(
|
||||
self.state,
|
||||
|
|
@ -321,7 +367,7 @@ impl XkbState {
|
|||
let num = xkb_keymap_key_get_syms_by_level(
|
||||
self.map.keymap,
|
||||
key + 8,
|
||||
self.mods.group,
|
||||
self.kb_state.mods.group,
|
||||
0,
|
||||
&mut res,
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue