diff --git a/build/enums.rs b/build/enums.rs index 7f904a7d..54c05db1 100644 --- a/build/enums.rs +++ b/build/enums.rs @@ -9,9 +9,6 @@ use { #[path = "../src/macros.rs"] mod macros; -#[path = "../src/xkbcommon/consts.rs"] -mod xkbcommon; - #[path = "../src/libinput/consts.rs"] mod libinput; @@ -141,21 +138,5 @@ pub fn main() -> anyhow::Result<()> { write_ty(&mut f, pango::CAIRO_OPERATORS, "cairo_operator_t")?; write_ty(&mut f, pango::PANGO_ELLIPSIZE_MODES, "PangoEllipsizeMode_")?; - let mut f = open("xkbcommon_tys.rs")?; - write_ty(&mut f, xkbcommon::XKB_LOG_LEVEL, "xkb_log_level")?; - write_ty(&mut f, xkbcommon::XKB_CONTEXT_FLAGS, "xkb_context_flags")?; - write_ty( - &mut f, - xkbcommon::XKB_KEYMAP_COMPILE_FLAGS, - "xkb_keymap_compile_flags", - )?; - write_ty(&mut f, xkbcommon::XKB_KEYMAP_FORMAT, "xkb_keymap_format")?; - write_ty( - &mut f, - xkbcommon::XKB_STATE_COMPONENT, - "xkb_state_component", - )?; - write_ty(&mut f, xkbcommon::XKB_KEY_DIRECTION, "xkb_key_direction")?; - Ok(()) } diff --git a/src/bridge.c b/src/bridge.c index 15390afc..337bb1a0 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -30,20 +30,3 @@ void jay_libinput_log_handler_bridge( jay_libinput_log_handler(libinput, priority, line); free(line); } - -void jay_xkbcommon_log_handler( - void *ctx, - int xkb_log_level, - const char *line -); - -void jay_xkbcommon_log_handler_bridge( - void *ctx, - int xkb_log_level, - const char *format, - va_list args -) { - char *line = fmt(format, args); - jay_xkbcommon_log_handler(ctx, xkb_log_level, line); - free(line); -} diff --git a/src/compositor.rs b/src/compositor.rs index 98a27dc6..28a9a905 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -26,6 +26,7 @@ use { workspace_manager::workspace_manager_done, }, io_uring::{IoUring, IoUringError}, + kbvm::KbvmContext, leaks, logger::Logger, output_schedule::OutputSchedule, @@ -49,7 +50,6 @@ use { version::VERSION, video::drm::wait_for_sync_obj::WaitForSyncObj, wheel::{Wheel, WheelError}, - xkbcommon::XkbContext, }, ahash::AHashSet, forker::ForkerProxy, @@ -139,8 +139,10 @@ fn start_compositor2( init_fd_limit(); leaks::init(); clientmem::init()?; - let xkb_ctx = XkbContext::new().unwrap(); - let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap(); + let kb_ctx = KbvmContext::default(); + let kb_keymap = kb_ctx + .parse_keymap(include_str!("keymap.xkb").as_bytes()) + .unwrap(); let engine = AsyncEngine::new(); let ring = IoUring::new(&engine, 32)?; let _signal_future = sighand::install(&engine, &ring)?; @@ -151,10 +153,10 @@ fn start_compositor2( scales.add(Scale::from_int(1)); let cpu_worker = Rc::new(CpuWorker::new(&ring, &engine)?); let state = Rc::new(State { - xkb_ctx, + kb_ctx, backend: CloneCell::new(Rc::new(DummyBackend)), forker: Default::default(), - default_keymap: xkb_keymap, + default_keymap: kb_keymap, eng: engine.clone(), render_ctx: Default::default(), drm_feedback: Default::default(), @@ -254,6 +256,7 @@ fn start_compositor2( wait_for_sync_obj: Rc::new(WaitForSyncObj::new(&ring, &engine)), explicit_sync_enabled: Cell::new(true), keyboard_state_ids: Default::default(), + physical_keyboard_ids: Default::default(), security_context_acceptors: Default::default(), cursor_user_group_ids: Default::default(), cursor_user_ids: Default::default(), diff --git a/src/config/handler.rs b/src/config/handler.rs index 2bf41700..0be9c0f8 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -10,6 +10,7 @@ use { format::config_formats, ifs::wl_seat::{SeatId, WlSeatGlobal}, io_uring::TaskResultExt, + kbvm::{KbvmError, KbvmMap}, output_schedule::map_cursor_hz, scale::Scale, state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State}, @@ -28,7 +29,6 @@ use { stack::Stack, timer::{TimerError, TimerFd}, }, - xkbcommon::{XkbCommonError, XkbKeymap}, }, bincode::Options, jay_config::{ @@ -73,7 +73,7 @@ pub(super) struct ConfigProxyHandler { pub handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize), pub state: Rc, pub next_id: NumCell, - pub keymaps: CopyHashMap>, + pub keymaps: CopyHashMap>, pub bufs: Stack>, pub workspace_ids: NumCell, @@ -180,7 +180,7 @@ impl ConfigProxyHandler { } fn handle_parse_keymap(&self, keymap: &str) -> Result<(), CphError> { - let (keymap, res) = match self.state.xkb_ctx.keymap_from_str(keymap) { + let (keymap, res) = match self.state.kb_ctx.parse_keymap(keymap.as_bytes()) { Ok(keymap) => { let id = Keymap(self.id()); self.keymaps.set(id, keymap); @@ -594,7 +594,7 @@ impl ConfigProxyHandler { } } - fn get_keymap(&self, keymap: Keymap) -> Result, CphError> { + fn get_keymap(&self, keymap: Keymap) -> Result, CphError> { match self.keymaps.get(&keymap) { Some(k) => Ok(k), None => Err(CphError::KeymapDoesNotExist(keymap)), @@ -2007,7 +2007,7 @@ enum CphError { #[error("Repeat delay is negative")] NegativeRepeatDelay, #[error("Parsing failed")] - ParseKeymapError(#[from] XkbCommonError), + ParseKeymapError(#[from] KbvmError), #[error("Device {0:?} does not exist")] DeviceDoesNotExist(InputDevice), #[error("Connector {0:?} does not exist")] diff --git a/src/ei/ei_ifs/ei_connection.rs b/src/ei/ei_ifs/ei_connection.rs index 510995a3..88270e38 100644 --- a/src/ei/ei_ifs/ei_connection.rs +++ b/src/ei/ei_ifs/ei_connection.rs @@ -64,9 +64,9 @@ impl EiConnection { if version == EiVersion(0) { return; } - let xkb_state_id = match self.context() { - EiContext::Sender => seat.seat_xkb_state().borrow().id, - EiContext::Receiver => seat.latest_xkb_state().borrow().id, + let kb_state_id = match self.context() { + EiContext::Sender => seat.seat_kb_state().borrow().id, + EiContext::Receiver => seat.latest_kb_state().borrow().id, }; let seat = Rc::new(EiSeat { id: self.client.new_id(), @@ -75,7 +75,8 @@ impl EiConnection { version, seat: seat.clone(), capabilities: Cell::new(0), - kb_state_id: Cell::new(xkb_state_id), + kb_state_id: Cell::new(kb_state_id), + keyboard_id: self.client.state.physical_keyboard_ids.next(), device: Default::default(), pointer: Default::default(), pointer_absolute: Default::default(), diff --git a/src/ei/ei_ifs/ei_device.rs b/src/ei/ei_ifs/ei_device.rs index 031b1541..4c09e11e 100644 --- a/src/ei/ei_ifs/ei_device.rs +++ b/src/ei/ei_ifs/ei_device.rs @@ -189,7 +189,8 @@ impl EiDeviceRequestHandler for EiDevice { seat.button_event(time, button, pressed); } while let Some((button, pressed)) = self.key_changes.pop() { - seat.key_event_with_seat_state(time, button, pressed); + let phy = seat.get_physical_keyboard(self.seat.keyboard_id, None); + phy.phy_state.update(time, seat, button, pressed); } if let Some((x, y)) = self.relative_motion.take() { let x = Fixed::from_f32(x); diff --git a/src/ei/ei_ifs/ei_seat.rs b/src/ei/ei_ifs/ei_seat.rs index f6900f6c..e7c016a7 100644 --- a/src/ei/ei_ifs/ei_seat.rs +++ b/src/ei/ei_ifs/ei_seat.rs @@ -16,7 +16,7 @@ use { EiContext, }, fixed::Fixed, - ifs::wl_seat::{wl_pointer::PendingScroll, WlSeatGlobal}, + ifs::wl_seat::{wl_pointer::PendingScroll, PhysicalKeyboardId, WlSeatGlobal}, keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId}, leaks::Tracker, tree::Node, @@ -49,6 +49,7 @@ pub struct EiSeat { pub seat: Rc, pub capabilities: Cell, pub kb_state_id: Cell, + pub keyboard_id: PhysicalKeyboardId, pub device: CloneCell>>, pub pointer: CloneCell>>, @@ -75,7 +76,11 @@ impl EiSeat { } } - pub fn handle_xkb_state_change(self: &Rc, old_id: KeyboardStateId, new: &KeyboardState) { + pub fn handle_keyboard_state_change( + self: &Rc, + old_id: KeyboardStateId, + new: &KeyboardState, + ) { if self.keyboard.is_none() { return; } @@ -94,7 +99,7 @@ impl EiSeat { if self.is_sender() { return; } - self.handle_xkb_state_change(old_id, state); + self.handle_keyboard_state_change(old_id, state); return; } if let Some(kb) = self.keyboard.get() { @@ -114,7 +119,7 @@ impl EiSeat { } let old_id = self.kb_state_id.get(); if old_id != kb_state.id { - self.handle_xkb_state_change(old_id, kb_state); + self.handle_keyboard_state_change(old_id, kb_state); } if let Some(kb) = self.keyboard.get() { kb.send_key(key, state); @@ -298,8 +303,8 @@ impl EiSeat { fn get_kb_state(&self) -> Rc { match self.context() { - EiContext::Sender => self.seat.seat_xkb_state(), - EiContext::Receiver => self.seat.latest_xkb_state(), + EiContext::Sender => self.seat.seat_kb_state(), + EiContext::Receiver => self.seat.latest_kb_state(), } } diff --git a/src/ifs/jay_input.rs b/src/ifs/jay_input.rs index 02b783a8..8c9f5513 100644 --- a/src/ifs/jay_input.rs +++ b/src/ifs/jay_input.rs @@ -4,6 +4,7 @@ use { client::{Client, ClientError}, clientmem::{ClientMem, ClientMemError}, ifs::wl_seat::WlSeatGlobal, + kbvm::{KbvmError, KbvmMap}, leaks::Tracker, libinput::consts::{ AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, @@ -13,7 +14,6 @@ use { state::{DeviceHandlerData, InputDeviceData}, utils::errorfmt::ErrorFmt, wire::{jay_input::*, JayInputId}, - xkbcommon::{XkbCommonError, XkbKeymap}, }, std::rc::Rc, thiserror::Error, @@ -72,7 +72,7 @@ impl JayInput { }); } - fn send_keymap(&self, map: &XkbKeymap) { + fn send_keymap(&self, map: &KbvmMap) { self.client.event(Keymap { self_id: self.id, keymap: map.map.clone(), @@ -167,7 +167,7 @@ impl JayInput { fn set_keymap_impl(&self, keymap: &Rc, len: u32, f: F) -> Result<(), JayInputError> where - F: FnOnce(&Rc) -> Result<(), JayInputError>, + F: FnOnce(&Rc) -> Result<(), JayInputError>, { let cm = Rc::new(ClientMem::new_private( keymap, @@ -180,7 +180,7 @@ impl JayInput { let mut map = vec![]; cm.read(&mut map)?; self.or_error(|| { - let map = self.client.state.xkb_ctx.keymap_from_str(&map)?; + let map = self.client.state.kb_ctx.parse_keymap(&map)?; f(&map)?; Ok(()) }) @@ -489,7 +489,7 @@ pub enum JayInputError { #[error("Could not access client memory")] ClientMemError(#[from] ClientMemError), #[error("Could not parse keymap")] - XkbCommonError(#[from] XkbCommonError), + ParseKeymap(#[from] KbvmError), #[error("Output is not connected")] OutputNotConnected, } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index dacbb9db..aa392568 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -72,7 +72,8 @@ use { }, xdg_toplevel_drag_v1::XdgToplevelDragV1, }, - keyboard::{DynKeyboardState, KeyboardState}, + kbvm::{KbvmMap, KbvmMapId, KbvmState, PhysicalKeyboardState}, + keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId}, leaks::Tracker, object::{Object, Version}, rect::Rect, @@ -83,8 +84,8 @@ use { }, utils::{ asyncevent::AsyncEvent, bindings::PerClientBindings, clonecell::CloneCell, - copyhashmap::CopyHashMap, errorfmt::ErrorFmt, linkedlist::LinkedNode, numcell::NumCell, - rc_eq::rc_eq, smallmap::SmallMap, + copyhashmap::CopyHashMap, linkedlist::LinkedNode, numcell::NumCell, rc_eq::rc_eq, + smallmap::SmallMap, }, wire::{ wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId, @@ -92,7 +93,6 @@ use { ZwpTextInputV3Id, }, wire_ei::EiSeatId, - xkbcommon::{KeymapId, XkbKeymap, XkbState}, }, ahash::AHashMap, smallvec::SmallVec, @@ -144,6 +144,13 @@ impl Drop for DroppedDnd { } } +linear_ids!(PhysicalKeyboardIds, PhysicalKeyboardId, u64); + +pub struct PhysicalKeyboard { + has_custom_map: Cell, + pub phy_state: PhysicalKeyboardState, +} + linear_ids!(SeatIds, SeatId); pub struct WlSeatGlobal { @@ -169,10 +176,12 @@ pub struct WlSeatGlobal { >, data_control_devices: CopyHashMap>, repeat_rate: Cell<(i32, i32)>, - seat_kb_map: CloneCell>, - seat_xkb_state: CloneCell>>, + seat_kb_map: CloneCell>, + seat_kb_state: CloneCell>>, latest_kb_state: CloneCell>, - xkb_states: CopyHashMap>>, + latest_kb_state_id: Cell, + kb_states: CopyHashMap>>, + kb_devices: CopyHashMap>, cursor_user_group: Rc, pointer_cursor: Rc, tree_changed: Rc, @@ -214,13 +223,11 @@ const CHANGE_TREE: u32 = 1 << 1; 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 seat_kb_state = state.default_keymap.state(state.keyboard_state_ids.next()); + let latest_kb_state_id = seat_kb_state.kb_state.id; + let seat_kb_state = Rc::new(RefCell::new(seat_kb_state)); + let kb_states = CopyHashMap::new(); + kb_states.set(state.default_keymap.id, Rc::downgrade(&seat_kb_state)); let cursor_user_group = CursorUserGroup::create(state); let cursor_user = cursor_user_group.create_user(); cursor_user.activate(); @@ -243,9 +250,11 @@ impl WlSeatGlobal { primary_selection_devices: RefCell::new(Default::default()), repeat_rate: Cell::new((25, 250)), seat_kb_map: CloneCell::new(state.default_keymap.clone()), - seat_xkb_state: CloneCell::new(seat_xkb_state.clone()), - latest_kb_state: CloneCell::new(seat_xkb_state.clone()), - xkb_states, + seat_kb_state: CloneCell::new(seat_kb_state.clone()), + latest_kb_state: CloneCell::new(seat_kb_state.clone()), + latest_kb_state_id: Cell::new(latest_kb_state_id), + kb_states, + kb_devices: Default::default(), cursor_user_group, pointer_cursor: cursor_user, tree_changed: Default::default(), @@ -318,7 +327,7 @@ impl WlSeatGlobal { } } - pub fn keymap(&self) -> Rc { + pub fn keymap(&self) -> Rc { self.seat_kb_map.get() } @@ -496,53 +505,46 @@ impl WlSeatGlobal { false } - pub fn set_seat_keymap(&self, keymap: &Rc) { - let Some(xkb_state) = self.get_xkb_state(keymap) else { - return; - }; + pub fn set_seat_keymap(&self, keymap: &Rc) { self.seat_kb_map.set(keymap.clone()); - 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()); + let new = self.get_kb_state(keymap); + let old = self.seat_kb_state.set(new.clone()); + if rc_eq(&old, &new) { + return; } + self.kb_devices.lock().retain(|_, p| p.has_custom_map.get()); + self.handle_keyboard_state_change(&old.borrow().kb_state, &new.borrow().kb_state); } - fn handle_xkb_state_change(&self, old: &XkbState, new: &XkbState) { + fn handle_keyboard_state_change(&self, old: &KeyboardState, new: &KeyboardState) { self.for_each_ei_seat(|ei_seat| { - ei_seat.handle_xkb_state_change(old.kb_state.id, &new.kb_state); + ei_seat.handle_keyboard_state_change(old.id, new); }); 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 { + if kb.kb_state_id() == old.id { kb.send_leave(serial, surface.id); - kb.enter(serial, surface.id, &new.kb_state); + kb.enter(serial, surface.id, new); } }); } - pub fn get_xkb_state(&self, keymap: &Rc) -> Option>> { - if let Some(weak) = self.xkb_states.get(&keymap.id) { + pub fn get_kb_state(&self, keymap: &Rc) -> Rc> { + if let Some(weak) = self.kb_states.get(&keymap.id) { if let Some(state) = weak.upgrade() { - return Some(state); + return state; } } - self.xkb_states + self.kb_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 - } - } + let s = keymap.state(self.state.keyboard_state_ids.next()); + let s = Rc::new(RefCell::new(s)); + self.kb_states.set(keymap.id, Rc::downgrade(&s)); + s } pub fn prepare_for_lock(self: &Rc) { @@ -1031,16 +1033,17 @@ impl WlSeatGlobal { self.update_capabilities(); } - pub fn remove_ei_seat(&self, ei: &EiSeat) { + pub fn remove_ei_seat(self: &Rc, ei: &EiSeat) { self.ei_seats.remove(&(ei.client.id, ei.id)); + self.destroy_physical_keyboard(ei.keyboard_id); self.update_capabilities(); } - pub fn seat_xkb_state(&self) -> Rc { - self.seat_xkb_state.get() + pub fn seat_kb_state(&self) -> Rc { + self.seat_kb_state.get() } - pub fn latest_xkb_state(&self) -> Rc { + pub fn latest_kb_state(&self) -> Rc { self.latest_kb_state.get() } @@ -1091,6 +1094,33 @@ impl WlSeatGlobal { } self.focus_node_with_serial(node, serial); } + + pub fn get_physical_keyboard( + &self, + id: PhysicalKeyboardId, + map: Option<&Rc>, + ) -> Rc { + if let Some(d) = self.kb_devices.get(&id) { + return d; + } + let state = match map { + Some(m) => self.get_kb_state(m), + _ => self.get_kb_state(&self.seat_kb_map.get()), + }; + let d = Rc::new(PhysicalKeyboard { + has_custom_map: Cell::new(map.is_some()), + phy_state: PhysicalKeyboardState::new(&state), + }); + self.kb_devices.set(id, d.clone()); + d + } + + pub fn destroy_physical_keyboard(self: &Rc, id: PhysicalKeyboardId) { + let Some(kb) = self.kb_devices.remove(&id) else { + return; + }; + kb.phy_state.destroy(self.state.now_usec(), self); + } } impl CursorUserOwner for WlSeatGlobal { @@ -1178,7 +1208,7 @@ impl WlSeatRequestHandler for WlSeat { p.enter( self.client.next_serial(), surface.id, - &self.global.seat_xkb_state.get().borrow().kb_state, + &self.global.seat_kb_state.get().borrow().kb_state, ); } } @@ -1265,17 +1295,20 @@ pub fn collect_kb_foci(node: Rc) -> SmallVec<[Rc; 3]> { 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 let Some(new) = &seat { + if let Some(old) = self.seat.get() { 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); + } else { + if self.seat.is_none() { + return; + } + } + self.destroy_physical_keyboard_state(); + let old = self.seat.set(seat.clone()); + if let Some(old) = old { if let Some(info) = &self.tablet_init { old.tablet_remove_tablet(info.id); } @@ -1287,7 +1320,6 @@ impl DeviceHandlerData { old.update_capabilities(); } } - self.update_xkb_state(); if let Some(seat) = &seat { if let Some(info) = &self.tablet_init { seat.tablet_add_tablet(self.device.id(), info); @@ -1302,34 +1334,15 @@ impl DeviceHandlerData { } } - 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; + fn destroy_physical_keyboard_state(&self) { + if let Some(seat) = self.seat.get() { + seat.destroy_physical_keyboard(self.keyboard_id); }; - 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()); - } + } + + pub fn set_keymap(&self, keymap: Option>) { + self.destroy_physical_keyboard_state(); + self.keymap.set(keymap); } pub fn set_output(&self, output: Option<&WlOutputGlobal>) { diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index d5fd2944..ed720292 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -33,16 +33,19 @@ use { }, wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface}, }, + kbvm::KbvmState, keyboard::KeyboardState, object::Version, rect::Rect, state::DeviceHandlerData, tree::{Direction, Node, ToplevelNode}, - utils::{bitflags::BitflagsExt, hash_map_ext::HashMapExt, smallmap::SmallMap}, + utils::{ + bitflags::BitflagsExt, hash_map_ext::HashMapExt, smallmap::SmallMap, + syncqueue::SyncQueue, + }, wire::WlDataOfferId, - xkbcommon::{XkbState, XKB_KEY_DOWN, XKB_KEY_UP}, }, - isnt::std_1::primitive::{IsntSlice2Ext, IsntSliceExt}, + isnt::std_1::primitive::IsntSliceExt, jay_config::{ input::SwitchEvent, keyboard::{ @@ -50,8 +53,9 @@ use { syms::{KeySym, SYM_Escape}, }, }, + kbvm::{state_machine::Event, ModifierMask}, smallvec::SmallVec, - std::{cell::RefCell, collections::hash_map::Entry, rc::Rc}, + std::{cell::RefCell, collections::hash_map::Entry, mem, rc::Rc}, }; #[derive(Default)] @@ -320,7 +324,11 @@ impl WlSeatGlobal { time_usec, key, state, - } => self.key_event(time_usec, key, state, || dev.get_effective_xkb_state(self)), + } => { + self.get_physical_keyboard(dev.keyboard_id, dev.keymap.get().as_ref()) + .phy_state + .update(time_usec, self, key, state); + } InputEvent::ConnectorPosition { time_usec, connector, @@ -779,130 +787,129 @@ impl WlSeatGlobal { self.touch_owner.frame(self); } - pub fn key_event_with_seat_state( + pub fn key_events( self: &Rc, time_usec: u64, - key: u32, - key_state: KeyState, + events: &SyncQueue, + kbvm_state_rc: &Rc>, ) { - self.key_event(time_usec, key, key_state, || self.seat_xkb_state.get()); - } - - pub(super) fn key_event( - self: &Rc, - 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) = { - match key_state { - KeyState::Released => { - if xkb_state.kb_state.pressed_keys.not_contains(&key) { - return; - } - (wl_keyboard::RELEASED, XKB_KEY_UP) - } - KeyState::Pressed => { - if xkb_state.kb_state.pressed_keys.contains(&key) { - return; - } - (wl_keyboard::PRESSED, XKB_KEY_DOWN) - } - } - }; + let mut kbvm_state = kbvm_state_rc.borrow_mut(); + self.latest_kb_state.set(kbvm_state_rc.clone()); + self.latest_kb_state_id.set(kbvm_state.kb_state.id); let mut shortcuts = SmallVec::<[_; 1]>::new(); - let new_mods; - { - let mut mods = xkb_state.mods().mods.0 & !(CAPS.0 | NUM.0); - if state == wl_keyboard::RELEASED { - mods |= RELEASE.0; - } - let scs = &*self.shortcuts.borrow(); - let keysyms = xkb_state.unmodified_keysyms(key); - let mut revert_pointer_to_default = false; - for &sym in keysyms { - if sym == SYM_Escape.0 && mods == 0 { - revert_pointer_to_default = true; + let mut components_changed = false; + while let Some(event) = events.pop() { + components_changed |= kbvm_state.kb_state.mods.apply_event(event); + let (key_state, kc) = match event { + Event::KeyDown(kc) => (KeyState::Pressed, kc), + Event::KeyUp(kc) => (KeyState::Released, kc), + _ => continue, + }; + let update_pressed_keys = |kbvm_state: &mut KbvmState| { + let pk = &mut kbvm_state.kb_state.pressed_keys; + match key_state { + KeyState::Released => pk.remove(&kc.to_evdev()), + KeyState::Pressed => pk.insert(kc.to_evdev()), } - if !self.state.lock.locked.get() { - if let Some(key_mods) = scs.get(&sym) { - for (key_mods, mask) in key_mods { - if mods & mask == key_mods { - shortcuts.push(InvokedShortcut { - unmasked_mods: Modifiers(mods), - effective_mods: Modifiers(key_mods), - sym: KeySym(sym), - }); + }; + shortcuts.clear(); + { + let mut mods = kbvm_state.kb_state.mods.mods.0 & !(CAPS.0 | NUM.0); + if key_state == KeyState::Released { + mods |= RELEASE.0; + } + let scs = &*self.shortcuts.borrow(); + let keysyms = kbvm_state.map.lookup_table.lookup( + kbvm_state.kb_state.mods.group, + ModifierMask::default(), + kc, + ); + let mut revert_pointer_to_default = false; + for props in keysyms { + let sym = props.keysym().0; + if sym == SYM_Escape.0 && mods == 0 { + revert_pointer_to_default = true; + } + if !self.state.lock.locked.get() { + if let Some(key_mods) = scs.get(&sym) { + for (key_mods, mask) in key_mods { + if mods & mask == key_mods { + shortcuts.push(InvokedShortcut { + unmasked_mods: Modifiers(mods), + effective_mods: Modifiers(key_mods), + sym: KeySym(sym), + }); + } } } } } - } - if revert_pointer_to_default { - drop(xkb_state); - self.pointer_owner.revert_to_default(self); - xkb_state = xkb_state_rc.borrow_mut(); - } - 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(); - let input_method_grab = self.input_method_grab.get(); - let mut forward = true; - if shortcuts.is_not_empty() { - self.forward.set(state == wl_keyboard::RELEASED); - 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 revert_pointer_to_default { + drop(kbvm_state); + self.pointer_owner.revert_to_default(self); + kbvm_state = kbvm_state_rc.borrow_mut(); } } - forward = self.forward.get(); - } - if forward { - match &input_method_grab { - Some(g) => g.on_key(time_usec, key, state, &xkb_state.kb_state), - _ => node.node_on_key(self, time_usec, key, state, &xkb_state.kb_state), - } - self.for_each_ei_seat(|ei_seat| { - ei_seat.handle_key(time_usec, key, state, &xkb_state.kb_state); - }); - } - if new_mods { - self.for_each_ei_seat(|ei_seat| { - ei_seat.handle_modifiers_changed(&xkb_state.kb_state); - }); self.state.for_each_seat_tester(|t| { - t.send_modifiers(self.id, &xkb_state.kb_state.mods); + t.send_key(self.id, time_usec, kc.to_evdev(), key_state); }); - match &input_method_grab { - Some(g) => g.on_modifiers(&xkb_state.kb_state), - _ => node.node_on_mods(self, &xkb_state.kb_state), + if shortcuts.is_not_empty() { + self.forward.set(key_state == KeyState::Released); + if let Some(config) = self.state.config.get() { + drop(kbvm_state); + for shortcut in &shortcuts { + config.invoke_shortcut(self.id(), shortcut); + } + kbvm_state = kbvm_state_rc.borrow_mut(); + if kbvm_state.kb_state.id != self.latest_kb_state_id.get() { + update_pressed_keys(&mut kbvm_state); + kbvm_state.apply_events(events); + return; + } + } + if !self.forward.get() { + update_pressed_keys(&mut kbvm_state); + continue; + } } + self.send_components(&mut components_changed, &kbvm_state); + let state = match key_state { + KeyState::Released => wl_keyboard::RELEASED, + KeyState::Pressed => wl_keyboard::PRESSED, + }; + match self.input_method_grab.get() { + Some(g) => g.on_key(time_usec, kc.to_evdev(), state, &kbvm_state.kb_state), + _ => self.keyboard_node.get().node_on_key( + self, + time_usec, + kc.to_evdev(), + state, + &kbvm_state.kb_state, + ), + } + self.for_each_ei_seat(|ei_seat| { + ei_seat.handle_key(time_usec, kc.to_evdev(), state, &kbvm_state.kb_state); + }); + update_pressed_keys(&mut kbvm_state); } - match key_state { - KeyState::Released => { - xkb_state.kb_state.pressed_keys.remove(&key); - } - KeyState::Pressed => { - xkb_state.kb_state.pressed_keys.insert(key); - } + self.send_components(&mut components_changed, &kbvm_state); + } + + fn send_components(&self, components_changed: &mut bool, kbvm_state: &KbvmState) { + if !mem::take(components_changed) { + return; + } + let kb_state = &kbvm_state.kb_state; + self.for_each_ei_seat(|ei_seat| { + ei_seat.handle_modifiers_changed(kb_state); + }); + self.state.for_each_seat_tester(|t| { + t.send_modifiers(self.id, &kb_state.mods); + }); + match self.input_method_grab.get() { + Some(g) => g.on_modifiers(kb_state), + _ => self.keyboard_node.get().node_on_mods(self, kb_state), } - drop(xkb_state); - self.latest_kb_state.set(xkb_state_rc); } pub(super) fn for_each_ei_seat(&self, mut f: impl FnMut(&Rc)) { diff --git a/src/ifs/wl_seat/wl_keyboard.rs b/src/ifs/wl_seat/wl_keyboard.rs index 08c206c7..55c4b8de 100644 --- a/src/ifs/wl_seat/wl_keyboard.rs +++ b/src/ifs/wl_seat/wl_keyboard.rs @@ -2,12 +2,11 @@ use { crate::{ client::ClientError, ifs::wl_seat::WlSeat, - keyboard::{KeyboardState, KeyboardStateId}, + keyboard::{KeyboardError, KeyboardState, KeyboardStateId}, leaks::Tracker, object::{Object, Version}, utils::errorfmt::ErrorFmt, wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId}, - xkbcommon::XkbCommonError, }, kbvm::Components, std::{cell::Cell, rc::Rc}, @@ -183,6 +182,6 @@ pub enum WlKeyboardError { #[error(transparent)] ClientError(Box), #[error(transparent)] - XkbCommonError(#[from] XkbCommonError), + KeyboardError(#[from] KeyboardError), } efrom!(WlKeyboardError, ClientError); diff --git a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs index 5605cfe5..09c6f276 100644 --- a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs +++ b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs @@ -9,11 +9,11 @@ use { }, wl_surface::WlSurface, }, + kbvm::KbvmError, keyboard::KeyboardState, leaks::Tracker, object::{Object, Version}, wire::{zwp_virtual_keyboard_v1::*, ZwpVirtualKeyboardV1Id}, - xkbcommon::XkbCommonError, }, std::{cell::RefCell, rc::Rc}, thiserror::Error, @@ -74,8 +74,8 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 { let map = self .client .state - .xkb_ctx - .keymap_from_str(&map) + .kb_ctx + .parse_keymap(&map) .map_err(ZwpVirtualKeyboardV1Error::ParseKeymap)?; *self.kb_state.borrow_mut() = KeyboardState { id: self.client.state.keyboard_state_ids.next(), @@ -103,6 +103,7 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 { 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(()) @@ -118,6 +119,7 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 { 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(()) } @@ -154,6 +156,6 @@ pub enum ZwpVirtualKeyboardV1Error { #[error("Could not read the keymap")] ReadKeymap(#[source] ClientMemError), #[error("Could not parse the keymap")] - ParseKeymap(#[source] XkbCommonError), + ParseKeymap(#[source] KbvmError), } efrom!(ZwpVirtualKeyboardV1Error, ClientError); diff --git a/src/it/tests/t0040_virtual_keyboard.rs b/src/it/tests/t0040_virtual_keyboard.rs index e667144c..78ccb5f0 100644 --- a/src/it/tests/t0040_virtual_keyboard.rs +++ b/src/it/tests/t0040_virtual_keyboard.rs @@ -3,7 +3,7 @@ use { backend::KeyState, clientmem::ClientMem, it::{test_error::TestResult, testrun::TestRun}, - xkbcommon::XkbContext, + kbvm::KbvmContext, }, bstr::ByteSlice, std::rc::Rc, @@ -14,8 +14,8 @@ testcase!(); async fn test(run: Rc) -> TestResult { let virtual_keymap_str = { - let xkb = XkbContext::new()?; - let map = xkb.keymap_from_str(VIRTUAL_KEYMAP).unwrap(); + let xkb = KbvmContext::default(); + let map = xkb.parse_keymap(VIRTUAL_KEYMAP.as_bytes()).unwrap(); read_keymap(&map.map, map.map_len) }; diff --git a/src/kbvm.rs b/src/kbvm.rs new file mode 100644 index 00000000..9a8e5fd7 --- /dev/null +++ b/src/kbvm.rs @@ -0,0 +1,216 @@ +use { + crate::{ + backend::KeyState, + ifs::wl_seat::WlSeatGlobal, + keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId}, + utils::{oserror::OsError, syncqueue::SyncQueue, vecset::VecSet}, + }, + kbvm::{ + lookup::LookupTable, + state_machine::{self, Direction, Event, StateMachine}, + xkb::{ + self, + diagnostic::{Diagnostic, WriteToLog}, + Keymap, + }, + Keycode, + }, + std::{ + cell::{Cell, Ref, RefCell}, + io::Write, + rc::Rc, + }, + thiserror::Error, + uapi::{c, OwnedFd}, +}; + +#[derive(Debug, Error)] +pub enum KbvmError { + #[error("could not parse the keymap")] + CouldNotParseKeymap(#[source] Diagnostic), + #[error("Could not create a keymap memfd")] + KeymapMemfd(#[source] OsError), +} + +pub struct KbvmContext { + pub ctx: xkb::Context, + pub ids: KbvmMapIds, +} + +impl Default for KbvmContext { + fn default() -> Self { + let mut ctx = xkb::Context::builder(); + ctx.enable_environment(true); + Self { + ctx: ctx.build(), + ids: Default::default(), + } + } +} + +linear_ids!(KbvmMapIds, KbvmMapId, u64); + +pub struct KbvmMap { + pub id: KbvmMapId, + pub state_machine: StateMachine, + pub lookup_table: LookupTable, + pub map: Rc, + pub map_len: usize, +} + +pub struct KbvmState { + pub map: Rc, + pub state: state_machine::State, + pub kb_state: KeyboardState, +} + +pub struct PhysicalKeyboardState { + state: Rc>, + inner: RefCell, + events: SyncQueue, + flushing: Cell, +} + +#[derive(Default)] +struct PkInner { + pressed_keys: VecSet, + event_stash: Vec, +} + +impl DynKeyboardState for RefCell { + fn borrow(&self) -> Ref<'_, KeyboardState> { + Ref::map(self.borrow(), |v| &v.kb_state) + } +} + +impl KbvmContext { + pub fn parse_keymap(&self, keymap: &[u8]) -> Result, KbvmError> { + let map = self + .ctx + .keymap_from_bytes(WriteToLog, None, keymap) + .map_err(KbvmError::CouldNotParseKeymap)?; + let (memfd, len) = create_keymap_memfd(&map).map_err(KbvmError::KeymapMemfd)?; + let builder = map.to_builder(); + Ok(Rc::new(KbvmMap { + id: self.ids.next(), + state_machine: builder.build_state_machine(), + map: Rc::new(memfd), + map_len: len + 1, + lookup_table: builder.build_lookup_table(), + })) + } +} + +fn create_keymap_memfd(map: &Keymap) -> Result<(OwnedFd, usize), OsError> { + let str = format!("{}\n", map.format()); + let mut memfd = uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING)?; + memfd.write_all(str.as_bytes())?; + memfd.write_all(&[0])?; + uapi::lseek(memfd.raw(), 0, c::SEEK_SET)?; + uapi::fcntl_add_seals( + memfd.raw(), + c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE, + )?; + Ok((memfd, str.len())) +} + +impl KbvmMap { + pub fn state(self: &Rc, id: KeyboardStateId) -> KbvmState { + KbvmState { + map: self.clone(), + state: self.state_machine.create_state(), + kb_state: KeyboardState { + id, + map: self.map.clone(), + map_len: self.map_len, + pressed_keys: Default::default(), + mods: Default::default(), + }, + } + } +} + +impl KbvmState { + pub fn apply_events(&mut self, events: &SyncQueue) { + let state = &mut self.kb_state; + while let Some(event) = events.pop() { + state.mods.apply_event(event); + match event { + Event::KeyDown(kc) => { + state.pressed_keys.insert(kc.to_evdev()); + } + Event::KeyUp(kc) => { + state.pressed_keys.remove(&kc.to_evdev()); + } + _ => {} + } + } + } +} + +impl PhysicalKeyboardState { + pub fn new(state: &Rc>) -> Self { + Self { + state: state.clone(), + inner: Default::default(), + events: Default::default(), + flushing: Cell::new(false), + } + } + + fn flush(&self, time_usec: u64, seat: &Rc) { + if self.flushing.replace(true) { + return; + } + seat.key_events(time_usec, &self.events, &self.state); + self.flushing.set(false); + } + + pub fn update(&self, time_usec: u64, seat: &Rc, key: u32, key_state: KeyState) { + { + let inner = &mut *self.inner.borrow_mut(); + match key_state { + KeyState::Released => { + if !inner.pressed_keys.remove(&key) { + return; + } + } + KeyState::Pressed => { + if !inner.pressed_keys.insert(key) { + return; + } + } + } + let state = &mut *self.state.borrow_mut(); + state.map.state_machine.handle_key( + &mut state.state, + &mut inner.event_stash, + Keycode::from_evdev(key), + match key_state { + KeyState::Released => Direction::Up, + KeyState::Pressed => Direction::Down, + }, + ); + self.events.append(&mut inner.event_stash); + } + self.flush(time_usec, seat); + } + + pub fn destroy(&self, time_usec: u64, seat: &Rc) { + { + let inner = &mut *self.inner.borrow_mut(); + let state = &mut *self.state.borrow_mut(); + let sm = &state.map.state_machine; + while let Some(key) = inner.pressed_keys.pop() { + sm.handle_key( + &mut state.state, + &mut inner.event_stash, + Keycode::from_evdev(key), + Direction::Up, + ); + } + self.events.append(&mut inner.event_stash); + } + self.flush(time_usec, seat); + } +} diff --git a/src/keyboard.rs b/src/keyboard.rs index 32484781..1b8d113d 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -1,13 +1,22 @@ use { - crate::utils::vecset::VecSet, + crate::utils::{oserror::OsError, vecset::VecSet}, kbvm::Components, std::{ cell::{Ref, RefCell}, rc::Rc, }, - uapi::OwnedFd, + thiserror::Error, + uapi::{c, Errno, OwnedFd}, }; +#[derive(Debug, Error)] +pub enum KeyboardError { + #[error("Could not create a keymap memfd")] + KeymapMemfd(#[source] OsError), + #[error("Could not copy the keymap")] + KeymapCopy(#[source] OsError), +} + linear_ids!(KeyboardStateIds, KeyboardStateId, u64); pub struct KeyboardState { @@ -27,3 +36,23 @@ impl DynKeyboardState for RefCell { self.borrow() } } + +impl KeyboardState { + pub fn create_new_keymap_fd(&self) -> Result, KeyboardError> { + let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) { + Ok(fd) => fd, + Err(e) => return Err(KeyboardError::KeymapMemfd(e.into())), + }; + let target = self.map_len as c::off_t; + let mut pos = 0; + while pos < target { + let rem = target - pos; + let res = uapi::sendfile(fd.raw(), self.map.raw(), Some(&mut pos), rem as usize); + match res { + Ok(_) | Err(Errno(c::EINTR)) => {} + Err(e) => return Err(KeyboardError::KeymapCopy(e.into())), + } + } + Ok(Rc::new(fd)) + } +} diff --git a/src/macros.rs b/src/macros.rs index 12d82383..3579eee2 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -249,6 +249,7 @@ macro_rules! cenum { } } +#[expect(unused_macros)] macro_rules! bitor { ($name:ident) => { impl std::ops::BitOr for $name { diff --git a/src/main.rs b/src/main.rs index d6ecb9c1..05032eed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,6 +74,7 @@ mod ifs; mod io_uring; #[cfg(feature = "it")] mod it; +mod kbvm; mod keyboard; mod libinput; mod logger; @@ -109,7 +110,6 @@ mod wire_ei; mod wire_xcon; mod wl_usr; mod xcon; -mod xkbcommon; mod xwayland; fn main() { diff --git a/src/state.rs b/src/state.rs index ece375cb..ac79f8ab 100644 --- a/src/state.rs +++ b/src/state.rs @@ -48,7 +48,7 @@ use { wl_output::{OutputGlobalOpt, OutputId, PersistentOutputState}, wl_seat::{ tablet::{TabletIds, TabletInit, TabletPadIds, TabletPadInit, TabletToolIds}, - SeatIds, WlSeatGlobal, + PhysicalKeyboardId, PhysicalKeyboardIds, SeatIds, WlSeatGlobal, }, wl_surface::{ tray::TrayItemIds, @@ -66,6 +66,7 @@ use { zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global, }, io_uring::IoUring, + kbvm::{KbvmContext, KbvmMap}, keyboard::KeyboardStateIds, leaks::Tracker, logger::Logger, @@ -100,7 +101,6 @@ use { ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId, ZwpLinuxDmabufFeedbackV1Id, }, - xkbcommon::{XkbContext, XkbKeymap, XkbState}, xwayland::{self, XWaylandEvent}, }, ahash::{AHashMap, AHashSet}, @@ -122,10 +122,10 @@ use { }; pub struct State { - pub xkb_ctx: XkbContext, + pub kb_ctx: KbvmContext, pub backend: CloneCell>, pub forker: CloneCell>>, - pub default_keymap: Rc, + pub default_keymap: Rc, pub eng: Rc, pub render_ctx: CloneCell>>, pub drm_feedback: CloneCell>>, @@ -206,6 +206,7 @@ pub struct State { pub wait_for_sync_obj: Rc, pub explicit_sync_enabled: Cell, pub keyboard_state_ids: KeyboardStateIds, + pub physical_keyboard_ids: PhysicalKeyboardIds, pub security_context_acceptors: SecurityContextAcceptors, pub cursor_user_group_ids: CursorUserGroupIds, pub cursor_user_ids: CursorUserIds, @@ -327,13 +328,13 @@ pub struct InputDeviceData { } pub struct DeviceHandlerData { + pub keyboard_id: PhysicalKeyboardId, pub seat: CloneCell>>, pub px_per_scroll_wheel: Cell, pub device: Rc, pub syspath: Option, pub devnode: Option, - pub keymap: CloneCell>>, - pub xkb_state: CloneCell>>>, + pub keymap: CloneCell>>, pub output: CloneCell>>, pub tablet_init: Option>, pub tablet_pad_init: Option>, diff --git a/src/tasks/input_device.rs b/src/tasks/input_device.rs index 2268beb6..7e1855f8 100644 --- a/src/tasks/input_device.rs +++ b/src/tasks/input_device.rs @@ -16,13 +16,13 @@ pub fn handle(state: &Rc, dev: Rc) { Some(dev_t) => udev_props(dev_t, 3), }; let data = Rc::new(DeviceHandlerData { + keyboard_id: state.physical_keyboard_ids.next(), seat: Default::default(), px_per_scroll_wheel: Cell::new(PX_PER_SCROLL), device: dev.clone(), syspath: props.syspath, devnode: props.devnode, keymap: Default::default(), - xkb_state: Default::default(), output: Default::default(), tablet_init: dev.tablet_info(), tablet_pad_init: dev.tablet_pad_info(), diff --git a/src/utils/syncqueue.rs b/src/utils/syncqueue.rs index 4a32c0f2..1a0852e1 100644 --- a/src/utils/syncqueue.rs +++ b/src/utils/syncqueue.rs @@ -29,6 +29,13 @@ impl SyncQueue { } } + pub fn append(&self, src: &mut Vec) { + unsafe { + self.el.get().deref_mut().extend(src.drain(..)); + } + } + + #[inline] pub fn pop(&self) -> Option { unsafe { self.el.get().deref_mut().pop_front() } } diff --git a/src/utils/vecset.rs b/src/utils/vecset.rs index 9a7d6c97..d058fe0a 100644 --- a/src/utils/vecset.rs +++ b/src/utils/vecset.rs @@ -43,4 +43,8 @@ impl VecSet { } false } + + pub fn pop(&mut self) -> Option { + self.vec.pop() + } } diff --git a/src/xkbcommon.rs b/src/xkbcommon.rs deleted file mode 100644 index d56a2ab3..00000000 --- a/src/xkbcommon.rs +++ /dev/null @@ -1,401 +0,0 @@ -#![allow(non_camel_case_types, improper_ctypes)] - -mod consts; - -include!(concat!(env!("OUT_DIR"), "/xkbcommon_tys.rs")); - -pub use consts::*; -use { - crate::{ - keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId}, - utils::{errorfmt::ErrorFmt, oserror::OsError, ptr_ext::PtrExt}, - }, - bstr::{BStr, ByteSlice}, - isnt::std_1::primitive::IsntConstPtrExt, - std::{ - cell::{Ref, RefCell}, - ffi::CStr, - io::Write, - ops::Deref, - ptr, - rc::Rc, - }, - thiserror::Error, - uapi::{c, Errno, OwnedFd}, -}; - -#[derive(Debug, Error)] -pub enum XkbCommonError { - #[error("Could not create an xkbcommon context")] - CreateContext, - #[error("Could not create an xkbcommon state")] - CreateState, - #[error("Could not create keymap from buffer")] - KeymapFromBuffer, - #[error("Could not convert the keymap to a string")] - AsStr, - #[error("Could not create a keymap memfd")] - KeymapMemfd(#[source] OsError), - #[error("Could not copy the keymap")] - KeymapCopy(#[source] OsError), -} - -struct xkb_context; -struct xkb_keymap; -struct xkb_state; - -type xkb_keycode_t = u32; -type xkb_layout_index_t = u32; -type xkb_level_index_t = u32; -type xkb_keysym_t = u32; -type xkb_mod_mask_t = u32; - -#[repr(C)] -struct xkb_rule_names { - rules: *const c::c_char, - model: *const c::c_char, - layout: *const c::c_char, - variant: *const c::c_char, - options: *const c::c_char, -} - -impl Default for xkb_rule_names { - fn default() -> Self { - Self { - rules: ptr::null(), - model: ptr::null(), - layout: ptr::null(), - variant: ptr::null(), - options: ptr::null(), - } - } -} - -#[link(name = "xkbcommon")] -unsafe extern "C" { - fn xkb_context_new(flags: xkb_context_flags) -> *mut xkb_context; - fn xkb_context_unref(context: *mut xkb_context); - fn xkb_context_set_log_verbosity(context: *mut xkb_context, verbosity: c::c_int); - fn xkb_context_set_log_fn(context: *mut xkb_context, log_fn: unsafe extern "C" fn()); - fn xkb_keymap_new_from_buffer( - context: *mut xkb_context, - buffer: *const u8, - length: usize, - format: xkb_keymap_format, - flags: xkb_keymap_compile_flags, - ) -> *mut xkb_keymap; - fn xkb_keymap_get_as_string( - keymap: *mut xkb_keymap, - format: xkb_keymap_format, - ) -> *mut c::c_char; - fn xkb_keymap_unref(keymap: *mut xkb_keymap); - // fn xkb_keymap_ref(keymap: *mut xkb_keymap) -> *mut xkb_keymap; - fn xkb_keymap_key_get_syms_by_level( - keymap: *mut xkb_keymap, - key: xkb_keycode_t, - layout: xkb_layout_index_t, - level: xkb_level_index_t, - syms_out: *mut *const xkb_keysym_t, - ) -> c::c_int; - fn xkb_state_unref(state: *mut xkb_state); - fn xkb_state_new(keymap: *mut xkb_keymap) -> *mut xkb_state; - fn xkb_state_update_key( - state: *mut xkb_state, - key: u32, - direction: xkb_key_direction, - ) -> xkb_state_component; - fn xkb_state_serialize_mods(state: *mut xkb_state, components: xkb_state_component) -> u32; - fn xkb_state_serialize_layout(state: *mut xkb_state, components: xkb_state_component) -> u32; - fn xkb_state_update_mask( - state: *mut xkb_state, - depressed_mods: xkb_mod_mask_t, - latched_mods: xkb_mod_mask_t, - locked_mods: xkb_mod_mask_t, - depressed_layout: xkb_layout_index_t, - latched_layout: xkb_layout_index_t, - locked_layout: xkb_layout_index_t, - ) -> xkb_state_component; -} - -pub struct XkbContext { - context: *mut xkb_context, - ids: KeymapIds, -} - -unsafe extern "C" { - fn jay_xkbcommon_log_handler_bridge(); -} - -linear_ids!(KeymapIds, KeymapId, u64); - -impl XkbContext { - pub fn new() -> Result { - let res = unsafe { xkb_context_new(XKB_CONTEXT_NO_FLAGS.raw() as _) }; - if res.is_null() { - return Err(XkbCommonError::CreateContext); - } - unsafe { - xkb_context_set_log_verbosity(res, 10); - xkb_context_set_log_fn(res, jay_xkbcommon_log_handler_bridge); - } - Ok(Self { - context: res, - ids: Default::default(), - }) - } - - fn raw_to_map(&self, raw: *mut xkb_keymap) -> Result, XkbCommonError> { - let res = unsafe { xkb_keymap_get_as_string(raw, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) }; - if res.is_null() { - unsafe { - xkb_keymap_unref(raw); - } - return Err(XkbCommonError::AsStr); - } - let str = XkbKeymapStr { - s: unsafe { CStr::from_ptr(res).to_bytes().as_bstr() }, - }; - let mut memfd = - uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap(); - memfd.write_all(str.as_bytes()).unwrap(); - memfd.write_all(&[0]).unwrap(); - uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap(); - uapi::fcntl_add_seals( - memfd.raw(), - c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE, - ) - .unwrap(); - Ok(Rc::new(XkbKeymap { - id: self.ids.next(), - keymap: raw, - map: Rc::new(memfd), - map_len: str.len() + 1, - })) - } - - pub fn keymap_from_str(&self, s: &S) -> Result, XkbCommonError> - where - S: AsRef<[u8]> + ?Sized, - { - let s = s.as_ref(); - unsafe { - let keymap = xkb_keymap_new_from_buffer( - self.context, - s.as_ptr(), - s.len(), - XKB_KEYMAP_FORMAT_TEXT_V1.raw(), - 0, - ); - if keymap.is_null() { - return Err(XkbCommonError::KeymapFromBuffer); - } - self.raw_to_map(keymap) - } - } -} - -impl Drop for XkbContext { - fn drop(&mut self) { - unsafe { - xkb_context_unref(self.context); - } - } -} - -pub struct XkbKeymap { - pub id: KeymapId, - keymap: *mut xkb_keymap, - pub map: Rc, - pub map_len: usize, -} - -impl XkbKeymap { - pub fn state(self: &Rc, id: KeyboardStateId) -> Result { - let res = unsafe { xkb_state_new(self.keymap) }; - if res.is_null() { - return Err(XkbCommonError::CreateState); - } - Ok(XkbState { - map: self.clone(), - state: res, - kb_state: KeyboardState { - id, - map: self.map.clone(), - map_len: self.map_len, - pressed_keys: Default::default(), - mods: Default::default(), - }, - }) - } -} - -impl Drop for XkbKeymap { - fn drop(&mut self) { - unsafe { - xkb_keymap_unref(self.keymap); - } - } -} - -pub struct XkbKeymapStr { - s: *const BStr, -} - -impl Deref for XkbKeymapStr { - type Target = BStr; - - fn deref(&self) -> &Self::Target { - unsafe { self.s.deref() } - } -} - -impl Drop for XkbKeymapStr { - fn drop(&mut self) { - unsafe { c::free(self.s as _) } - } -} - -pub struct XkbState { - map: Rc, - state: *mut xkb_state, - pub kb_state: KeyboardState, -} - -impl DynKeyboardState for RefCell { - fn borrow(&self) -> Ref<'_, KeyboardState> { - Ref::map(self.borrow(), |v| &v.kb_state) - } -} - -impl KeyboardState { - pub fn create_new_keymap_fd(&self) -> Result, XkbCommonError> { - let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) { - Ok(fd) => fd, - Err(e) => return Err(XkbCommonError::KeymapMemfd(e.into())), - }; - let target = self.map_len as c::off_t; - let mut pos = 0; - while pos < target { - let rem = target - pos; - let res = uapi::sendfile(fd.raw(), self.map.raw(), Some(&mut pos), rem as usize); - match res { - Ok(_) | Err(Errno(c::EINTR)) => {} - Err(e) => return Err(XkbCommonError::KeymapCopy(e.into())), - } - } - Ok(Rc::new(fd)) - } -} - -impl XkbState { - pub fn mods(&self) -> kbvm::Components { - self.kb_state.mods - } - - fn fetch(&mut self, changes: xkb_state_component) -> bool { - unsafe { - if changes != 0 { - self.kb_state.mods.mods_pressed.0 = - xkb_state_serialize_mods(self.state, XKB_STATE_MODS_DEPRESSED.raw() as _); - self.kb_state.mods.mods_latched.0 = - xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LATCHED.raw() as _); - self.kb_state.mods.mods_locked.0 = - xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LOCKED.raw() as _); - self.kb_state.mods.group_locked.0 = - xkb_state_serialize_layout(self.state, XKB_STATE_LAYOUT_EFFECTIVE.raw() as _); - self.kb_state.mods.update_effective(); - true - } else { - false - } - } - } - - 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; - } - - #[expect(dead_code)] - pub fn set( - &mut self, - mods_depressed: u32, - mods_latched: u32, - mods_locked: u32, - group: u32, - ) -> bool { - unsafe { - let changes = xkb_state_update_mask( - self.state, - mods_depressed, - mods_latched, - mods_locked, - 0, - 0, - group, - ); - self.fetch(changes) - } - } - - pub fn unmodified_keysyms(&self, key: u32) -> &[xkb_keysym_t] { - let mut res = ptr::null(); - unsafe { - let num = xkb_keymap_key_get_syms_by_level( - self.map.keymap, - key + 8, - self.kb_state.mods.group.0, - 0, - &mut res, - ); - if num > 0 { - std::slice::from_raw_parts(res, num as usize) - } else { - &[] - } - } - } -} - -impl Drop for XkbState { - fn drop(&mut self) { - unsafe { - xkb_state_unref(self.state); - } - } -} - -#[unsafe(no_mangle)] -unsafe extern "C" fn jay_xkbcommon_log_handler( - _ctx: *mut xkb_context, - level: xkb_log_level, - line: *const c::c_char, -) { - assert!(line.is_not_null()); - let buf = unsafe { CStr::from_ptr(line) }; - let level = match XkbLogLevel(level) { - XKB_LOG_LEVEL_CRITICAL | XKB_LOG_LEVEL_ERROR => log::Level::Error, - XKB_LOG_LEVEL_WARNING => log::Level::Warn, - XKB_LOG_LEVEL_INFO => log::Level::Info, - XKB_LOG_LEVEL_DEBUG => log::Level::Debug, - _ => log::Level::Error, - }; - log::log!( - level, - "xkbcommon: {}", - buf.to_bytes().trim_ascii_end().as_bstr(), - ); -} diff --git a/src/xkbcommon/consts.rs b/src/xkbcommon/consts.rs deleted file mode 100644 index 559b3bef..00000000 --- a/src/xkbcommon/consts.rs +++ /dev/null @@ -1,58 +0,0 @@ -#![allow(dead_code)] - -cenum! { - XkbLogLevel, XKB_LOG_LEVEL; - - XKB_LOG_LEVEL_CRITICAL = 10, - XKB_LOG_LEVEL_ERROR = 20, - XKB_LOG_LEVEL_WARNING = 30, - XKB_LOG_LEVEL_INFO = 40, - XKB_LOG_LEVEL_DEBUG = 50, -} - -cenum! { - XkbContextFlags, XKB_CONTEXT_FLAGS; - - XKB_CONTEXT_NO_FLAGS = 0, - XKB_CONTEXT_NO_DEFAULT_INCLUDES = 1 << 0, - XKB_CONTEXT_NO_ENVIRONMENT_NAMES = 1 << 1, -} - -bitor!(XkbContextFlags); - -cenum! { - XkbKeymapCompileFlags, XKB_KEYMAP_COMPILE_FLAGS; - - XKB_KEYMAP_COMPILE_NO_FLAGS = 0, -} - -bitor!(XkbKeymapCompileFlags); - -cenum! { - XkbKeymapFormat, XKB_KEYMAP_FORMAT; - - XKB_KEYMAP_FORMAT_TEXT_V1 = 1, -} - -cenum! { - XkbStateComponent, XKB_STATE_COMPONENT; - - XKB_STATE_MODS_DEPRESSED = 1 << 0, - XKB_STATE_MODS_LATCHED = 1 << 1, - XKB_STATE_MODS_LOCKED = 1 << 2, - XKB_STATE_MODS_EFFECTIVE = 1 << 3, - XKB_STATE_LAYOUT_DEPRESSED = 1 << 4, - XKB_STATE_LAYOUT_LATCHED = 1 << 5, - XKB_STATE_LAYOUT_LOCKED = 1 << 6, - XKB_STATE_LAYOUT_EFFECTIVE = 1 << 7, - XKB_STATE_LEDS = 1 << 8, -} - -bitor!(XkbStateComponent); - -cenum! { - XkbKeyDirection, XKB_KEY_DIRECTION; - - XKB_KEY_UP = 0, - XKB_KEY_DOWN = 1, -}