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"]
|
#[path = "../src/macros.rs"]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
#[path = "../src/xkbcommon/consts.rs"]
|
|
||||||
mod xkbcommon;
|
|
||||||
|
|
||||||
#[path = "../src/libinput/consts.rs"]
|
#[path = "../src/libinput/consts.rs"]
|
||||||
mod libinput;
|
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::CAIRO_OPERATORS, "cairo_operator_t")?;
|
||||||
write_ty(&mut f, pango::PANGO_ELLIPSIZE_MODES, "PangoEllipsizeMode_")?;
|
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(())
|
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);
|
jay_libinput_log_handler(libinput, priority, line);
|
||||||
free(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,
|
workspace_manager::workspace_manager_done,
|
||||||
},
|
},
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
|
kbvm::KbvmContext,
|
||||||
leaks,
|
leaks,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
output_schedule::OutputSchedule,
|
output_schedule::OutputSchedule,
|
||||||
|
|
@ -49,7 +50,6 @@ use {
|
||||||
version::VERSION,
|
version::VERSION,
|
||||||
video::drm::wait_for_sync_obj::WaitForSyncObj,
|
video::drm::wait_for_sync_obj::WaitForSyncObj,
|
||||||
wheel::{Wheel, WheelError},
|
wheel::{Wheel, WheelError},
|
||||||
xkbcommon::XkbContext,
|
|
||||||
},
|
},
|
||||||
ahash::AHashSet,
|
ahash::AHashSet,
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
|
|
@ -139,8 +139,10 @@ fn start_compositor2(
|
||||||
init_fd_limit();
|
init_fd_limit();
|
||||||
leaks::init();
|
leaks::init();
|
||||||
clientmem::init()?;
|
clientmem::init()?;
|
||||||
let xkb_ctx = XkbContext::new().unwrap();
|
let kb_ctx = KbvmContext::default();
|
||||||
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
let kb_keymap = kb_ctx
|
||||||
|
.parse_keymap(include_str!("keymap.xkb").as_bytes())
|
||||||
|
.unwrap();
|
||||||
let engine = AsyncEngine::new();
|
let engine = AsyncEngine::new();
|
||||||
let ring = IoUring::new(&engine, 32)?;
|
let ring = IoUring::new(&engine, 32)?;
|
||||||
let _signal_future = sighand::install(&engine, &ring)?;
|
let _signal_future = sighand::install(&engine, &ring)?;
|
||||||
|
|
@ -151,10 +153,10 @@ fn start_compositor2(
|
||||||
scales.add(Scale::from_int(1));
|
scales.add(Scale::from_int(1));
|
||||||
let cpu_worker = Rc::new(CpuWorker::new(&ring, &engine)?);
|
let cpu_worker = Rc::new(CpuWorker::new(&ring, &engine)?);
|
||||||
let state = Rc::new(State {
|
let state = Rc::new(State {
|
||||||
xkb_ctx,
|
kb_ctx,
|
||||||
backend: CloneCell::new(Rc::new(DummyBackend)),
|
backend: CloneCell::new(Rc::new(DummyBackend)),
|
||||||
forker: Default::default(),
|
forker: Default::default(),
|
||||||
default_keymap: xkb_keymap,
|
default_keymap: kb_keymap,
|
||||||
eng: engine.clone(),
|
eng: engine.clone(),
|
||||||
render_ctx: Default::default(),
|
render_ctx: Default::default(),
|
||||||
drm_feedback: Default::default(),
|
drm_feedback: Default::default(),
|
||||||
|
|
@ -254,6 +256,7 @@ fn start_compositor2(
|
||||||
wait_for_sync_obj: Rc::new(WaitForSyncObj::new(&ring, &engine)),
|
wait_for_sync_obj: Rc::new(WaitForSyncObj::new(&ring, &engine)),
|
||||||
explicit_sync_enabled: Cell::new(true),
|
explicit_sync_enabled: Cell::new(true),
|
||||||
keyboard_state_ids: Default::default(),
|
keyboard_state_ids: Default::default(),
|
||||||
|
physical_keyboard_ids: Default::default(),
|
||||||
security_context_acceptors: Default::default(),
|
security_context_acceptors: Default::default(),
|
||||||
cursor_user_group_ids: Default::default(),
|
cursor_user_group_ids: Default::default(),
|
||||||
cursor_user_ids: Default::default(),
|
cursor_user_ids: Default::default(),
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use {
|
||||||
format::config_formats,
|
format::config_formats,
|
||||||
ifs::wl_seat::{SeatId, WlSeatGlobal},
|
ifs::wl_seat::{SeatId, WlSeatGlobal},
|
||||||
io_uring::TaskResultExt,
|
io_uring::TaskResultExt,
|
||||||
|
kbvm::{KbvmError, KbvmMap},
|
||||||
output_schedule::map_cursor_hz,
|
output_schedule::map_cursor_hz,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
|
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
|
||||||
|
|
@ -28,7 +29,6 @@ use {
|
||||||
stack::Stack,
|
stack::Stack,
|
||||||
timer::{TimerError, TimerFd},
|
timer::{TimerError, TimerFd},
|
||||||
},
|
},
|
||||||
xkbcommon::{XkbCommonError, XkbKeymap},
|
|
||||||
},
|
},
|
||||||
bincode::Options,
|
bincode::Options,
|
||||||
jay_config::{
|
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 handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||||
pub state: Rc<State>,
|
pub state: Rc<State>,
|
||||||
pub next_id: NumCell<u64>,
|
pub next_id: NumCell<u64>,
|
||||||
pub keymaps: CopyHashMap<Keymap, Rc<XkbKeymap>>,
|
pub keymaps: CopyHashMap<Keymap, Rc<KbvmMap>>,
|
||||||
pub bufs: Stack<Vec<u8>>,
|
pub bufs: Stack<Vec<u8>>,
|
||||||
|
|
||||||
pub workspace_ids: NumCell<u64>,
|
pub workspace_ids: NumCell<u64>,
|
||||||
|
|
@ -180,7 +180,7 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_parse_keymap(&self, keymap: &str) -> Result<(), CphError> {
|
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) => {
|
Ok(keymap) => {
|
||||||
let id = Keymap(self.id());
|
let id = Keymap(self.id());
|
||||||
self.keymaps.set(id, keymap);
|
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) {
|
match self.keymaps.get(&keymap) {
|
||||||
Some(k) => Ok(k),
|
Some(k) => Ok(k),
|
||||||
None => Err(CphError::KeymapDoesNotExist(keymap)),
|
None => Err(CphError::KeymapDoesNotExist(keymap)),
|
||||||
|
|
@ -2007,7 +2007,7 @@ enum CphError {
|
||||||
#[error("Repeat delay is negative")]
|
#[error("Repeat delay is negative")]
|
||||||
NegativeRepeatDelay,
|
NegativeRepeatDelay,
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseKeymapError(#[from] XkbCommonError),
|
ParseKeymapError(#[from] KbvmError),
|
||||||
#[error("Device {0:?} does not exist")]
|
#[error("Device {0:?} does not exist")]
|
||||||
DeviceDoesNotExist(InputDevice),
|
DeviceDoesNotExist(InputDevice),
|
||||||
#[error("Connector {0:?} does not exist")]
|
#[error("Connector {0:?} does not exist")]
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,9 @@ impl EiConnection {
|
||||||
if version == EiVersion(0) {
|
if version == EiVersion(0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let xkb_state_id = match self.context() {
|
let kb_state_id = match self.context() {
|
||||||
EiContext::Sender => seat.seat_xkb_state().borrow().id,
|
EiContext::Sender => seat.seat_kb_state().borrow().id,
|
||||||
EiContext::Receiver => seat.latest_xkb_state().borrow().id,
|
EiContext::Receiver => seat.latest_kb_state().borrow().id,
|
||||||
};
|
};
|
||||||
let seat = Rc::new(EiSeat {
|
let seat = Rc::new(EiSeat {
|
||||||
id: self.client.new_id(),
|
id: self.client.new_id(),
|
||||||
|
|
@ -75,7 +75,8 @@ impl EiConnection {
|
||||||
version,
|
version,
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
capabilities: Cell::new(0),
|
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(),
|
device: Default::default(),
|
||||||
pointer: Default::default(),
|
pointer: Default::default(),
|
||||||
pointer_absolute: Default::default(),
|
pointer_absolute: Default::default(),
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,8 @@ impl EiDeviceRequestHandler for EiDevice {
|
||||||
seat.button_event(time, button, pressed);
|
seat.button_event(time, button, pressed);
|
||||||
}
|
}
|
||||||
while let Some((button, pressed)) = self.key_changes.pop() {
|
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() {
|
if let Some((x, y)) = self.relative_motion.take() {
|
||||||
let x = Fixed::from_f32(x);
|
let x = Fixed::from_f32(x);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use {
|
||||||
EiContext,
|
EiContext,
|
||||||
},
|
},
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
ifs::wl_seat::{wl_pointer::PendingScroll, WlSeatGlobal},
|
ifs::wl_seat::{wl_pointer::PendingScroll, PhysicalKeyboardId, WlSeatGlobal},
|
||||||
keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId},
|
keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
tree::Node,
|
tree::Node,
|
||||||
|
|
@ -49,6 +49,7 @@ pub struct EiSeat {
|
||||||
pub seat: Rc<WlSeatGlobal>,
|
pub seat: Rc<WlSeatGlobal>,
|
||||||
pub capabilities: Cell<u64>,
|
pub capabilities: Cell<u64>,
|
||||||
pub kb_state_id: Cell<KeyboardStateId>,
|
pub kb_state_id: Cell<KeyboardStateId>,
|
||||||
|
pub keyboard_id: PhysicalKeyboardId,
|
||||||
|
|
||||||
pub device: CloneCell<Option<Rc<EiDevice>>>,
|
pub device: CloneCell<Option<Rc<EiDevice>>>,
|
||||||
pub pointer: CloneCell<Option<Rc<EiPointer>>>,
|
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() {
|
if self.keyboard.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +99,7 @@ impl EiSeat {
|
||||||
if self.is_sender() {
|
if self.is_sender() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.handle_xkb_state_change(old_id, state);
|
self.handle_keyboard_state_change(old_id, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(kb) = self.keyboard.get() {
|
if let Some(kb) = self.keyboard.get() {
|
||||||
|
|
@ -114,7 +119,7 @@ impl EiSeat {
|
||||||
}
|
}
|
||||||
let old_id = self.kb_state_id.get();
|
let old_id = self.kb_state_id.get();
|
||||||
if old_id != kb_state.id {
|
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() {
|
if let Some(kb) = self.keyboard.get() {
|
||||||
kb.send_key(key, state);
|
kb.send_key(key, state);
|
||||||
|
|
@ -298,8 +303,8 @@ impl EiSeat {
|
||||||
|
|
||||||
fn get_kb_state(&self) -> Rc<dyn DynKeyboardState> {
|
fn get_kb_state(&self) -> Rc<dyn DynKeyboardState> {
|
||||||
match self.context() {
|
match self.context() {
|
||||||
EiContext::Sender => self.seat.seat_xkb_state(),
|
EiContext::Sender => self.seat.seat_kb_state(),
|
||||||
EiContext::Receiver => self.seat.latest_xkb_state(),
|
EiContext::Receiver => self.seat.latest_kb_state(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use {
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
clientmem::{ClientMem, ClientMemError},
|
clientmem::{ClientMem, ClientMemError},
|
||||||
ifs::wl_seat::WlSeatGlobal,
|
ifs::wl_seat::WlSeatGlobal,
|
||||||
|
kbvm::{KbvmError, KbvmMap},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
libinput::consts::{
|
libinput::consts::{
|
||||||
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||||
|
|
@ -13,7 +14,6 @@ use {
|
||||||
state::{DeviceHandlerData, InputDeviceData},
|
state::{DeviceHandlerData, InputDeviceData},
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::errorfmt::ErrorFmt,
|
||||||
wire::{jay_input::*, JayInputId},
|
wire::{jay_input::*, JayInputId},
|
||||||
xkbcommon::{XkbCommonError, XkbKeymap},
|
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
thiserror::Error,
|
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.client.event(Keymap {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
keymap: map.map.clone(),
|
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>
|
fn set_keymap_impl<F>(&self, keymap: &Rc<OwnedFd>, len: u32, f: F) -> Result<(), JayInputError>
|
||||||
where
|
where
|
||||||
F: FnOnce(&Rc<XkbKeymap>) -> Result<(), JayInputError>,
|
F: FnOnce(&Rc<KbvmMap>) -> Result<(), JayInputError>,
|
||||||
{
|
{
|
||||||
let cm = Rc::new(ClientMem::new_private(
|
let cm = Rc::new(ClientMem::new_private(
|
||||||
keymap,
|
keymap,
|
||||||
|
|
@ -180,7 +180,7 @@ impl JayInput {
|
||||||
let mut map = vec![];
|
let mut map = vec![];
|
||||||
cm.read(&mut map)?;
|
cm.read(&mut map)?;
|
||||||
self.or_error(|| {
|
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)?;
|
f(&map)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|
@ -489,7 +489,7 @@ pub enum JayInputError {
|
||||||
#[error("Could not access client memory")]
|
#[error("Could not access client memory")]
|
||||||
ClientMemError(#[from] ClientMemError),
|
ClientMemError(#[from] ClientMemError),
|
||||||
#[error("Could not parse keymap")]
|
#[error("Could not parse keymap")]
|
||||||
XkbCommonError(#[from] XkbCommonError),
|
ParseKeymap(#[from] KbvmError),
|
||||||
#[error("Output is not connected")]
|
#[error("Output is not connected")]
|
||||||
OutputNotConnected,
|
OutputNotConnected,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,8 @@ use {
|
||||||
},
|
},
|
||||||
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
||||||
},
|
},
|
||||||
keyboard::{DynKeyboardState, KeyboardState},
|
kbvm::{KbvmMap, KbvmMapId, KbvmState, PhysicalKeyboardState},
|
||||||
|
keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
|
|
@ -83,8 +84,8 @@ use {
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, bindings::PerClientBindings, clonecell::CloneCell,
|
asyncevent::AsyncEvent, bindings::PerClientBindings, clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, linkedlist::LinkedNode, numcell::NumCell,
|
copyhashmap::CopyHashMap, linkedlist::LinkedNode, numcell::NumCell, rc_eq::rc_eq,
|
||||||
rc_eq::rc_eq, smallmap::SmallMap,
|
smallmap::SmallMap,
|
||||||
},
|
},
|
||||||
wire::{
|
wire::{
|
||||||
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
||||||
|
|
@ -92,7 +93,6 @@ use {
|
||||||
ZwpTextInputV3Id,
|
ZwpTextInputV3Id,
|
||||||
},
|
},
|
||||||
wire_ei::EiSeatId,
|
wire_ei::EiSeatId,
|
||||||
xkbcommon::{KeymapId, XkbKeymap, XkbState},
|
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
smallvec::SmallVec,
|
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);
|
linear_ids!(SeatIds, SeatId);
|
||||||
|
|
||||||
pub struct WlSeatGlobal {
|
pub struct WlSeatGlobal {
|
||||||
|
|
@ -169,10 +176,12 @@ pub struct WlSeatGlobal {
|
||||||
>,
|
>,
|
||||||
data_control_devices: CopyHashMap<DataControlDeviceId, Rc<dyn DynDataControlDevice>>,
|
data_control_devices: CopyHashMap<DataControlDeviceId, Rc<dyn DynDataControlDevice>>,
|
||||||
repeat_rate: Cell<(i32, i32)>,
|
repeat_rate: Cell<(i32, i32)>,
|
||||||
seat_kb_map: CloneCell<Rc<XkbKeymap>>,
|
seat_kb_map: CloneCell<Rc<KbvmMap>>,
|
||||||
seat_xkb_state: CloneCell<Rc<RefCell<XkbState>>>,
|
seat_kb_state: CloneCell<Rc<RefCell<KbvmState>>>,
|
||||||
latest_kb_state: CloneCell<Rc<dyn DynKeyboardState>>,
|
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>,
|
cursor_user_group: Rc<CursorUserGroup>,
|
||||||
pointer_cursor: Rc<CursorUser>,
|
pointer_cursor: Rc<CursorUser>,
|
||||||
tree_changed: Rc<AsyncEvent>,
|
tree_changed: Rc<AsyncEvent>,
|
||||||
|
|
@ -214,13 +223,11 @@ const CHANGE_TREE: u32 = 1 << 1;
|
||||||
|
|
||||||
impl WlSeatGlobal {
|
impl WlSeatGlobal {
|
||||||
pub fn new(name: GlobalName, seat_name: &str, state: &Rc<State>) -> Rc<Self> {
|
pub fn new(name: GlobalName, seat_name: &str, state: &Rc<State>) -> Rc<Self> {
|
||||||
let seat_xkb_state = state
|
let seat_kb_state = state.default_keymap.state(state.keyboard_state_ids.next());
|
||||||
.default_keymap
|
let latest_kb_state_id = seat_kb_state.kb_state.id;
|
||||||
.state(state.keyboard_state_ids.next())
|
let seat_kb_state = Rc::new(RefCell::new(seat_kb_state));
|
||||||
.map(|s| Rc::new(RefCell::new(s)))
|
let kb_states = CopyHashMap::new();
|
||||||
.unwrap();
|
kb_states.set(state.default_keymap.id, Rc::downgrade(&seat_kb_state));
|
||||||
let xkb_states = CopyHashMap::new();
|
|
||||||
xkb_states.set(state.default_keymap.id, Rc::downgrade(&seat_xkb_state));
|
|
||||||
let cursor_user_group = CursorUserGroup::create(state);
|
let cursor_user_group = CursorUserGroup::create(state);
|
||||||
let cursor_user = cursor_user_group.create_user();
|
let cursor_user = cursor_user_group.create_user();
|
||||||
cursor_user.activate();
|
cursor_user.activate();
|
||||||
|
|
@ -243,9 +250,11 @@ impl WlSeatGlobal {
|
||||||
primary_selection_devices: RefCell::new(Default::default()),
|
primary_selection_devices: RefCell::new(Default::default()),
|
||||||
repeat_rate: Cell::new((25, 250)),
|
repeat_rate: Cell::new((25, 250)),
|
||||||
seat_kb_map: CloneCell::new(state.default_keymap.clone()),
|
seat_kb_map: CloneCell::new(state.default_keymap.clone()),
|
||||||
seat_xkb_state: CloneCell::new(seat_xkb_state.clone()),
|
seat_kb_state: CloneCell::new(seat_kb_state.clone()),
|
||||||
latest_kb_state: CloneCell::new(seat_xkb_state.clone()),
|
latest_kb_state: CloneCell::new(seat_kb_state.clone()),
|
||||||
xkb_states,
|
latest_kb_state_id: Cell::new(latest_kb_state_id),
|
||||||
|
kb_states,
|
||||||
|
kb_devices: Default::default(),
|
||||||
cursor_user_group,
|
cursor_user_group,
|
||||||
pointer_cursor: cursor_user,
|
pointer_cursor: cursor_user,
|
||||||
tree_changed: Default::default(),
|
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()
|
self.seat_kb_map.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,53 +505,46 @@ impl WlSeatGlobal {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_seat_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
pub fn set_seat_keymap(&self, keymap: &Rc<KbvmMap>) {
|
||||||
let Some(xkb_state) = self.get_xkb_state(keymap) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
self.seat_kb_map.set(keymap.clone());
|
self.seat_kb_map.set(keymap.clone());
|
||||||
let old = self.seat_xkb_state.set(xkb_state.clone());
|
let new = self.get_kb_state(keymap);
|
||||||
if !rc_eq(&old, &xkb_state) {
|
let old = self.seat_kb_state.set(new.clone());
|
||||||
self.handle_xkb_state_change(&old.borrow(), &xkb_state.borrow());
|
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| {
|
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 {
|
let Some(surface) = self.keyboard_node.get().node_into_surface() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let serial = surface.client.next_serial();
|
let serial = surface.client.next_serial();
|
||||||
self.surface_kb_event(Version::ALL, &surface, |kb| {
|
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.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>>> {
|
pub fn get_kb_state(&self, keymap: &Rc<KbvmMap>) -> Rc<RefCell<KbvmState>> {
|
||||||
if let Some(weak) = self.xkb_states.get(&keymap.id) {
|
if let Some(weak) = self.kb_states.get(&keymap.id) {
|
||||||
if let Some(state) = weak.upgrade() {
|
if let Some(state) = weak.upgrade() {
|
||||||
return Some(state);
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.xkb_states
|
self.kb_states
|
||||||
.lock()
|
.lock()
|
||||||
.retain(|_, state| state.strong_count() > 0);
|
.retain(|_, state| state.strong_count() > 0);
|
||||||
match keymap.state(self.state.keyboard_state_ids.next()) {
|
let s = keymap.state(self.state.keyboard_state_ids.next());
|
||||||
Ok(s) => {
|
let s = Rc::new(RefCell::new(s));
|
||||||
let s = Rc::new(RefCell::new(s));
|
self.kb_states.set(keymap.id, Rc::downgrade(&s));
|
||||||
self.xkb_states.set(keymap.id, Rc::downgrade(&s));
|
s
|
||||||
Some(s)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not create xkb state: {}", ErrorFmt(e));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_for_lock(self: &Rc<Self>) {
|
pub fn prepare_for_lock(self: &Rc<Self>) {
|
||||||
|
|
@ -1031,16 +1033,17 @@ impl WlSeatGlobal {
|
||||||
self.update_capabilities();
|
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.ei_seats.remove(&(ei.client.id, ei.id));
|
||||||
|
self.destroy_physical_keyboard(ei.keyboard_id);
|
||||||
self.update_capabilities();
|
self.update_capabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seat_xkb_state(&self) -> Rc<dyn DynKeyboardState> {
|
pub fn seat_kb_state(&self) -> Rc<dyn DynKeyboardState> {
|
||||||
self.seat_xkb_state.get()
|
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()
|
self.latest_kb_state.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1091,6 +1094,33 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
self.focus_node_with_serial(node, serial);
|
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 {
|
impl CursorUserOwner for WlSeatGlobal {
|
||||||
|
|
@ -1178,7 +1208,7 @@ impl WlSeatRequestHandler for WlSeat {
|
||||||
p.enter(
|
p.enter(
|
||||||
self.client.next_serial(),
|
self.client.next_serial(),
|
||||||
surface.id,
|
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 {
|
impl DeviceHandlerData {
|
||||||
pub fn set_seat(&self, seat: Option<Rc<WlSeatGlobal>>) {
|
pub fn set_seat(&self, seat: Option<Rc<WlSeatGlobal>>) {
|
||||||
let old = self.seat.set(seat.clone());
|
if let Some(new) = &seat {
|
||||||
if let Some(old) = old {
|
if let Some(old) = self.seat.get() {
|
||||||
if let Some(new) = &seat {
|
|
||||||
if old.id() == new.id() {
|
if old.id() == new.id() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let xkb_state = self.get_effective_xkb_state(&old);
|
} else {
|
||||||
let xkb_state = &mut *xkb_state.borrow_mut();
|
if self.seat.is_none() {
|
||||||
xkb_state.reset();
|
return;
|
||||||
old.handle_xkb_state_change(xkb_state, xkb_state);
|
}
|
||||||
|
}
|
||||||
|
self.destroy_physical_keyboard_state();
|
||||||
|
let old = self.seat.set(seat.clone());
|
||||||
|
if let Some(old) = old {
|
||||||
if let Some(info) = &self.tablet_init {
|
if let Some(info) = &self.tablet_init {
|
||||||
old.tablet_remove_tablet(info.id);
|
old.tablet_remove_tablet(info.id);
|
||||||
}
|
}
|
||||||
|
|
@ -1287,7 +1320,6 @@ impl DeviceHandlerData {
|
||||||
old.update_capabilities();
|
old.update_capabilities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update_xkb_state();
|
|
||||||
if let Some(seat) = &seat {
|
if let Some(seat) = &seat {
|
||||||
if let Some(info) = &self.tablet_init {
|
if let Some(info) = &self.tablet_init {
|
||||||
seat.tablet_add_tablet(self.device.id(), info);
|
seat.tablet_add_tablet(self.device.id(), info);
|
||||||
|
|
@ -1302,34 +1334,15 @@ impl DeviceHandlerData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keymap(&self, keymap: Option<Rc<XkbKeymap>>) {
|
fn destroy_physical_keyboard_state(&self) {
|
||||||
self.keymap.set(keymap);
|
if let Some(seat) = self.seat.get() {
|
||||||
self.update_xkb_state();
|
seat.destroy_physical_keyboard(self.keyboard_id);
|
||||||
}
|
|
||||||
|
|
||||||
fn get_effective_xkb_state(&self, seat: &WlSeatGlobal) -> Rc<RefCell<XkbState>> {
|
|
||||||
match self.xkb_state.get() {
|
|
||||||
Some(s) => s,
|
|
||||||
_ => seat.seat_xkb_state.get(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_xkb_state(&self) {
|
|
||||||
let Some(seat) = self.seat.get() else {
|
|
||||||
self.xkb_state.take();
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
let old = self.get_effective_xkb_state(&seat);
|
}
|
||||||
self.xkb_state.take();
|
|
||||||
if let Some(keymap) = self.keymap.get() {
|
pub fn set_keymap(&self, keymap: Option<Rc<KbvmMap>>) {
|
||||||
if let Some(state) = seat.get_xkb_state(&keymap) {
|
self.destroy_physical_keyboard_state();
|
||||||
self.xkb_state.set(Some(state));
|
self.keymap.set(keymap);
|
||||||
}
|
|
||||||
}
|
|
||||||
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_output(&self, output: Option<&WlOutputGlobal>) {
|
pub fn set_output(&self, output: Option<&WlOutputGlobal>) {
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,19 @@ use {
|
||||||
},
|
},
|
||||||
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
||||||
},
|
},
|
||||||
|
kbvm::KbvmState,
|
||||||
keyboard::KeyboardState,
|
keyboard::KeyboardState,
|
||||||
object::Version,
|
object::Version,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
state::DeviceHandlerData,
|
state::DeviceHandlerData,
|
||||||
tree::{Direction, Node, ToplevelNode},
|
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,
|
wire::WlDataOfferId,
|
||||||
xkbcommon::{XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
|
||||||
},
|
},
|
||||||
isnt::std_1::primitive::{IsntSlice2Ext, IsntSliceExt},
|
isnt::std_1::primitive::IsntSliceExt,
|
||||||
jay_config::{
|
jay_config::{
|
||||||
input::SwitchEvent,
|
input::SwitchEvent,
|
||||||
keyboard::{
|
keyboard::{
|
||||||
|
|
@ -50,8 +53,9 @@ use {
|
||||||
syms::{KeySym, SYM_Escape},
|
syms::{KeySym, SYM_Escape},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
kbvm::{state_machine::Event, ModifierMask},
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{cell::RefCell, collections::hash_map::Entry, rc::Rc},
|
std::{cell::RefCell, collections::hash_map::Entry, mem, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -320,7 +324,11 @@ impl WlSeatGlobal {
|
||||||
time_usec,
|
time_usec,
|
||||||
key,
|
key,
|
||||||
state,
|
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 {
|
InputEvent::ConnectorPosition {
|
||||||
time_usec,
|
time_usec,
|
||||||
connector,
|
connector,
|
||||||
|
|
@ -779,130 +787,129 @@ impl WlSeatGlobal {
|
||||||
self.touch_owner.frame(self);
|
self.touch_owner.frame(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_event_with_seat_state(
|
pub fn key_events(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
time_usec: u64,
|
time_usec: u64,
|
||||||
key: u32,
|
events: &SyncQueue<Event>,
|
||||||
key_state: KeyState,
|
kbvm_state_rc: &Rc<RefCell<KbvmState>>,
|
||||||
) {
|
) {
|
||||||
self.key_event(time_usec, key, key_state, || self.seat_xkb_state.get());
|
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);
|
||||||
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 shortcuts = SmallVec::<[_; 1]>::new();
|
let mut shortcuts = SmallVec::<[_; 1]>::new();
|
||||||
let new_mods;
|
let mut components_changed = false;
|
||||||
{
|
while let Some(event) = events.pop() {
|
||||||
let mut mods = xkb_state.mods().mods.0 & !(CAPS.0 | NUM.0);
|
components_changed |= kbvm_state.kb_state.mods.apply_event(event);
|
||||||
if state == wl_keyboard::RELEASED {
|
let (key_state, kc) = match event {
|
||||||
mods |= RELEASE.0;
|
Event::KeyDown(kc) => (KeyState::Pressed, kc),
|
||||||
}
|
Event::KeyUp(kc) => (KeyState::Released, kc),
|
||||||
let scs = &*self.shortcuts.borrow();
|
_ => continue,
|
||||||
let keysyms = xkb_state.unmodified_keysyms(key);
|
};
|
||||||
let mut revert_pointer_to_default = false;
|
let update_pressed_keys = |kbvm_state: &mut KbvmState| {
|
||||||
for &sym in keysyms {
|
let pk = &mut kbvm_state.kb_state.pressed_keys;
|
||||||
if sym == SYM_Escape.0 && mods == 0 {
|
match key_state {
|
||||||
revert_pointer_to_default = true;
|
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) {
|
shortcuts.clear();
|
||||||
for (key_mods, mask) in key_mods {
|
{
|
||||||
if mods & mask == key_mods {
|
let mut mods = kbvm_state.kb_state.mods.mods.0 & !(CAPS.0 | NUM.0);
|
||||||
shortcuts.push(InvokedShortcut {
|
if key_state == KeyState::Released {
|
||||||
unmasked_mods: Modifiers(mods),
|
mods |= RELEASE.0;
|
||||||
effective_mods: Modifiers(key_mods),
|
}
|
||||||
sym: KeySym(sym),
|
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 {
|
||||||
if revert_pointer_to_default {
|
drop(kbvm_state);
|
||||||
drop(xkb_state);
|
self.pointer_owner.revert_to_default(self);
|
||||||
self.pointer_owner.revert_to_default(self);
|
kbvm_state = kbvm_state_rc.borrow_mut();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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| {
|
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 {
|
if shortcuts.is_not_empty() {
|
||||||
Some(g) => g.on_modifiers(&xkb_state.kb_state),
|
self.forward.set(key_state == KeyState::Released);
|
||||||
_ => node.node_on_mods(self, &xkb_state.kb_state),
|
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 {
|
self.send_components(&mut components_changed, &kbvm_state);
|
||||||
KeyState::Released => {
|
}
|
||||||
xkb_state.kb_state.pressed_keys.remove(&key);
|
|
||||||
}
|
fn send_components(&self, components_changed: &mut bool, kbvm_state: &KbvmState) {
|
||||||
KeyState::Pressed => {
|
if !mem::take(components_changed) {
|
||||||
xkb_state.kb_state.pressed_keys.insert(key);
|
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>)) {
|
pub(super) fn for_each_ei_seat(&self, mut f: impl FnMut(&Rc<EiSeat>)) {
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
client::ClientError,
|
client::ClientError,
|
||||||
ifs::wl_seat::WlSeat,
|
ifs::wl_seat::WlSeat,
|
||||||
keyboard::{KeyboardState, KeyboardStateId},
|
keyboard::{KeyboardError, KeyboardState, KeyboardStateId},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::errorfmt::ErrorFmt,
|
||||||
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
||||||
xkbcommon::XkbCommonError,
|
|
||||||
},
|
},
|
||||||
kbvm::Components,
|
kbvm::Components,
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
|
|
@ -183,6 +182,6 @@ pub enum WlKeyboardError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<ClientError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
XkbCommonError(#[from] XkbCommonError),
|
KeyboardError(#[from] KeyboardError),
|
||||||
}
|
}
|
||||||
efrom!(WlKeyboardError, ClientError);
|
efrom!(WlKeyboardError, ClientError);
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ use {
|
||||||
},
|
},
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
|
kbvm::KbvmError,
|
||||||
keyboard::KeyboardState,
|
keyboard::KeyboardState,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
wire::{zwp_virtual_keyboard_v1::*, ZwpVirtualKeyboardV1Id},
|
wire::{zwp_virtual_keyboard_v1::*, ZwpVirtualKeyboardV1Id},
|
||||||
xkbcommon::XkbCommonError,
|
|
||||||
},
|
},
|
||||||
std::{cell::RefCell, rc::Rc},
|
std::{cell::RefCell, rc::Rc},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -74,8 +74,8 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
|
||||||
let map = self
|
let map = self
|
||||||
.client
|
.client
|
||||||
.state
|
.state
|
||||||
.xkb_ctx
|
.kb_ctx
|
||||||
.keymap_from_str(&map)
|
.parse_keymap(&map)
|
||||||
.map_err(ZwpVirtualKeyboardV1Error::ParseKeymap)?;
|
.map_err(ZwpVirtualKeyboardV1Error::ParseKeymap)?;
|
||||||
*self.kb_state.borrow_mut() = KeyboardState {
|
*self.kb_state.borrow_mut() = KeyboardState {
|
||||||
id: self.client.state.keyboard_state_ids.next(),
|
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),
|
wl_keyboard::RELEASED => kb_state.pressed_keys.remove(&req.key),
|
||||||
_ => kb_state.pressed_keys.insert(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());
|
self.seat.latest_kb_state.set(self.kb_state.clone());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -118,6 +119,7 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
|
||||||
self.for_each_kb(|serial, surface, kb| {
|
self.for_each_kb(|serial, surface, kb| {
|
||||||
kb.on_mods_changed(serial, surface.id, &kb_state);
|
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());
|
self.seat.latest_kb_state.set(self.kb_state.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -154,6 +156,6 @@ pub enum ZwpVirtualKeyboardV1Error {
|
||||||
#[error("Could not read the keymap")]
|
#[error("Could not read the keymap")]
|
||||||
ReadKeymap(#[source] ClientMemError),
|
ReadKeymap(#[source] ClientMemError),
|
||||||
#[error("Could not parse the keymap")]
|
#[error("Could not parse the keymap")]
|
||||||
ParseKeymap(#[source] XkbCommonError),
|
ParseKeymap(#[source] KbvmError),
|
||||||
}
|
}
|
||||||
efrom!(ZwpVirtualKeyboardV1Error, ClientError);
|
efrom!(ZwpVirtualKeyboardV1Error, ClientError);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
backend::KeyState,
|
backend::KeyState,
|
||||||
clientmem::ClientMem,
|
clientmem::ClientMem,
|
||||||
it::{test_error::TestResult, testrun::TestRun},
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
xkbcommon::XkbContext,
|
kbvm::KbvmContext,
|
||||||
},
|
},
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
|
|
@ -14,8 +14,8 @@ testcase!();
|
||||||
|
|
||||||
async fn test(run: Rc<TestRun>) -> TestResult {
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
let virtual_keymap_str = {
|
let virtual_keymap_str = {
|
||||||
let xkb = XkbContext::new()?;
|
let xkb = KbvmContext::default();
|
||||||
let map = xkb.keymap_from_str(VIRTUAL_KEYMAP).unwrap();
|
let map = xkb.parse_keymap(VIRTUAL_KEYMAP.as_bytes()).unwrap();
|
||||||
read_keymap(&map.map, map.map_len)
|
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 {
|
use {
|
||||||
crate::utils::vecset::VecSet,
|
crate::utils::{oserror::OsError, vecset::VecSet},
|
||||||
kbvm::Components,
|
kbvm::Components,
|
||||||
std::{
|
std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
rc::Rc,
|
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);
|
linear_ids!(KeyboardStateIds, KeyboardStateId, u64);
|
||||||
|
|
||||||
pub struct KeyboardState {
|
pub struct KeyboardState {
|
||||||
|
|
@ -27,3 +36,23 @@ impl DynKeyboardState for RefCell<KeyboardState> {
|
||||||
self.borrow()
|
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 {
|
macro_rules! bitor {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
impl std::ops::BitOr for $name {
|
impl std::ops::BitOr for $name {
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ mod ifs;
|
||||||
mod io_uring;
|
mod io_uring;
|
||||||
#[cfg(feature = "it")]
|
#[cfg(feature = "it")]
|
||||||
mod it;
|
mod it;
|
||||||
|
mod kbvm;
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod libinput;
|
mod libinput;
|
||||||
mod logger;
|
mod logger;
|
||||||
|
|
@ -109,7 +110,6 @@ mod wire_ei;
|
||||||
mod wire_xcon;
|
mod wire_xcon;
|
||||||
mod wl_usr;
|
mod wl_usr;
|
||||||
mod xcon;
|
mod xcon;
|
||||||
mod xkbcommon;
|
|
||||||
mod xwayland;
|
mod xwayland;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
13
src/state.rs
13
src/state.rs
|
|
@ -48,7 +48,7 @@ use {
|
||||||
wl_output::{OutputGlobalOpt, OutputId, PersistentOutputState},
|
wl_output::{OutputGlobalOpt, OutputId, PersistentOutputState},
|
||||||
wl_seat::{
|
wl_seat::{
|
||||||
tablet::{TabletIds, TabletInit, TabletPadIds, TabletPadInit, TabletToolIds},
|
tablet::{TabletIds, TabletInit, TabletPadIds, TabletPadInit, TabletToolIds},
|
||||||
SeatIds, WlSeatGlobal,
|
PhysicalKeyboardId, PhysicalKeyboardIds, SeatIds, WlSeatGlobal,
|
||||||
},
|
},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
tray::TrayItemIds,
|
tray::TrayItemIds,
|
||||||
|
|
@ -66,6 +66,7 @@ use {
|
||||||
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global,
|
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global,
|
||||||
},
|
},
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
|
kbvm::{KbvmContext, KbvmMap},
|
||||||
keyboard::KeyboardStateIds,
|
keyboard::KeyboardStateIds,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
|
|
@ -100,7 +101,6 @@ use {
|
||||||
ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayRenderCtxId, JaySeatEventsId,
|
ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayRenderCtxId, JaySeatEventsId,
|
||||||
JayWorkspaceWatcherId, ZwpLinuxDmabufFeedbackV1Id,
|
JayWorkspaceWatcherId, ZwpLinuxDmabufFeedbackV1Id,
|
||||||
},
|
},
|
||||||
xkbcommon::{XkbContext, XkbKeymap, XkbState},
|
|
||||||
xwayland::{self, XWaylandEvent},
|
xwayland::{self, XWaylandEvent},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
|
|
@ -122,10 +122,10 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub xkb_ctx: XkbContext,
|
pub kb_ctx: KbvmContext,
|
||||||
pub backend: CloneCell<Rc<dyn Backend>>,
|
pub backend: CloneCell<Rc<dyn Backend>>,
|
||||||
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
||||||
pub default_keymap: Rc<XkbKeymap>,
|
pub default_keymap: Rc<KbvmMap>,
|
||||||
pub eng: Rc<AsyncEngine>,
|
pub eng: Rc<AsyncEngine>,
|
||||||
pub render_ctx: CloneCell<Option<Rc<dyn GfxContext>>>,
|
pub render_ctx: CloneCell<Option<Rc<dyn GfxContext>>>,
|
||||||
pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>,
|
pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>,
|
||||||
|
|
@ -206,6 +206,7 @@ pub struct State {
|
||||||
pub wait_for_sync_obj: Rc<WaitForSyncObj>,
|
pub wait_for_sync_obj: Rc<WaitForSyncObj>,
|
||||||
pub explicit_sync_enabled: Cell<bool>,
|
pub explicit_sync_enabled: Cell<bool>,
|
||||||
pub keyboard_state_ids: KeyboardStateIds,
|
pub keyboard_state_ids: KeyboardStateIds,
|
||||||
|
pub physical_keyboard_ids: PhysicalKeyboardIds,
|
||||||
pub security_context_acceptors: SecurityContextAcceptors,
|
pub security_context_acceptors: SecurityContextAcceptors,
|
||||||
pub cursor_user_group_ids: CursorUserGroupIds,
|
pub cursor_user_group_ids: CursorUserGroupIds,
|
||||||
pub cursor_user_ids: CursorUserIds,
|
pub cursor_user_ids: CursorUserIds,
|
||||||
|
|
@ -327,13 +328,13 @@ pub struct InputDeviceData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DeviceHandlerData {
|
pub struct DeviceHandlerData {
|
||||||
|
pub keyboard_id: PhysicalKeyboardId,
|
||||||
pub seat: CloneCell<Option<Rc<WlSeatGlobal>>>,
|
pub seat: CloneCell<Option<Rc<WlSeatGlobal>>>,
|
||||||
pub px_per_scroll_wheel: Cell<f64>,
|
pub px_per_scroll_wheel: Cell<f64>,
|
||||||
pub device: Rc<dyn InputDevice>,
|
pub device: Rc<dyn InputDevice>,
|
||||||
pub syspath: Option<String>,
|
pub syspath: Option<String>,
|
||||||
pub devnode: Option<String>,
|
pub devnode: Option<String>,
|
||||||
pub keymap: CloneCell<Option<Rc<XkbKeymap>>>,
|
pub keymap: CloneCell<Option<Rc<KbvmMap>>>,
|
||||||
pub xkb_state: CloneCell<Option<Rc<RefCell<XkbState>>>>,
|
|
||||||
pub output: CloneCell<Option<Rc<OutputGlobalOpt>>>,
|
pub output: CloneCell<Option<Rc<OutputGlobalOpt>>>,
|
||||||
pub tablet_init: Option<Box<TabletInit>>,
|
pub tablet_init: Option<Box<TabletInit>>,
|
||||||
pub tablet_pad_init: Option<Box<TabletPadInit>>,
|
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),
|
Some(dev_t) => udev_props(dev_t, 3),
|
||||||
};
|
};
|
||||||
let data = Rc::new(DeviceHandlerData {
|
let data = Rc::new(DeviceHandlerData {
|
||||||
|
keyboard_id: state.physical_keyboard_ids.next(),
|
||||||
seat: Default::default(),
|
seat: Default::default(),
|
||||||
px_per_scroll_wheel: Cell::new(PX_PER_SCROLL),
|
px_per_scroll_wheel: Cell::new(PX_PER_SCROLL),
|
||||||
device: dev.clone(),
|
device: dev.clone(),
|
||||||
syspath: props.syspath,
|
syspath: props.syspath,
|
||||||
devnode: props.devnode,
|
devnode: props.devnode,
|
||||||
keymap: Default::default(),
|
keymap: Default::default(),
|
||||||
xkb_state: Default::default(),
|
|
||||||
output: Default::default(),
|
output: Default::default(),
|
||||||
tablet_init: dev.tablet_info(),
|
tablet_init: dev.tablet_info(),
|
||||||
tablet_pad_init: dev.tablet_pad_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> {
|
pub fn pop(&self) -> Option<T> {
|
||||||
unsafe { self.el.get().deref_mut().pop_front() }
|
unsafe { self.el.get().deref_mut().pop_front() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,4 +43,8 @@ impl<T: PartialEq> VecSet<T> {
|
||||||
}
|
}
|
||||||
false
|
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