keyboard: replace xkbcommon by kbvm
This commit is contained in:
parent
51ceba72b0
commit
541a7b5ebc
23 changed files with 532 additions and 738 deletions
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
17
src/bridge.c
17
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>) {
|
||||
|
|
|
|||
|
|
@ -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>)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
216
src/kbvm.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ macro_rules! cenum {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(unused_macros)]
|
||||
macro_rules! bitor {
|
||||
($name:ident) => {
|
||||
impl std::ops::BitOr for $name {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
13
src/state.rs
13
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<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>>,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,4 +43,8 @@ impl<T: PartialEq> VecSet<T> {
|
|||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.vec.pop()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
401
src/xkbcommon.rs
401
src/xkbcommon.rs
|
|
@ -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(),
|
||||
);
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue