1
0
Fork 0
forked from wry/wry

keyboard: replace xkbcommon by kbvm

This commit is contained in:
Julian Orth 2025-01-07 20:03:49 +01:00
parent 51ceba72b0
commit 541a7b5ebc
23 changed files with 532 additions and 738 deletions

View file

@ -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(())
}

View file

@ -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);
}

View file

@ -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(),

View file

@ -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<State>,
pub next_id: NumCell<u64>,
pub keymaps: CopyHashMap<Keymap, Rc<XkbKeymap>>,
pub keymaps: CopyHashMap<Keymap, Rc<KbvmMap>>,
pub bufs: Stack<Vec<u8>>,
pub workspace_ids: NumCell<u64>,
@ -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<Rc<XkbKeymap>, CphError> {
fn get_keymap(&self, keymap: Keymap) -> Result<Rc<KbvmMap>, 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")]

View file

@ -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(),

View file

@ -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);

View file

@ -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<WlSeatGlobal>,
pub capabilities: Cell<u64>,
pub kb_state_id: Cell<KeyboardStateId>,
pub keyboard_id: PhysicalKeyboardId,
pub device: CloneCell<Option<Rc<EiDevice>>>,
pub pointer: CloneCell<Option<Rc<EiPointer>>>,
@ -75,7 +76,11 @@ impl EiSeat {
}
}
pub fn handle_xkb_state_change(self: &Rc<Self>, old_id: KeyboardStateId, new: &KeyboardState) {
pub fn handle_keyboard_state_change(
self: &Rc<Self>,
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<dyn DynKeyboardState> {
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(),
}
}

View file

@ -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<F>(&self, keymap: &Rc<OwnedFd>, len: u32, f: F) -> Result<(), JayInputError>
where
F: FnOnce(&Rc<XkbKeymap>) -> Result<(), JayInputError>,
F: FnOnce(&Rc<KbvmMap>) -> 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,
}

View file

@ -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<bool>,
pub phy_state: PhysicalKeyboardState,
}
linear_ids!(SeatIds, SeatId);
pub struct WlSeatGlobal {
@ -169,10 +176,12 @@ pub struct WlSeatGlobal {
>,
data_control_devices: CopyHashMap<DataControlDeviceId, Rc<dyn DynDataControlDevice>>,
repeat_rate: Cell<(i32, i32)>,
seat_kb_map: CloneCell<Rc<XkbKeymap>>,
seat_xkb_state: CloneCell<Rc<RefCell<XkbState>>>,
seat_kb_map: CloneCell<Rc<KbvmMap>>,
seat_kb_state: CloneCell<Rc<RefCell<KbvmState>>>,
latest_kb_state: CloneCell<Rc<dyn DynKeyboardState>>,
xkb_states: CopyHashMap<KeymapId, Weak<RefCell<XkbState>>>,
latest_kb_state_id: Cell<KeyboardStateId>,
kb_states: CopyHashMap<KbvmMapId, Weak<RefCell<KbvmState>>>,
kb_devices: CopyHashMap<PhysicalKeyboardId, Rc<PhysicalKeyboard>>,
cursor_user_group: Rc<CursorUserGroup>,
pointer_cursor: Rc<CursorUser>,
tree_changed: Rc<AsyncEvent>,
@ -214,13 +223,11 @@ const CHANGE_TREE: u32 = 1 << 1;
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 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<XkbKeymap> {
pub fn keymap(&self) -> Rc<KbvmMap> {
self.seat_kb_map.get()
}
@ -496,53 +505,46 @@ impl WlSeatGlobal {
false
}
pub fn set_seat_keymap(&self, keymap: &Rc<XkbKeymap>) {
let Some(xkb_state) = self.get_xkb_state(keymap) else {
return;
};
pub fn set_seat_keymap(&self, keymap: &Rc<KbvmMap>) {
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<XkbKeymap>) -> Option<Rc<RefCell<XkbState>>> {
if let Some(weak) = self.xkb_states.get(&keymap.id) {
pub fn get_kb_state(&self, keymap: &Rc<KbvmMap>) -> Rc<RefCell<KbvmState>> {
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<Self>) {
@ -1031,16 +1033,17 @@ impl WlSeatGlobal {
self.update_capabilities();
}
pub fn remove_ei_seat(&self, ei: &EiSeat) {
pub fn remove_ei_seat(self: &Rc<Self>, 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<dyn DynKeyboardState> {
self.seat_xkb_state.get()
pub fn seat_kb_state(&self) -> Rc<dyn DynKeyboardState> {
self.seat_kb_state.get()
}
pub fn latest_xkb_state(&self) -> Rc<dyn DynKeyboardState> {
pub fn latest_kb_state(&self) -> Rc<dyn DynKeyboardState> {
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<KbvmMap>>,
) -> Rc<PhysicalKeyboard> {
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<Self>, 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<dyn Node>) -> SmallVec<[Rc<WlSeatGlobal>; 3]> {
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 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<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;
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<Rc<KbvmMap>>) {
self.destroy_physical_keyboard_state();
self.keymap.set(keymap);
}
pub fn set_output(&self, output: Option<&WlOutputGlobal>) {

View file

@ -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<Self>,
time_usec: u64,
key: u32,
key_state: KeyState,
events: &SyncQueue<Event>,
kbvm_state_rc: &Rc<RefCell<KbvmState>>,
) {
self.key_event(time_usec, key, key_state, || self.seat_xkb_state.get());
}
pub(super) fn key_event<F>(
self: &Rc<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) = {
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<EiSeat>)) {

View file

@ -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<ClientError>),
#[error(transparent)]
XkbCommonError(#[from] XkbCommonError),
KeyboardError(#[from] KeyboardError),
}
efrom!(WlKeyboardError, ClientError);

View file

@ -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);

View file

@ -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<TestRun>) -> 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)
};

216
src/kbvm.rs Normal file
View file

@ -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<OwnedFd>,
pub map_len: usize,
}
pub struct KbvmState {
pub map: Rc<KbvmMap>,
pub state: state_machine::State,
pub kb_state: KeyboardState,
}
pub struct PhysicalKeyboardState {
state: Rc<RefCell<KbvmState>>,
inner: RefCell<PkInner>,
events: SyncQueue<Event>,
flushing: Cell<bool>,
}
#[derive(Default)]
struct PkInner {
pressed_keys: VecSet<u32>,
event_stash: Vec<Event>,
}
impl DynKeyboardState for RefCell<KbvmState> {
fn borrow(&self) -> Ref<'_, KeyboardState> {
Ref::map(self.borrow(), |v| &v.kb_state)
}
}
impl KbvmContext {
pub fn parse_keymap(&self, keymap: &[u8]) -> Result<Rc<KbvmMap>, 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<Self>, 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<Event>) {
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<RefCell<KbvmState>>) -> Self {
Self {
state: state.clone(),
inner: Default::default(),
events: Default::default(),
flushing: Cell::new(false),
}
}
fn flush(&self, time_usec: u64, seat: &Rc<WlSeatGlobal>) {
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<WlSeatGlobal>, 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<WlSeatGlobal>) {
{
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);
}
}

View file

@ -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<KeyboardState> {
self.borrow()
}
}
impl KeyboardState {
pub fn create_new_keymap_fd(&self) -> Result<Rc<OwnedFd>, 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))
}
}

