Merge pull request #345 from mahkoh/jorth/kbvm
keyboard: replace xkbcommon by kbvm
This commit is contained in:
commit
4e23f4824e
41 changed files with 794 additions and 892 deletions
71
Cargo.lock
generated
71
Cargo.lock
generated
|
|
@ -298,6 +298,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "debug-fn"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24efe21bd9a78102d1225f10f0a41d9d5b43f4df7ae8235f39a9c79e4d476c1e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
|
@ -369,6 +375,12 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
|
|
@ -466,6 +478,9 @@ name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
|
@ -564,6 +579,7 @@ dependencies = [
|
||||||
"jay-algorithms",
|
"jay-algorithms",
|
||||||
"jay-config",
|
"jay-config",
|
||||||
"jay-toml-config",
|
"jay-toml-config",
|
||||||
|
"kbvm",
|
||||||
"libloading",
|
"libloading",
|
||||||
"linearize",
|
"linearize",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -628,6 +644,40 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kbvm"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "723f422224bcf2bcbf788f71bc022a269b5abf7f02c50b07f91cdc9dd67fa902"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"bstr",
|
||||||
|
"cfg-if",
|
||||||
|
"debug-fn",
|
||||||
|
"hashbrown",
|
||||||
|
"indexmap",
|
||||||
|
"isnt",
|
||||||
|
"kbvm-proc",
|
||||||
|
"linearize",
|
||||||
|
"log",
|
||||||
|
"pkg-config",
|
||||||
|
"secure-execution",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kbvm-proc"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28067e7361c0069c3753795d131653f9ea5333aeb35a3855fb2de66447c48ac8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.96",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -874,6 +924,12 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.16"
|
version = "0.17.16"
|
||||||
|
|
@ -1069,6 +1125,15 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secure-execution"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23ceccce47e43305aa02a0d9182ad09364357d073447435d7ae2e219ce750e55"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.217"
|
version = "1.0.217"
|
||||||
|
|
@ -1349,6 +1414,12 @@ version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsafe-libyaml"
|
name = "unsafe-libyaml"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ linearize = { version = "0.1.3", features = ["derive"] }
|
||||||
png = "0.17.13"
|
png = "0.17.13"
|
||||||
rustc-demangle = { version = "0.1.24", optional = true }
|
rustc-demangle = { version = "0.1.24", optional = true }
|
||||||
tracy-client-sys = { version = "0.24.1", features = ["ondemand", "manual-lifetime", "debuginfod"], optional = true }
|
tracy-client-sys = { version = "0.24.1", features = ["ondemand", "manual-lifetime", "debuginfod"], optional = true }
|
||||||
|
kbvm = "0.1.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
repc = "0.1.1"
|
repc = "0.1.1"
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Needs jay-compositor release.
|
||||||
|
|
||||||
# 1.8.0
|
# 1.8.0
|
||||||
|
|
||||||
- Needs jay-config release.
|
- Needs jay-config release.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
This release replaces xkbcommon by the kbvm crate.
|
||||||
|
|
||||||
|
This is a huge change in how input is handled. The intention is that this is completely
|
||||||
|
invisible to users.
|
||||||
|
|
||||||
|
Therefore this release contains only this change. You can downgrade to the previous
|
||||||
|
release to switch back to xkbcommon without any loss in functionality. In this case please
|
||||||
|
report what is broken.
|
||||||
|
|
||||||
# 1.8.0 (2025-01-27)
|
# 1.8.0 (2025-01-27)
|
||||||
|
|
||||||
- Various bugfixes.
|
- Various bugfixes.
|
||||||
|
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use {
|
||||||
ei_ifs::ei_device::{EiDevice, EiDeviceInterface},
|
ei_ifs::ei_device::{EiDevice, EiDeviceInterface},
|
||||||
ei_object::{EiObject, EiVersion},
|
ei_object::{EiObject, EiVersion},
|
||||||
},
|
},
|
||||||
|
keyboard::KeyboardState,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
wire_ei::{
|
wire_ei::{
|
||||||
ei_keyboard::{
|
ei_keyboard::{
|
||||||
|
|
@ -13,7 +14,6 @@ use {
|
||||||
},
|
},
|
||||||
EiKeyboardId,
|
EiKeyboardId,
|
||||||
},
|
},
|
||||||
xkbcommon::KeyboardState,
|
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -36,8 +36,8 @@ impl EiKeyboard {
|
||||||
self.client.event(Keymap {
|
self.client.event(Keymap {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
keymap_type: KEYMAP_TYPE_XKB,
|
keymap_type: KEYMAP_TYPE_XKB,
|
||||||
size: state.map_len as _,
|
size: state.map.len as _,
|
||||||
keymap: state.map.clone(),
|
keymap: state.map.map.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,18 +45,21 @@ impl EiKeyboard {
|
||||||
self.client.event(Modifiers {
|
self.client.event(Modifiers {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial: self.client.serial(),
|
serial: self.client.serial(),
|
||||||
depressed: state.mods.mods_depressed,
|
depressed: state.mods.mods_pressed.0,
|
||||||
locked: state.mods.mods_locked,
|
locked: state.mods.mods_locked.0,
|
||||||
latched: state.mods.mods_latched,
|
latched: state.mods.mods_latched.0,
|
||||||
group: state.mods.group,
|
group: state.mods.group.0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_key(&self, key: u32, state: u32) {
|
pub fn send_key(&self, key: u32, state: KeyState) {
|
||||||
self.client.event(ServerKey {
|
self.client.event(ServerKey {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
key,
|
key,
|
||||||
state,
|
state: match state {
|
||||||
|
KeyState::Released => 0,
|
||||||
|
KeyState::Pressed => 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ 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},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
tree::Node,
|
tree::Node,
|
||||||
utils::{array, bitflags::BitflagsExt, clonecell::CloneCell},
|
utils::{array, bitflags::BitflagsExt, clonecell::CloneCell},
|
||||||
|
|
@ -26,7 +27,6 @@ use {
|
||||||
},
|
},
|
||||||
EiSeatId,
|
EiSeatId,
|
||||||
},
|
},
|
||||||
xkbcommon::{DynKeyboardState, KeyboardState, KeyboardStateId},
|
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -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() {
|
||||||
|
|
@ -106,7 +111,7 @@ impl EiSeat {
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
time_usec: u64,
|
time_usec: u64,
|
||||||
key: u32,
|
key: u32,
|
||||||
state: u32,
|
state: KeyState,
|
||||||
kb_state: &KeyboardState,
|
kb_state: &KeyboardState,
|
||||||
) {
|
) {
|
||||||
if self.is_sender() {
|
if self.is_sender() {
|
||||||
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::gfx_apis::gl::{
|
||||||
gfx_apis::gl::{
|
egl::sys::{EGLDisplay, EGL_EXTENSIONS},
|
||||||
egl::sys::{EGLDisplay, EGL_EXTENSIONS},
|
gl::sys::GL_EXTENSIONS,
|
||||||
gl::sys::GL_EXTENSIONS,
|
sys::{EGL, GLESV2},
|
||||||
sys::{EGL, GLESV2},
|
RenderError,
|
||||||
RenderError,
|
|
||||||
},
|
|
||||||
utils::trim::AsciiTrim,
|
|
||||||
},
|
},
|
||||||
ahash::AHashSet,
|
ahash::AHashSet,
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
|
|
@ -21,7 +18,7 @@ unsafe fn get_extensions(ext: *const c::c_char) -> Option<AHashSet<String>> {
|
||||||
let mut res = AHashSet::new();
|
let mut res = AHashSet::new();
|
||||||
let ext = unsafe { CStr::from_ptr(ext).to_bytes() };
|
let ext = unsafe { CStr::from_ptr(ext).to_bytes() };
|
||||||
for part in ext.split_str(" ") {
|
for part in ext.split_str(" ") {
|
||||||
let name = part.trim();
|
let name = part.trim_ascii();
|
||||||
if name.len() > 0 {
|
if name.len() > 0 {
|
||||||
if let Ok(s) = str::from_utf8(name) {
|
if let Ok(s) = str::from_utf8(name) {
|
||||||
res.insert(s.to_string());
|
res.insert(s.to_string());
|
||||||
|
|
|
||||||
|
|
@ -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,11 +72,11 @@ 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.map.clone(),
|
||||||
keymap_len: (map.map_len - 1) as _,
|
keymap_len: (map.map.len - 1) as _,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
wire::{jay_seat_events::*, JaySeatEventsId},
|
wire::{jay_seat_events::*, JaySeatEventsId},
|
||||||
xkbcommon::ModifierState,
|
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -26,12 +25,12 @@ pub struct JaySeatEvents {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JaySeatEvents {
|
impl JaySeatEvents {
|
||||||
pub fn send_modifiers(&self, seat: SeatId, mods: &ModifierState) {
|
pub fn send_modifiers(&self, seat: SeatId, mods: &kbvm::Components) {
|
||||||
self.client.event(Modifiers {
|
self.client.event(Modifiers {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
seat: seat.raw(),
|
seat: seat.raw(),
|
||||||
modifiers: mods.mods_effective,
|
modifiers: mods.mods.0,
|
||||||
group: mods.group,
|
group: mods.group.0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ use {
|
||||||
},
|
},
|
||||||
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
||||||
},
|
},
|
||||||
|
kbvm::{KbvmMap, KbvmMapId, KbvmState, PhysicalKeyboardState},
|
||||||
|
keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId, KeymapFd},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
|
|
@ -82,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,
|
||||||
|
|
@ -91,7 +93,6 @@ use {
|
||||||
ZwpTextInputV3Id,
|
ZwpTextInputV3Id,
|
||||||
},
|
},
|
||||||
wire_ei::EiSeatId,
|
wire_ei::EiSeatId,
|
||||||
xkbcommon::{DynKeyboardState, KeyboardState, KeymapId, XkbKeymap, XkbState},
|
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
|
|
@ -103,7 +104,6 @@ use {
|
||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::OwnedFd,
|
|
||||||
};
|
};
|
||||||
pub use {
|
pub use {
|
||||||
event_handling::NodeSeatState,
|
event_handling::NodeSeatState,
|
||||||
|
|
@ -143,6 +143,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 {
|
||||||
|
|
@ -168,10 +175,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>,
|
||||||
|
|
@ -213,13 +222,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();
|
||||||
|
|
@ -242,9 +249,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(),
|
||||||
|
|
@ -317,7 +326,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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,53 +504,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>) {
|
||||||
|
|
@ -1030,16 +1032,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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1090,6 +1093,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 {
|
||||||
|
|
@ -1148,11 +1178,15 @@ impl WlSeat {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keymap_fd(&self, state: &KeyboardState) -> Result<Rc<OwnedFd>, WlKeyboardError> {
|
pub fn keymap_fd(&self, state: &KeyboardState) -> Result<KeymapFd, WlKeyboardError> {
|
||||||
|
let fd = match self.client.is_xwayland {
|
||||||
|
true => &state.xwayland_map,
|
||||||
|
_ => &state.map,
|
||||||
|
};
|
||||||
if self.version >= READ_ONLY_KEYMAP_SINCE {
|
if self.version >= READ_ONLY_KEYMAP_SINCE {
|
||||||
return Ok(state.map.clone());
|
return Ok(fd.clone());
|
||||||
}
|
}
|
||||||
Ok(state.create_new_keymap_fd()?)
|
Ok(fd.create_unprotected_fd()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1177,7 +1211,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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1264,17 +1298,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);
|
||||||
}
|
}
|
||||||
|
|
@ -1286,7 +1323,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);
|
||||||
|
|
@ -1301,34 +1337,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>) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use {
|
||||||
wl_seat::{
|
wl_seat::{
|
||||||
tablet::{TabletPad, TabletPadId, TabletTool, TabletToolId},
|
tablet::{TabletPad, TabletPadId, TabletTool, TabletToolId},
|
||||||
text_input::TextDisconnectReason,
|
text_input::TextDisconnectReason,
|
||||||
wl_keyboard::{self, WlKeyboard},
|
wl_keyboard::WlKeyboard,
|
||||||
wl_pointer::{
|
wl_pointer::{
|
||||||
self, PendingScroll, WlPointer, AXIS_DISCRETE_SINCE_VERSION,
|
self, PendingScroll, WlPointer, AXIS_DISCRETE_SINCE_VERSION,
|
||||||
AXIS_RELATIVE_DIRECTION_SINCE_VERSION, AXIS_SOURCE_SINCE_VERSION,
|
AXIS_RELATIVE_DIRECTION_SINCE_VERSION, AXIS_SOURCE_SINCE_VERSION,
|
||||||
|
|
@ -33,15 +33,19 @@ use {
|
||||||
},
|
},
|
||||||
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
||||||
},
|
},
|
||||||
|
kbvm::KbvmState,
|
||||||
|
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::{KeyboardState, 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::{
|
||||||
|
|
@ -49,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)]
|
||||||
|
|
@ -319,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,
|
||||||
|
|
@ -778,130 +787,125 @@ 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_effective & !(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);
|
||||||
|
match self.input_method_grab.get() {
|
||||||
|
Some(g) => g.on_key(time_usec, kc.to_evdev(), key_state, &kbvm_state.kb_state),
|
||||||
|
_ => self.keyboard_node.get().node_on_key(
|
||||||
|
self,
|
||||||
|
time_usec,
|
||||||
|
kc.to_evdev(),
|
||||||
|
key_state,
|
||||||
|
&kbvm_state.kb_state,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
self.for_each_ei_seat(|ei_seat| {
|
||||||
|
ei_seat.handle_key(time_usec, kc.to_evdev(), key_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>)) {
|
||||||
|
|
@ -1331,7 +1335,7 @@ impl WlSeatGlobal {
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
time_usec: u64,
|
time_usec: u64,
|
||||||
key: u32,
|
key: u32,
|
||||||
state: u32,
|
state: KeyState,
|
||||||
kb_state: &KeyboardState,
|
kb_state: &KeyboardState,
|
||||||
) {
|
) {
|
||||||
let serial = surface.client.next_serial();
|
let serial = surface.client.next_serial();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
backend::KeyState,
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
ifs::wl_seat::{text_input::zwp_input_method_v2::ZwpInputMethodV2, wl_keyboard},
|
ifs::wl_seat::{text_input::zwp_input_method_v2::ZwpInputMethodV2, wl_keyboard},
|
||||||
|
keyboard::{KeyboardState, KeyboardStateId},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::errorfmt::ErrorFmt,
|
||||||
wire::{zwp_input_method_keyboard_grab_v2::*, ZwpInputMethodKeyboardGrabV2Id},
|
wire::{zwp_input_method_keyboard_grab_v2::*, ZwpInputMethodKeyboardGrabV2Id},
|
||||||
xkbcommon::{KeyboardState, KeyboardStateId},
|
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -27,7 +28,7 @@ impl ZwpInputMethodKeyboardGrabV2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_keymap(&self, kb_state: &KeyboardState) {
|
fn send_keymap(&self, kb_state: &KeyboardState) {
|
||||||
let map = match kb_state.create_new_keymap_fd() {
|
let map = match kb_state.map.create_unprotected_fd() {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Could not create new keymap fd: {}", ErrorFmt(e));
|
log::error!("Could not create new keymap fd: {}", ErrorFmt(e));
|
||||||
|
|
@ -37,8 +38,8 @@ impl ZwpInputMethodKeyboardGrabV2 {
|
||||||
self.client.event(Keymap {
|
self.client.event(Keymap {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
format: wl_keyboard::XKB_V1,
|
format: wl_keyboard::XKB_V1,
|
||||||
fd: map,
|
fd: map.map,
|
||||||
size: kb_state.map_len as _,
|
size: map.len as _,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,7 +49,7 @@ impl ZwpInputMethodKeyboardGrabV2 {
|
||||||
self.kb_state_id.set(kb_state.id);
|
self.kb_state_id.set(kb_state.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_key(&self, time_usec: u64, key: u32, state: u32, kb_state: &KeyboardState) {
|
pub fn on_key(&self, time_usec: u64, key: u32, state: KeyState, kb_state: &KeyboardState) {
|
||||||
let serial = self.client.next_serial();
|
let serial = self.client.next_serial();
|
||||||
if self.kb_state_id.get() != kb_state.id {
|
if self.kb_state_id.get() != kb_state.id {
|
||||||
self.update_state(serial, kb_state);
|
self.update_state(serial, kb_state);
|
||||||
|
|
@ -56,13 +57,16 @@ impl ZwpInputMethodKeyboardGrabV2 {
|
||||||
self.send_key(serial, time_usec, key, state);
|
self.send_key(serial, time_usec, key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_key(&self, serial: u64, time_usec: u64, key: u32, state: u32) {
|
fn send_key(&self, serial: u64, time_usec: u64, key: u32, state: KeyState) {
|
||||||
self.client.event(Key {
|
self.client.event(Key {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial: serial as _,
|
serial: serial as _,
|
||||||
time: (time_usec / 1000) as _,
|
time: (time_usec / 1000) as _,
|
||||||
key,
|
key,
|
||||||
state,
|
state: match state {
|
||||||
|
KeyState::Released => wl_keyboard::RELEASED,
|
||||||
|
KeyState::Pressed => wl_keyboard::PRESSED,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,10 +82,10 @@ impl ZwpInputMethodKeyboardGrabV2 {
|
||||||
self.client.event(Modifiers {
|
self.client.event(Modifiers {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial: serial as _,
|
serial: serial as _,
|
||||||
mods_depressed: kb_state.mods.mods_depressed,
|
mods_depressed: kb_state.mods.mods_pressed.0,
|
||||||
mods_latched: kb_state.mods.mods_latched,
|
mods_latched: kb_state.mods.mods_latched.0,
|
||||||
mods_locked: kb_state.mods.mods_locked,
|
mods_locked: kb_state.mods.mods_locked.0,
|
||||||
group: kb_state.mods.group,
|
group: kb_state.mods.group.0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ use {
|
||||||
ZwpInputPopupSurfaceV2, ZwpInputPopupSurfaceV2Error,
|
ZwpInputPopupSurfaceV2, ZwpInputPopupSurfaceV2Error,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
keyboard::KeyboardStateId,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
utils::{clonecell::CloneCell, numcell::NumCell, smallmap::SmallMap},
|
utils::{clonecell::CloneCell, numcell::NumCell, smallmap::SmallMap},
|
||||||
wire::{zwp_input_method_v2::*, ZwpInputMethodV2Id, ZwpInputPopupSurfaceV2Id},
|
wire::{zwp_input_method_v2::*, ZwpInputMethodV2Id, ZwpInputPopupSurfaceV2Id},
|
||||||
xkbcommon::KeyboardStateId,
|
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
backend::KeyState,
|
||||||
client::ClientError,
|
client::ClientError,
|
||||||
ifs::wl_seat::WlSeat,
|
ifs::wl_seat::WlSeat,
|
||||||
|
keyboard::{KeyboardError, KeyboardState, KeyboardStateId},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::{errorfmt::ErrorFmt, vecset::VecSet},
|
||||||
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
||||||
xkbcommon::{KeyboardState, KeyboardStateId, ModifierState, XkbCommonError},
|
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
kbvm::Components,
|
||||||
|
std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -25,6 +30,7 @@ pub struct WlKeyboard {
|
||||||
id: WlKeyboardId,
|
id: WlKeyboardId,
|
||||||
seat: Rc<WlSeat>,
|
seat: Rc<WlSeat>,
|
||||||
kb_state_id: Cell<KeyboardStateId>,
|
kb_state_id: Cell<KeyboardStateId>,
|
||||||
|
pressed_keys: RefCell<VecSet<u32>>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,6 +40,7 @@ impl WlKeyboard {
|
||||||
id,
|
id,
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
kb_state_id: Cell::new(KeyboardStateId::from_raw(0)),
|
kb_state_id: Cell::new(KeyboardStateId::from_raw(0)),
|
||||||
|
pressed_keys: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,8 +80,8 @@ impl WlKeyboard {
|
||||||
self.seat.client.event(Keymap {
|
self.seat.client.event(Keymap {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
format: XKB_V1,
|
format: XKB_V1,
|
||||||
fd,
|
fd: fd.map,
|
||||||
size: state.map_len as _,
|
size: fd.len as _,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +95,11 @@ impl WlKeyboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_enter(&self, serial: u64, surface: WlSurfaceId, keys: &[u32]) {
|
fn send_enter(&self, serial: u64, surface: WlSurfaceId, keys: &[u32]) {
|
||||||
|
{
|
||||||
|
let pk = &mut self.pressed_keys.borrow_mut();
|
||||||
|
pk.clear();
|
||||||
|
pk.extend(keys);
|
||||||
|
}
|
||||||
self.seat.client.event(Enter {
|
self.seat.client.event(Enter {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial: serial as _,
|
serial: serial as _,
|
||||||
|
|
@ -109,7 +121,7 @@ impl WlKeyboard {
|
||||||
serial: u64,
|
serial: u64,
|
||||||
time: u32,
|
time: u32,
|
||||||
key: u32,
|
key: u32,
|
||||||
state: u32,
|
state: KeyState,
|
||||||
surface: WlSurfaceId,
|
surface: WlSurfaceId,
|
||||||
kb_state: &KeyboardState,
|
kb_state: &KeyboardState,
|
||||||
) {
|
) {
|
||||||
|
|
@ -119,13 +131,31 @@ impl WlKeyboard {
|
||||||
self.send_key(serial, time, key, state);
|
self.send_key(serial, time, key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_key(&self, serial: u64, time: u32, key: u32, state: u32) {
|
fn send_key(&self, serial: u64, time: u32, key: u32, state: KeyState) {
|
||||||
|
{
|
||||||
|
let pk = &mut self.pressed_keys.borrow_mut();
|
||||||
|
match state {
|
||||||
|
KeyState::Released => {
|
||||||
|
if !pk.remove(&key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyState::Pressed => {
|
||||||
|
if !pk.insert(key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
self.seat.client.event(Key {
|
self.seat.client.event(Key {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial: serial as _,
|
serial: serial as _,
|
||||||
time,
|
time,
|
||||||
key,
|
key,
|
||||||
state,
|
state: match state {
|
||||||
|
KeyState::Released => RELEASED,
|
||||||
|
KeyState::Pressed => PRESSED,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,14 +167,14 @@ impl WlKeyboard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_modifiers(&self, serial: u64, mods: &ModifierState) {
|
fn send_modifiers(&self, serial: u64, mods: &Components) {
|
||||||
self.seat.client.event(Modifiers {
|
self.seat.client.event(Modifiers {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial: serial as _,
|
serial: serial as _,
|
||||||
mods_depressed: mods.mods_depressed,
|
mods_depressed: mods.mods_pressed.0,
|
||||||
mods_latched: mods.mods_latched,
|
mods_latched: mods.mods_latched.0,
|
||||||
mods_locked: mods.mods_locked,
|
mods_locked: mods.mods_locked.0,
|
||||||
group: mods.group,
|
group: mods.group.0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,6 +211,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);
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ use {
|
||||||
client::{Client, ClientCaps, ClientError, CAP_VIRTUAL_KEYBOARD_MANAGER},
|
client::{Client, ClientCaps, ClientError, CAP_VIRTUAL_KEYBOARD_MANAGER},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::wl_seat::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
ifs::wl_seat::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
||||||
|
keyboard::KeyboardState,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
wire::{zwp_virtual_keyboard_manager_v1::*, ZwpVirtualKeyboardManagerV1Id},
|
wire::{zwp_virtual_keyboard_manager_v1::*, ZwpVirtualKeyboardManagerV1Id},
|
||||||
xkbcommon::KeyboardState,
|
|
||||||
},
|
},
|
||||||
std::{cell::RefCell, rc::Rc},
|
std::{cell::RefCell, rc::Rc},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -87,7 +87,7 @@ impl ZwpVirtualKeyboardManagerV1RequestHandler for ZwpVirtualKeyboardManagerV1 {
|
||||||
kb_state: Rc::new(RefCell::new(KeyboardState {
|
kb_state: Rc::new(RefCell::new(KeyboardState {
|
||||||
id: self.client.state.keyboard_state_ids.next(),
|
id: self.client.state.keyboard_state_ids.next(),
|
||||||
map: seat_keymap.map.clone(),
|
map: seat_keymap.map.clone(),
|
||||||
map_len: seat_keymap.map_len,
|
xwayland_map: seat_keymap.xwayland_map.clone(),
|
||||||
pressed_keys: Default::default(),
|
pressed_keys: Default::default(),
|
||||||
mods: Default::default(),
|
mods: Default::default(),
|
||||||
})),
|
})),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
backend::KeyState,
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
clientmem::{ClientMem, ClientMemError},
|
clientmem::{ClientMem, ClientMemError},
|
||||||
ifs::{
|
ifs::{
|
||||||
|
|
@ -9,10 +10,11 @@ use {
|
||||||
},
|
},
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
|
kbvm::KbvmError,
|
||||||
|
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::{KeyboardState, XkbCommonError},
|
|
||||||
},
|
},
|
||||||
std::{cell::RefCell, rc::Rc},
|
std::{cell::RefCell, rc::Rc},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -73,13 +75,13 @@ 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(),
|
||||||
map: map.map.clone(),
|
map: map.map.clone(),
|
||||||
map_len: map.map_len,
|
xwayland_map: map.xwayland_map.clone(),
|
||||||
pressed_keys: Default::default(),
|
pressed_keys: Default::default(),
|
||||||
mods: Default::default(),
|
mods: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -89,19 +91,20 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
|
||||||
fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let kb_state = &mut *self.kb_state.borrow_mut();
|
let kb_state = &mut *self.kb_state.borrow_mut();
|
||||||
let contains = kb_state.pressed_keys.contains(&req.key);
|
let contains = kb_state.pressed_keys.contains(&req.key);
|
||||||
let valid = match req.state {
|
let (state, valid) = match req.state {
|
||||||
wl_keyboard::RELEASED => contains,
|
wl_keyboard::RELEASED => (KeyState::Released, contains),
|
||||||
wl_keyboard::PRESSED => !contains,
|
wl_keyboard::PRESSED => (KeyState::Pressed, !contains),
|
||||||
_ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)),
|
_ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)),
|
||||||
};
|
};
|
||||||
if valid {
|
if valid {
|
||||||
self.for_each_kb(|serial, surface, kb| {
|
self.for_each_kb(|serial, surface, kb| {
|
||||||
kb.on_key(serial, req.time, req.key, req.state, surface.id, kb_state);
|
kb.on_key(serial, req.time, req.key, state, surface.id, kb_state);
|
||||||
});
|
});
|
||||||
match req.state {
|
match req.state {
|
||||||
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(())
|
||||||
|
|
@ -109,14 +112,15 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
|
||||||
|
|
||||||
fn modifiers(&self, req: Modifiers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn modifiers(&self, req: Modifiers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let kb_state = &mut *self.kb_state.borrow_mut();
|
let kb_state = &mut *self.kb_state.borrow_mut();
|
||||||
kb_state.mods.mods_depressed = req.mods_depressed;
|
kb_state.mods.mods_pressed.0 = req.mods_depressed;
|
||||||
kb_state.mods.mods_latched = req.mods_latched;
|
kb_state.mods.mods_latched.0 = req.mods_latched;
|
||||||
kb_state.mods.mods_locked = req.mods_locked;
|
kb_state.mods.mods_locked.0 = req.mods_locked;
|
||||||
kb_state.mods.mods_effective = req.mods_depressed | req.mods_latched | req.mods_locked;
|
kb_state.mods.group_locked.0 = req.group;
|
||||||
kb_state.mods.group = req.group;
|
kb_state.mods.update_effective();
|
||||||
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(())
|
||||||
}
|
}
|
||||||
|
|
@ -153,6 +157,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);
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ use {
|
||||||
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
||||||
},
|
},
|
||||||
io_uring::IoUringError,
|
io_uring::IoUringError,
|
||||||
|
keyboard::KeyboardState,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
rect::{DamageQueue, Rect, Region},
|
rect::{DamageQueue, Rect, Region},
|
||||||
|
|
@ -88,7 +89,6 @@ use {
|
||||||
wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id,
|
wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id,
|
||||||
ZwpLinuxDmabufFeedbackV1Id,
|
ZwpLinuxDmabufFeedbackV1Id,
|
||||||
},
|
},
|
||||||
xkbcommon::KeyboardState,
|
|
||||||
xwayland::XWaylandEvent,
|
xwayland::XWaylandEvent,
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
@ -1741,7 +1741,7 @@ impl Node for WlSurface {
|
||||||
seat: &WlSeatGlobal,
|
seat: &WlSeatGlobal,
|
||||||
time_usec: u64,
|
time_usec: u64,
|
||||||
key: u32,
|
key: u32,
|
||||||
state: u32,
|
state: KeyState,
|
||||||
kb_state: &KeyboardState,
|
kb_state: &KeyboardState,
|
||||||
) {
|
) {
|
||||||
seat.key_surface(self, time_usec, key, state, kb_state);
|
seat.key_surface(self, time_usec, key, state, kb_state);
|
||||||
|
|
|
||||||
|
|
@ -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,9 +14,9 @@ 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.map.len)
|
||||||
};
|
};
|
||||||
|
|
||||||
let ds = run.create_default_setup().await?;
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
|
||||||
222
src/kbvm.rs
Normal file
222
src/kbvm.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::KeyState,
|
||||||
|
ifs::wl_seat::WlSeatGlobal,
|
||||||
|
keyboard::{DynKeyboardState, KeyboardState, KeyboardStateId, KeymapFd},
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[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: KeymapFd,
|
||||||
|
pub xwayland_map: KeymapFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 builder = map.to_builder();
|
||||||
|
Ok(Rc::new(KbvmMap {
|
||||||
|
id: self.ids.next(),
|
||||||
|
state_machine: builder.build_state_machine(),
|
||||||
|
map: create_keymap_memfd(&map, false).map_err(KbvmError::KeymapMemfd)?,
|
||||||
|
xwayland_map: create_keymap_memfd(&map, true).map_err(KbvmError::KeymapMemfd)?,
|
||||||
|
lookup_table: builder.build_lookup_table(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_keymap_memfd(map: &Keymap, xwayland: bool) -> Result<KeymapFd, OsError> {
|
||||||
|
let mut format = map.format();
|
||||||
|
if xwayland {
|
||||||
|
format = format.lookup_only(true).rename_long_keys(true);
|
||||||
|
}
|
||||||
|
let str = format!("{}\n", 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(KeymapFd {
|
||||||
|
map: Rc::new(memfd),
|
||||||
|
len: str.len() + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
xwayland_map: self.xwayland_map.clone(),
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/keyboard.rs
Normal file
67
src/keyboard.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
use {
|
||||||
|
crate::utils::{oserror::OsError, vecset::VecSet},
|
||||||
|
kbvm::Components,
|
||||||
|
std::{
|
||||||
|
cell::{Ref, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
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 {
|
||||||
|
pub id: KeyboardStateId,
|
||||||
|
pub map: KeymapFd,
|
||||||
|
pub xwayland_map: KeymapFd,
|
||||||
|
pub pressed_keys: VecSet<u32>,
|
||||||
|
pub mods: Components,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DynKeyboardState {
|
||||||
|
fn borrow(&self) -> Ref<'_, KeyboardState>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynKeyboardState for RefCell<KeyboardState> {
|
||||||
|
fn borrow(&self) -> Ref<'_, KeyboardState> {
|
||||||
|
self.borrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct KeymapFd {
|
||||||
|
pub map: Rc<OwnedFd>,
|
||||||
|
pub len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeymapFd {
|
||||||
|
pub fn create_unprotected_fd(&self) -> Result<Self, 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.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(Self {
|
||||||
|
map: Rc::new(fd),
|
||||||
|
len: self.len,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
udev::UdevError,
|
udev::UdevError,
|
||||||
utils::{errorfmt::ErrorFmt, oserror::OsError, ptr_ext::PtrExt, trim::AsciiTrim},
|
utils::{errorfmt::ErrorFmt, oserror::OsError, ptr_ext::PtrExt},
|
||||||
},
|
},
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
isnt::std_1::primitive::IsntConstPtrExt,
|
isnt::std_1::primitive::IsntConstPtrExt,
|
||||||
|
|
@ -182,5 +182,9 @@ unsafe extern "C" fn jay_libinput_log_handler(
|
||||||
LIBINPUT_LOG_PRIORITY_ERROR => log::Level::Error,
|
LIBINPUT_LOG_PRIORITY_ERROR => log::Level::Error,
|
||||||
_ => log::Level::Error,
|
_ => log::Level::Error,
|
||||||
};
|
};
|
||||||
log::log!(priority, "libinput: {}", str.to_bytes().trim().as_bstr());
|
log::log!(
|
||||||
|
priority,
|
||||||
|
"libinput: {}",
|
||||||
|
str.to_bytes().trim_ascii().as_bstr()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,24 +181,14 @@ impl Log for LogWrapper {
|
||||||
let buffer = unsafe { &mut *buffer };
|
let buffer = unsafe { &mut *buffer };
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let _ = if let Some(mp) = record.module_path() {
|
let _ = writeln!(
|
||||||
writeln!(
|
buffer,
|
||||||
buffer,
|
"[{} {:5} {}] {}",
|
||||||
"[{} {:5} {}] {}",
|
humantime::format_rfc3339_millis(now),
|
||||||
humantime::format_rfc3339_millis(now),
|
record.level(),
|
||||||
record.level(),
|
record.target(),
|
||||||
mp,
|
record.args(),
|
||||||
record.args(),
|
);
|
||||||
)
|
|
||||||
} else {
|
|
||||||
writeln!(
|
|
||||||
buffer,
|
|
||||||
"[{} {:5}] {}",
|
|
||||||
humantime::format_rfc3339_millis(now),
|
|
||||||
record.level(),
|
|
||||||
record.args(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let mut fd = Fd::new(self.logger.file_fd.load(Relaxed));
|
let mut fd = Fd::new(self.logger.file_fd.load(Relaxed));
|
||||||
let _ = fd.write_all(buffer);
|
let _ = fd.write_all(buffer);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,8 @@ mod ifs;
|
||||||
mod io_uring;
|
mod io_uring;
|
||||||
#[cfg(feature = "it")]
|
#[cfg(feature = "it")]
|
||||||
mod it;
|
mod it;
|
||||||
|
mod kbvm;
|
||||||
|
mod keyboard;
|
||||||
mod libinput;
|
mod libinput;
|
||||||
mod logger;
|
mod logger;
|
||||||
mod logind;
|
mod logind;
|
||||||
|
|
@ -108,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() {
|
||||||
|
|
|
||||||
14
src/state.rs
14
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,8 @@ use {
|
||||||
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global,
|
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global,
|
||||||
},
|
},
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
|
kbvm::{KbvmContext, KbvmMap},
|
||||||
|
keyboard::KeyboardStateIds,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
rect::{Rect, Region},
|
rect::{Rect, Region},
|
||||||
|
|
@ -99,7 +101,6 @@ use {
|
||||||
ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayRenderCtxId, JaySeatEventsId,
|
ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayRenderCtxId, JaySeatEventsId,
|
||||||
JayWorkspaceWatcherId, ZwpLinuxDmabufFeedbackV1Id,
|
JayWorkspaceWatcherId, ZwpLinuxDmabufFeedbackV1Id,
|
||||||
},
|
},
|
||||||
xkbcommon::{KeyboardStateIds, XkbContext, XkbKeymap, XkbState},
|
|
||||||
xwayland::{self, XWaylandEvent},
|
xwayland::{self, XWaylandEvent},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
|
|
@ -121,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>>>,
|
||||||
|
|
@ -205,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,
|
||||||
|
|
@ -326,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(),
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ use {
|
||||||
},
|
},
|
||||||
wl_surface::{tray::TrayItemId, WlSurface},
|
wl_surface::{tray::TrayItemId, WlSurface},
|
||||||
},
|
},
|
||||||
|
keyboard::KeyboardState,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
utils::numcell::NumCell,
|
utils::numcell::NumCell,
|
||||||
xkbcommon::KeyboardState,
|
|
||||||
},
|
},
|
||||||
jay_config::Direction as JayDirection,
|
jay_config::Direction as JayDirection,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -189,7 +189,7 @@ pub trait Node: 'static {
|
||||||
seat: &WlSeatGlobal,
|
seat: &WlSeatGlobal,
|
||||||
time_usec: u64,
|
time_usec: u64,
|
||||||
key: u32,
|
key: u32,
|
||||||
state: u32,
|
state: KeyState,
|
||||||
kb_state: &KeyboardState,
|
kb_state: &KeyboardState,
|
||||||
) {
|
) {
|
||||||
let _ = seat;
|
let _ = seat;
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ pub mod timer;
|
||||||
pub mod toplevel_identifier;
|
pub mod toplevel_identifier;
|
||||||
pub mod transform_ext;
|
pub mod transform_ext;
|
||||||
pub mod tri;
|
pub mod tri;
|
||||||
pub mod trim;
|
|
||||||
pub mod unlink_on_drop;
|
pub mod unlink_on_drop;
|
||||||
pub mod vec_ext;
|
pub mod vec_ext;
|
||||||
pub mod vecdeque_ext;
|
pub mod vecdeque_ext;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::utils::{errorfmt::ErrorFmt, oserror::OsError, trim::AsciiTrim},
|
crate::utils::{errorfmt::ErrorFmt, oserror::OsError},
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
uapi::{c, OwnedFd},
|
uapi::{c, OwnedFd},
|
||||||
};
|
};
|
||||||
|
|
@ -12,7 +12,7 @@ pub struct PidInfo {
|
||||||
|
|
||||||
pub fn get_pid_info(uid: c::uid_t, pid: c::pid_t) -> PidInfo {
|
pub fn get_pid_info(uid: c::uid_t, pid: c::pid_t) -> PidInfo {
|
||||||
let comm = match std::fs::read(format!("/proc/{}/comm", pid)) {
|
let comm = match std::fs::read(format!("/proc/{}/comm", pid)) {
|
||||||
Ok(name) => name.trim().as_bstr().to_string(),
|
Ok(name) => name.trim_ascii_end().as_bstr().to_string(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Could not read `comm` of pid {}: {}", pid, ErrorFmt(e));
|
log::warn!("Could not read `comm` of pid {}: {}", pid, ErrorFmt(e));
|
||||||
"Unknown".to_string()
|
"Unknown".to_string()
|
||||||
|
|
|
||||||
|
|
@ -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() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
pub trait AsciiTrim {
|
|
||||||
fn trim(&self) -> &[u8];
|
|
||||||
fn trim_start(&self) -> &[u8];
|
|
||||||
fn trim_end(&self) -> &[u8];
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsciiTrim for [u8] {
|
|
||||||
fn trim(&self) -> &[u8] {
|
|
||||||
self.trim_start().trim_end()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trim_start(&self) -> &[u8] {
|
|
||||||
let mut s = self;
|
|
||||||
while let Some((b, r)) = s.split_first() {
|
|
||||||
if !matches!(*b, b' ' | b'\t' | b'\n') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s = r;
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trim_end(&self) -> &[u8] {
|
|
||||||
let mut s = self;
|
|
||||||
while let Some((b, r)) = s.split_last() {
|
|
||||||
if !matches!(*b, b' ' | b'\t' | b'\n') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s = r;
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,7 +19,6 @@ impl<T> Deref for VecSet<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> VecSet<T> {
|
impl<T> VecSet<T> {
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.vec.clear();
|
self.vec.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -43,4 +42,17 @@ impl<T: PartialEq> VecSet<T> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<T> {
|
||||||
|
self.vec.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend(&mut self, vals: &[T])
|
||||||
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
for v in vals.iter().copied() {
|
||||||
|
self.insert(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
utils::{bitflags::BitflagsExt, oserror::OsError, trim::AsciiTrim},
|
utils::{bitflags::BitflagsExt, oserror::OsError},
|
||||||
video::drm::{
|
video::drm::{
|
||||||
DrmBlob, DrmCardResources, DrmConnector, DrmConnectorInfo, DrmCrtc, DrmEncoder,
|
DrmBlob, DrmCardResources, DrmConnector, DrmConnectorInfo, DrmCrtc, DrmEncoder,
|
||||||
DrmEncoderInfo, DrmError, DrmFb, DrmModeInfo, DrmPlane, DrmPlaneInfo, DrmProperty,
|
DrmEncoderInfo, DrmError, DrmFb, DrmModeInfo, DrmPlane, DrmPlaneInfo, DrmProperty,
|
||||||
|
|
@ -163,7 +163,7 @@ pub fn get_device_name_from_fd2(fd: c::c_int) -> Result<Ustring, OsError> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if let Some(pf) = buf.strip_prefix(b"DEVNAME=") {
|
if let Some(pf) = buf.strip_prefix(b"DEVNAME=") {
|
||||||
return Ok(uapi::format_ustr!("/dev/{}", pf.trim_end().as_bstr()));
|
return Ok(uapi::format_ustr!("/dev/{}", pf.trim_ascii_end().as_bstr()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(OsError(c::ENOENT))
|
Err(OsError(c::ENOENT))
|
||||||
|
|
|
||||||
427
src/xkbcommon.rs
427
src/xkbcommon.rs
|
|
@ -1,427 +0,0 @@
|
||||||
#![allow(non_camel_case_types, improper_ctypes)]
|
|
||||||
|
|
||||||
mod consts;
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/xkbcommon_tys.rs"));
|
|
||||||
|
|
||||||
pub use consts::*;
|
|
||||||
use {
|
|
||||||
crate::utils::{
|
|
||||||
errorfmt::ErrorFmt, oserror::OsError, ptr_ext::PtrExt, trim::AsciiTrim, vecset::VecSet,
|
|
||||||
},
|
|
||||||
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 _) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
|
||||||
pub struct ModifierState {
|
|
||||||
pub mods_depressed: u32,
|
|
||||||
pub mods_latched: u32,
|
|
||||||
pub mods_locked: u32,
|
|
||||||
pub mods_effective: u32,
|
|
||||||
pub group: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
linear_ids!(KeyboardStateIds, KeyboardStateId, u64);
|
|
||||||
|
|
||||||
pub struct KeyboardState {
|
|
||||||
pub id: KeyboardStateId,
|
|
||||||
pub map: Rc<OwnedFd>,
|
|
||||||
pub map_len: usize,
|
|
||||||
pub pressed_keys: VecSet<u32>,
|
|
||||||
pub mods: ModifierState,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DynKeyboardState {
|
|
||||||
fn borrow(&self) -> Ref<'_, KeyboardState>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DynKeyboardState for RefCell<KeyboardState> {
|
|
||||||
fn borrow(&self) -> Ref<'_, KeyboardState> {
|
|
||||||
self.borrow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) -> ModifierState {
|
|
||||||
self.kb_state.mods
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fetch(&mut self, changes: xkb_state_component) -> bool {
|
|
||||||
unsafe {
|
|
||||||
if changes != 0 {
|
|
||||||
self.kb_state.mods.mods_depressed =
|
|
||||||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_DEPRESSED.raw() as _);
|
|
||||||
self.kb_state.mods.mods_latched =
|
|
||||||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LATCHED.raw() as _);
|
|
||||||
self.kb_state.mods.mods_locked =
|
|
||||||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LOCKED.raw() as _);
|
|
||||||
self.kb_state.mods.mods_effective = self.kb_state.mods.mods_depressed
|
|
||||||
| self.kb_state.mods.mods_latched
|
|
||||||
| self.kb_state.mods.mods_locked;
|
|
||||||
self.kb_state.mods.group =
|
|
||||||
xkb_state_serialize_layout(self.state, XKB_STATE_LAYOUT_EFFECTIVE.raw() as _);
|
|
||||||
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,
|
|
||||||
&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_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