diff --git a/src/compositor.rs b/src/compositor.rs index 068f281e..3d3add14 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -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); diff --git a/src/config/handler.rs b/src/config/handler.rs index ad39226d..79a47237 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -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(()) } diff --git a/src/ifs/jay_input.rs b/src/ifs/jay_input.rs index 28617ee2..f9368f6e 100644 --- a/src/ifs/jay_input.rs +++ b/src/ifs/jay_input.rs @@ -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) -> 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) -> 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(()) }) } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index d4c7448e..04075381 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -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, found_tree: RefCell>, keyboard_node: CloneCell>, - pressed_keys: RefCell>, bindings: RefCell>>>, x_data_devices: SmallMap, 1>, data_devices: RefCell>>>, @@ -144,10 +143,9 @@ pub struct WlSeatGlobal { CopyHashMap<(ClientId, ZwlrDataControlDeviceV1Id), Rc>, repeat_rate: Cell<(i32, i32)>, seat_kb_map: CloneCell>, - seat_kb_map_id: Cell, - effective_kb_map: CloneCell>, - effective_kb_map_id: Cell, - kb_state: RefCell, + seat_xkb_state: CloneCell>>, + latest_kb_state: CloneCell>, + xkb_states: CopyHashMap>>, cursor: CloneCell>>, tree_changed: Rc, selection: CloneCell>>, @@ -168,7 +166,6 @@ pub struct WlSeatGlobal { constraint: CloneCell>>, idle_notifications: CopyHashMap<(ClientId, ExtIdleNotificationV1Id), Rc>, last_input_usec: Cell, - keymap_version: NumCell, } 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) -> Rc { + 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) { + 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 handle_xkb_state_change(&self, old: &XkbState, new: &XkbState) { + let Some(surface) = self.keyboard_node.get().node_into_surface() else { + return; + }; + 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); + } + }); } - fn set_effective_keymap(&self, keymap: &Rc) { - let state = match keymap.state() { - Ok(s) => s, + pub fn get_xkb_state(&self, keymap: &Rc) -> Option>> { + 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 keymap state: {}", ErrorFmt(e)); - return; + log::error!("Could not create xkb state: {}", ErrorFmt(e)); + None } - }; - 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); + } } pub fn prepare_for_lock(self: &Rc) { @@ -1146,19 +1171,19 @@ impl WlSeat { self.global.move_(node); } - pub fn keymap_fd(&self, keymap: &XkbKeymap) -> Result, WlKeyboardError> { + pub fn keymap_fd(&self, state: &KeyboardState) -> Result, 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) -> SmallVec<[Rc; 3]> { collect_kb_foci2(node, &mut res); res } + +impl DeviceHandlerData { + pub fn set_seat(&self, seat: Option>) { + 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>) { + self.keymap.set(keymap); + self.update_xkb_state(); + } + + fn get_effective_xkb_state(&self, seat: &WlSeatGlobal) -> Rc> { + 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()); + } + } +} diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 009c279f..f7328a65 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -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( + &self, + time_usec: u64, + key: u32, + key_state: KeyState, + mut get_state: F, + ) where + F: FnMut() -> Rc>, + { + 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(&self, ver: Version, surface: &WlSurface, mut f: F) + pub fn surface_kb_event(&self, ver: Version, surface: &WlSurface, mut f: F) where F: FnMut(&Rc), { @@ -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 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 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_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) }); } } diff --git a/src/ifs/wl_seat/wl_keyboard.rs b/src/ifs/wl_seat/wl_keyboard.rs index 091d9b39..b104404b 100644 --- a/src/ifs/wl_seat/wl_keyboard.rs +++ b/src/ifs/wl_seat/wl_keyboard.rs @@ -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, - pub(super) keymap_version: NumCell, + kb_state_id: Cell, pub tracker: Tracker, } @@ -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, 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, 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, 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, - 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, }) } diff --git a/src/ifs/wl_seat/zwp_virtual_keyboard_manager_v1.rs b/src/ifs/wl_seat/zwp_virtual_keyboard_manager_v1.rs index c92e50f9..717666ca 100644 --- a/src/ifs/wl_seat/zwp_virtual_keyboard_manager_v1.rs +++ b/src/ifs/wl_seat/zwp_virtual_keyboard_manager_v1.rs @@ -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, ) -> 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)?; diff --git a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs index ae86cbb5..2dde71f4 100644 --- a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs +++ b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs @@ -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, pub tracker: Tracker, pub version: Version, - pub keymap_id: Cell>, - pub keymap: CloneCell>>, + pub kb_state: Rc>, } 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(&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) -> 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) -> 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(()) } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 07a8940f..8e996c94 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -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( diff --git a/src/it/tests/t0040_virtual_keyboard.rs b/src/it/tests/t0040_virtual_keyboard.rs index 433f14bc..bf6519f2 100644 --- a/src/it/tests/t0040_virtual_keyboard.rs +++ b/src/it/tests/t0040_virtual_keyboard.rs @@ -110,7 +110,7 @@ async fn test(run: Rc) -> TestResult { mods.mods_locked, mods.group ), - (0, 0, 0, 0) + (0, 0, 0, 1) ); } diff --git a/src/state.rs b/src/state.rs index 0a5522c3..d99e9729 100644 --- a/src/state.rs +++ b/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, pub explicit_sync_enabled: Cell, + pub keyboard_state_ids: KeyboardStateIds, } // impl Drop for State { @@ -244,15 +245,8 @@ pub struct DeviceHandlerData { pub device: Rc, pub syspath: Option, pub devnode: Option, - pub keymap_id: Cell>, pub keymap: CloneCell>>, -} - -impl DeviceHandlerData { - pub fn set_keymap(&self, keymap: &Rc) { - self.keymap_id.set(Some(keymap.id)); - self.keymap.set(Some(keymap.clone())); - } + pub xkb_state: CloneCell>>>, } pub struct ConnectorData { diff --git a/src/tasks/input_device.rs b/src/tasks/input_device.rs index f32e8149..08857ad7 100644 --- a/src/tasks/input_device.rs +++ b/src/tasks/input_device.rs @@ -21,8 +21,8 @@ pub fn handle(state: &Rc, dev: Rc) { 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; } } diff --git a/src/tree.rs b/src/tree.rs index 975ff0b0..4946497d 100644 --- a/src/tree.rs +++ b/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( diff --git a/src/utils/vecset.rs b/src/utils/vecset.rs index 7333ec9b..8351e3b8 100644 --- a/src/utils/vecset.rs +++ b/src/utils/vecset.rs @@ -19,6 +19,7 @@ impl Deref for VecSet { } impl VecSet { + #[allow(dead_code)] pub fn clear(&mut self) { self.vec.clear(); } diff --git a/src/xkbcommon.rs b/src/xkbcommon.rs index c6c1531a..ab033913 100644 --- a/src/xkbcommon.rs +++ b/src/xkbcommon.rs @@ -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) -> Result { + pub fn state(self: &Rc, id: KeyboardStateId) -> Result { 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, + pub map_len: usize, + pub pressed_keys: VecSet, + pub mods: ModifierState, +} + +pub trait DynKeyboardState { + fn borrow(&self) -> Ref<'_, KeyboardState>; +} + +impl DynKeyboardState for RefCell { + fn borrow(&self) -> Ref<'_, KeyboardState> { + self.borrow() + } +} + pub struct XkbState { map: Rc, state: *mut xkb_state, - mods: ModifierState, + pub kb_state: KeyboardState, +} + +impl DynKeyboardState for RefCell { + 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 { + 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 { + 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 { + ) -> 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, );