View file

@ -249,6 +249,7 @@ macro_rules! cenum {
}
}
#[expect(unused_macros)]
macro_rules! bitor {
($name:ident) => {
impl std::ops::BitOr for $name {

View file

@ -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() {

View file

@ -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<Rc<dyn Backend>>,
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
pub default_keymap: Rc<XkbKeymap>,
pub default_keymap: Rc<KbvmMap>,
pub eng: Rc<AsyncEngine>,
pub render_ctx: CloneCell<Option<Rc<dyn GfxContext>>>,
pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>,
@ -206,6 +206,7 @@ pub struct State {
pub wait_for_sync_obj: Rc<WaitForSyncObj>,
pub explicit_sync_enabled: Cell<bool>,
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<Option<Rc<WlSeatGlobal>>>,
pub px_per_scroll_wheel: Cell<f64>,
pub device: Rc<dyn InputDevice>,
pub syspath: Option<String>,
pub devnode: Option<String>,
pub keymap: CloneCell<Option<Rc<XkbKeymap>>>,
pub xkb_state: CloneCell<Option<Rc<RefCell<XkbState>>>>,
pub keymap: CloneCell<Option<Rc<KbvmMap>>>,
pub output: CloneCell<Option<Rc<OutputGlobalOpt>>>,
pub tablet_init: Option<Box<TabletInit>>,
pub tablet_pad_init: Option<Box<TabletPadInit>>,

View file

@ -16,13 +16,13 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
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(),

View file

@ -29,6 +29,13 @@ impl<T> SyncQueue<T> {
}
}
pub fn append(&self, src: &mut Vec<T>) {
unsafe {
self.el.get().deref_mut().extend(src.drain(..));
}
}
#[inline]
pub fn pop(&self) -> Option<T> {
unsafe { self.el.get().deref_mut().pop_front() }
}

View file

@ -43,4 +43,8 @@ impl<T: PartialEq> VecSet<T> {
}
false
}
pub fn pop(&mut self) -> Option<T> {
self.vec.pop()
}
}

View file

@ -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<Self, XkbCommonError> {
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<Rc<XkbKeymap>, 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<S>(&self, s: &S) -> Result<Rc<XkbKeymap>, 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<OwnedFd>,
pub map_len: usize,
}
impl XkbKeymap {
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);
}
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<XkbKeymap>,
state: *mut xkb_state,
pub kb_state: KeyboardState,
}
impl DynKeyboardState for RefCell<XkbState> {
fn borrow(&self) -> Ref<'_, KeyboardState> {
Ref::map(self.borrow(), |v| &v.kb_state)
}
}
impl KeyboardState {
pub fn create_new_keymap_fd(&self) -> Result<Rc<OwnedFd>, 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(),
);
}

View file

@ -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,
}