Merge pull request #162 from mahkoh/jorth/device-keymap
seat: implement per-device keymaps
This commit is contained in:
commit
13ef43bedf
25 changed files with 382 additions and 105 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Needs jay-config release.
|
||||||
|
- Needs jay-toml-config release.
|
||||||
|
- Needs jay-compositor release.
|
||||||
|
|
||||||
# 1.0.3
|
# 1.0.3
|
||||||
|
|
||||||
- Needs jay-compositor release.
|
- Needs jay-compositor release.
|
||||||
|
|
|
||||||
|
|
@ -818,6 +818,10 @@ impl Client {
|
||||||
self.send(&ClientMessage::SetSeat { device, seat })
|
self.send(&ClientMessage::SetSeat { device, seat })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_device_keymap(&self, device: InputDevice, keymap: Keymap) {
|
||||||
|
self.send(&ClientMessage::DeviceSetKeymap { device, keymap })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_left_handed(&self, device: InputDevice, left_handed: bool) {
|
pub fn set_left_handed(&self, device: InputDevice, left_handed: bool) {
|
||||||
self.send(&ClientMessage::SetLeftHanded {
|
self.send(&ClientMessage::SetLeftHanded {
|
||||||
device,
|
device,
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,10 @@ pub enum ClientMessage<'a> {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
},
|
},
|
||||||
GetSocketPath,
|
GetSocketPath,
|
||||||
|
DeviceSetKeymap {
|
||||||
|
device: InputDevice,
|
||||||
|
keymap: Keymap,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,16 @@ impl InputDevice {
|
||||||
get!().set_seat(self, seat)
|
get!().set_seat(self, seat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the keymap of the device.
|
||||||
|
///
|
||||||
|
/// This overrides the keymap set for the seat. The keymap becomes active when a key
|
||||||
|
/// on the device is pressed.
|
||||||
|
///
|
||||||
|
/// Setting the invalid keymap reverts to the seat keymap.
|
||||||
|
pub fn set_keymap(self, keymap: Keymap) {
|
||||||
|
get!().set_device_keymap(self, keymap)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether the device has the specified capability.
|
/// Returns whether the device has the specified capability.
|
||||||
pub fn has_capability(self, cap: Capability) -> bool {
|
pub fn has_capability(self, cap: Capability) -> bool {
|
||||||
get!(false).has_capability(self, cap)
|
get!(false).has_capability(self, cap)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
- Add support for wp-alpha-modifier.
|
- Add support for wp-alpha-modifier.
|
||||||
|
- Add support for per-device keymaps.
|
||||||
|
|
||||||
# 1.0.3 (2024-04-11)
|
# 1.0.3 (2024-04-11)
|
||||||
|
|
||||||
|
|
|
||||||
112
src/cli/input.rs
112
src/cli/input.rs
|
|
@ -19,7 +19,7 @@ use {
|
||||||
ops::DerefMut,
|
ops::DerefMut,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
uapi::c,
|
uapi::{c, OwnedFd},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
|
|
@ -119,6 +119,10 @@ pub enum DeviceCommand {
|
||||||
SetPxPerWheelScroll(SetPxPerWheelScrollArgs),
|
SetPxPerWheelScroll(SetPxPerWheelScrollArgs),
|
||||||
/// Set the transformation matrix.
|
/// Set the transformation matrix.
|
||||||
SetTransformMatrix(SetTransformMatrixArgs),
|
SetTransformMatrix(SetTransformMatrixArgs),
|
||||||
|
/// Set the keymap of this device.
|
||||||
|
SetKeymap(SetKeymapArgs),
|
||||||
|
/// Retrieve the keymap of this device.
|
||||||
|
Keymap,
|
||||||
/// Attach the device to a seat.
|
/// Attach the device to a seat.
|
||||||
Attach(AttachArgs),
|
Attach(AttachArgs),
|
||||||
/// Detach the device from its seat.
|
/// Detach the device from its seat.
|
||||||
|
|
@ -292,6 +296,47 @@ impl Input {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepare_keymap(&self, a: &SetKeymapArgs) -> (Rc<OwnedFd>, usize) {
|
||||||
|
let map = match &a.file {
|
||||||
|
None => {
|
||||||
|
let mut map = vec![];
|
||||||
|
if let Err(e) = stdin().read_to_end(&mut map) {
|
||||||
|
eprintln!("Could not read from stdin: {}", ErrorFmt(e));
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
map
|
||||||
|
}
|
||||||
|
Some(f) => match std::fs::read(f) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Could not read {}: {}", f, ErrorFmt(e));
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut memfd =
|
||||||
|
uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
|
||||||
|
memfd.write_all(&map).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();
|
||||||
|
(Rc::new(memfd), map.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_keymap(&self, input: JayInputId) -> Vec<u8> {
|
||||||
|
let data = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
jay_input::Keymap::handle(&self.tc, input, data.clone(), |d, map| {
|
||||||
|
let mem = Rc::new(ClientMem::new(map.keymap.raw(), map.keymap_len as _, true).unwrap())
|
||||||
|
.offset(0);
|
||||||
|
mem.read(d.borrow_mut().deref_mut()).unwrap();
|
||||||
|
});
|
||||||
|
self.tc.round_trip().await;
|
||||||
|
data.take()
|
||||||
|
}
|
||||||
|
|
||||||
async fn seat(self: &Rc<Self>, input: JayInputId, args: SeatArgs) {
|
async fn seat(self: &Rc<Self>, input: JayInputId, args: SeatArgs) {
|
||||||
let tc = &self.tc;
|
let tc = &self.tc;
|
||||||
match args.command.unwrap_or_default() {
|
match args.command.unwrap_or_default() {
|
||||||
|
|
@ -318,40 +363,15 @@ impl Input {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
SeatCommand::SetKeymap(a) => {
|
SeatCommand::SetKeymap(a) => {
|
||||||
|
let (memfd, len) = self.prepare_keymap(&a);
|
||||||
self.handle_error(input, |e| {
|
self.handle_error(input, |e| {
|
||||||
eprintln!("Could not set keymap: {}", e);
|
eprintln!("Could not set keymap: {}", e);
|
||||||
});
|
});
|
||||||
let map = match &a.file {
|
|
||||||
None => {
|
|
||||||
let mut map = vec![];
|
|
||||||
if let Err(e) = stdin().read_to_end(&mut map) {
|
|
||||||
eprintln!("Could not read from stdin: {}", ErrorFmt(e));
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
map
|
|
||||||
}
|
|
||||||
Some(f) => match std::fs::read(f) {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Could not read {}: {}", f, ErrorFmt(e));
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let mut memfd =
|
|
||||||
uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
|
|
||||||
memfd.write_all(&map).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();
|
|
||||||
tc.send(jay_input::SetKeymap {
|
tc.send(jay_input::SetKeymap {
|
||||||
self_id: input,
|
self_id: input,
|
||||||
seat: &args.seat,
|
seat: &args.seat,
|
||||||
keymap: Rc::new(memfd),
|
keymap: memfd,
|
||||||
keymap_len: map.len() as _,
|
keymap_len: len as _,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
SeatCommand::UseHardwareCursor(a) => {
|
SeatCommand::UseHardwareCursor(a) => {
|
||||||
|
|
@ -368,20 +388,11 @@ impl Input {
|
||||||
self.handle_error(input, |e| {
|
self.handle_error(input, |e| {
|
||||||
eprintln!("Could not retrieve the keymap: {}", e);
|
eprintln!("Could not retrieve the keymap: {}", e);
|
||||||
});
|
});
|
||||||
let data = Rc::new(RefCell::new(Vec::new()));
|
|
||||||
jay_input::Keymap::handle(tc, input, data.clone(), |d, map| {
|
|
||||||
let mem = Rc::new(
|
|
||||||
ClientMem::new(map.keymap.raw(), map.keymap_len as _, true).unwrap(),
|
|
||||||
)
|
|
||||||
.offset(0);
|
|
||||||
mem.read(d.borrow_mut().deref_mut()).unwrap();
|
|
||||||
});
|
|
||||||
tc.send(jay_input::GetKeymap {
|
tc.send(jay_input::GetKeymap {
|
||||||
self_id: input,
|
self_id: input,
|
||||||
seat: &args.seat,
|
seat: &args.seat,
|
||||||
});
|
});
|
||||||
tc.round_trip().await;
|
let map = self.handle_keymap(input).await;
|
||||||
let map = data.take();
|
|
||||||
stdout().write_all(&map).unwrap();
|
stdout().write_all(&map).unwrap();
|
||||||
}
|
}
|
||||||
SeatCommand::SetCursorSize(a) => {
|
SeatCommand::SetCursorSize(a) => {
|
||||||
|
|
@ -530,6 +541,29 @@ impl Input {
|
||||||
id: args.device,
|
id: args.device,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
DeviceCommand::SetKeymap(a) => {
|
||||||
|
let (memfd, len) = self.prepare_keymap(&a);
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not set keymap: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetDeviceKeymap {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
keymap: memfd,
|
||||||
|
keymap_len: len as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::Keymap => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not retrieve the keymap: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::GetDeviceKeymap {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
});
|
||||||
|
let map = self.handle_keymap(input).await;
|
||||||
|
stdout().write_all(&map).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tc.round_trip().await;
|
tc.round_trip().await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,23 @@ impl ConfigProxyHandler {
|
||||||
} else {
|
} else {
|
||||||
self.get_keymap(keymap)?
|
self.get_keymap(keymap)?
|
||||||
};
|
};
|
||||||
seat.set_keymap(&keymap);
|
seat.set_seat_keymap(&keymap);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_set_device_keymap(
|
||||||
|
&self,
|
||||||
|
device: InputDevice,
|
||||||
|
keymap: Keymap,
|
||||||
|
) -> Result<(), CphError> {
|
||||||
|
let dev = self.get_device_handler_data(device)?;
|
||||||
|
if keymap.is_invalid() {
|
||||||
|
dev.keymap_id.set(None);
|
||||||
|
dev.keymap.set(None);
|
||||||
|
} else {
|
||||||
|
let map = self.get_keymap(keymap)?;
|
||||||
|
dev.set_keymap(&map);
|
||||||
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1746,6 +1762,9 @@ impl ConfigProxyHandler {
|
||||||
self.handle_set_explicit_sync_enabled(enabled)
|
self.handle_set_explicit_sync_enabled(enabled)
|
||||||
}
|
}
|
||||||
ClientMessage::GetSocketPath => self.handle_get_socket_path(),
|
ClientMessage::GetSocketPath => self.handle_get_socket_path(),
|
||||||
|
ClientMessage::DeviceSetKeymap { device, keymap } => self
|
||||||
|
.handle_set_device_keymap(device, keymap)
|
||||||
|
.wrn("set_device_keymap")?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,11 @@ use {
|
||||||
state::{DeviceHandlerData, InputDeviceData},
|
state::{DeviceHandlerData, InputDeviceData},
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::errorfmt::ErrorFmt,
|
||||||
wire::{jay_input::*, JayInputId},
|
wire::{jay_input::*, JayInputId},
|
||||||
xkbcommon::XkbCommonError,
|
xkbcommon::{XkbCommonError, XkbKeymap},
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
uapi::OwnedFd,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct JayInput {
|
pub struct JayInput {
|
||||||
|
|
@ -67,8 +68,7 @@ impl JayInput {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_keymap(&self, data: &WlSeatGlobal) {
|
fn send_keymap(&self, map: &XkbKeymap) {
|
||||||
let map = data.keymap();
|
|
||||||
self.client.event(Keymap {
|
self.client.event(Keymap {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
keymap: map.map.clone(),
|
keymap: map.map.clone(),
|
||||||
|
|
@ -138,6 +138,20 @@ impl JayInput {
|
||||||
Some(d) => Ok(d.data.clone()),
|
Some(d) => Ok(d.data.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_keymap_impl<F>(&self, keymap: &OwnedFd, len: u32, f: F) -> Result<(), JayInputError>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Rc<XkbKeymap>) -> Result<(), JayInputError>,
|
||||||
|
{
|
||||||
|
let cm = Rc::new(ClientMem::new(keymap.raw(), len as _, true)?).offset(0);
|
||||||
|
let mut map = vec![];
|
||||||
|
cm.read(&mut map)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let map = self.client.state.xkb_ctx.keymap_from_str(&map)?;
|
||||||
|
f(&map)?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JayInputRequestHandler for JayInput {
|
impl JayInputRequestHandler for JayInput {
|
||||||
|
|
@ -174,13 +188,9 @@ impl JayInputRequestHandler for JayInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_keymap(&self, req: SetKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_keymap(&self, req: SetKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let cm = Rc::new(ClientMem::new(req.keymap.raw(), req.keymap_len as _, true)?).offset(0);
|
self.set_keymap_impl(&req.keymap, req.keymap_len, |map| {
|
||||||
let mut map = vec![];
|
|
||||||
cm.read(&mut map)?;
|
|
||||||
self.or_error(|| {
|
|
||||||
let map = self.client.state.xkb_ctx.keymap_from_str(&map)?;
|
|
||||||
let seat = self.seat(req.seat)?;
|
let seat = self.seat(req.seat)?;
|
||||||
seat.set_keymap(&map);
|
seat.set_seat_keymap(&map);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +210,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
fn get_keymap(&self, req: GetKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn get_keymap(&self, req: GetKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let seat = self.seat(req.seat)?;
|
let seat = self.seat(req.seat)?;
|
||||||
self.send_keymap(&seat);
|
self.send_keymap(&seat.keymap());
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -360,6 +370,24 @@ impl JayInputRequestHandler for JayInput {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_device_keymap(&self, req: SetDeviceKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.set_keymap_impl(&req.keymap, req.keymap_len, |map| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.set_keymap(&map);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_device_keymap(&self, req: GetDeviceKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
if let Some(map) = dev.keymap.get() {
|
||||||
|
self.send_keymap(&map);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
|
|
|
||||||
|
|
@ -56,16 +56,16 @@ use {
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt, linkedlist::LinkedNode, numcell::NumCell, rc_eq::rc_eq,
|
errorfmt::ErrorFmt, linkedlist::LinkedNode, numcell::NumCell, rc_eq::rc_eq,
|
||||||
smallmap::SmallMap, transform_ext::TransformExt,
|
smallmap::SmallMap, transform_ext::TransformExt, vecset::VecSet,
|
||||||
},
|
},
|
||||||
wire::{
|
wire::{
|
||||||
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
||||||
WlSeatId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
|
WlSeatId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
|
||||||
ZwpRelativePointerV1Id,
|
ZwpRelativePointerV1Id,
|
||||||
},
|
},
|
||||||
xkbcommon::{XkbKeymap, XkbState},
|
xkbcommon::{KeymapId, XkbKeymap, XkbState},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::AHashMap,
|
||||||
jay_config::keyboard::mods::Modifiers,
|
jay_config::keyboard::mods::Modifiers,
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -128,7 +128,7 @@ pub struct WlSeatGlobal {
|
||||||
pointer_stack_modified: Cell<bool>,
|
pointer_stack_modified: Cell<bool>,
|
||||||
found_tree: RefCell<Vec<FoundNode>>,
|
found_tree: RefCell<Vec<FoundNode>>,
|
||||||
keyboard_node: CloneCell<Rc<dyn Node>>,
|
keyboard_node: CloneCell<Rc<dyn Node>>,
|
||||||
pressed_keys: RefCell<AHashSet<u32>>,
|
pressed_keys: RefCell<VecSet<u32>>,
|
||||||
bindings: RefCell<AHashMap<ClientId, AHashMap<WlSeatId, Rc<WlSeat>>>>,
|
bindings: RefCell<AHashMap<ClientId, AHashMap<WlSeatId, Rc<WlSeat>>>>,
|
||||||
x_data_devices: SmallMap<XIpcDeviceId, Rc<XIpcDevice>, 1>,
|
x_data_devices: SmallMap<XIpcDeviceId, Rc<XIpcDevice>, 1>,
|
||||||
data_devices: RefCell<AHashMap<ClientId, AHashMap<WlDataDeviceId, Rc<WlDataDevice>>>>,
|
data_devices: RefCell<AHashMap<ClientId, AHashMap<WlDataDeviceId, Rc<WlDataDevice>>>>,
|
||||||
|
|
@ -141,7 +141,10 @@ pub struct WlSeatGlobal {
|
||||||
wlr_data_devices:
|
wlr_data_devices:
|
||||||
CopyHashMap<(ClientId, ZwlrDataControlDeviceV1Id), Rc<ZwlrDataControlDeviceV1>>,
|
CopyHashMap<(ClientId, ZwlrDataControlDeviceV1Id), Rc<ZwlrDataControlDeviceV1>>,
|
||||||
repeat_rate: Cell<(i32, i32)>,
|
repeat_rate: Cell<(i32, i32)>,
|
||||||
kb_map: CloneCell<Rc<XkbKeymap>>,
|
seat_kb_map: CloneCell<Rc<XkbKeymap>>,
|
||||||
|
seat_kb_map_id: Cell<KeymapId>,
|
||||||
|
effective_kb_map: CloneCell<Rc<XkbKeymap>>,
|
||||||
|
effective_kb_map_id: Cell<KeymapId>,
|
||||||
kb_state: RefCell<XkbState>,
|
kb_state: RefCell<XkbState>,
|
||||||
cursor: CloneCell<Option<Rc<dyn Cursor>>>,
|
cursor: CloneCell<Option<Rc<dyn Cursor>>>,
|
||||||
tree_changed: Rc<AsyncEvent>,
|
tree_changed: Rc<AsyncEvent>,
|
||||||
|
|
@ -163,6 +166,7 @@ pub struct WlSeatGlobal {
|
||||||
constraint: CloneCell<Option<Rc<SeatConstraint>>>,
|
constraint: CloneCell<Option<Rc<SeatConstraint>>>,
|
||||||
idle_notifications: CopyHashMap<(ClientId, ExtIdleNotificationV1Id), Rc<ExtIdleNotificationV1>>,
|
idle_notifications: CopyHashMap<(ClientId, ExtIdleNotificationV1Id), Rc<ExtIdleNotificationV1>>,
|
||||||
last_input_usec: Cell<u64>,
|
last_input_usec: Cell<u64>,
|
||||||
|
keymap_version: NumCell<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHANGE_CURSOR_MOVED: u32 = 1 << 0;
|
const CHANGE_CURSOR_MOVED: u32 = 1 << 0;
|
||||||
|
|
@ -196,7 +200,10 @@ impl WlSeatGlobal {
|
||||||
data_devices: RefCell::new(Default::default()),
|
data_devices: RefCell::new(Default::default()),
|
||||||
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)),
|
||||||
kb_map: CloneCell::new(state.default_keymap.clone()),
|
seat_kb_map: CloneCell::new(state.default_keymap.clone()),
|
||||||
|
seat_kb_map_id: Cell::new(state.default_keymap.id),
|
||||||
|
effective_kb_map: CloneCell::new(state.default_keymap.clone()),
|
||||||
|
effective_kb_map_id: Cell::new(state.default_keymap.id),
|
||||||
kb_state: RefCell::new(state.default_keymap.state().unwrap()),
|
kb_state: RefCell::new(state.default_keymap.state().unwrap()),
|
||||||
cursor: Default::default(),
|
cursor: Default::default(),
|
||||||
tree_changed: Default::default(),
|
tree_changed: Default::default(),
|
||||||
|
|
@ -219,6 +226,7 @@ impl WlSeatGlobal {
|
||||||
idle_notifications: Default::default(),
|
idle_notifications: Default::default(),
|
||||||
last_input_usec: Cell::new(now_usec()),
|
last_input_usec: Cell::new(now_usec()),
|
||||||
wlr_data_devices: Default::default(),
|
wlr_data_devices: Default::default(),
|
||||||
|
keymap_version: NumCell::new(1),
|
||||||
});
|
});
|
||||||
state.add_cursor_size(*DEFAULT_CURSOR_SIZE);
|
state.add_cursor_size(*DEFAULT_CURSOR_SIZE);
|
||||||
let seat = slf.clone();
|
let seat = slf.clone();
|
||||||
|
|
@ -236,7 +244,7 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keymap(&self) -> Rc<XkbKeymap> {
|
pub fn keymap(&self) -> Rc<XkbKeymap> {
|
||||||
self.kb_map.get()
|
self.seat_kb_map.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toplevel_drag(&self) -> Option<Rc<XdgToplevelDragV1>> {
|
pub fn toplevel_drag(&self) -> Option<Rc<XdgToplevelDragV1>> {
|
||||||
|
|
@ -505,7 +513,12 @@ impl WlSeatGlobal {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
pub fn set_seat_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
||||||
|
self.seat_kb_map.set(keymap.clone());
|
||||||
|
self.seat_kb_map_id.set(keymap.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_effective_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
||||||
let state = match keymap.state() {
|
let state = match keymap.state() {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -513,24 +526,13 @@ impl WlSeatGlobal {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.kb_map.set(keymap.clone());
|
self.keyboard_node.get().node_on_unfocus(self);
|
||||||
|
self.effective_kb_map.set(keymap.clone());
|
||||||
|
self.effective_kb_map_id.set(keymap.id);
|
||||||
*self.kb_state.borrow_mut() = state;
|
*self.kb_state.borrow_mut() = state;
|
||||||
let bindings = self.bindings.borrow_mut();
|
self.keymap_version.fetch_add(1);
|
||||||
for (id, client) in bindings.iter() {
|
self.pressed_keys.borrow_mut().clear();
|
||||||
for seat in client.values() {
|
self.keyboard_node.get().node_on_focus(self);
|
||||||
let kbs = seat.keyboards.lock();
|
|
||||||
for kb in kbs.values() {
|
|
||||||
let fd = match seat.keymap_fd(keymap) {
|
|
||||||
Ok(fd) => fd,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not creat a file descriptor to transfer the keymap to client {}: {}", id, ErrorFmt(e));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
kb.send_keymap(wl_keyboard::XKB_V1, fd, keymap.map_len as _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_for_lock(self: &Rc<Self>) {
|
pub fn prepare_for_lock(self: &Rc<Self>) {
|
||||||
|
|
@ -1180,12 +1182,13 @@ impl WlSeatRequestHandler for WlSeat {
|
||||||
track!(self.client, p);
|
track!(self.client, p);
|
||||||
self.client.add_client_obj(&p)?;
|
self.client.add_client_obj(&p)?;
|
||||||
self.keyboards.set(req.id, p.clone());
|
self.keyboards.set(req.id, p.clone());
|
||||||
let keymap = self.global.kb_map.get();
|
p.send_keymap();
|
||||||
p.send_keymap(
|
if let Some(surface) = self.global.keyboard_node.get().node_into_surface() {
|
||||||
wl_keyboard::XKB_V1,
|
if surface.client.id == self.client.id {
|
||||||
self.keymap_fd(&keymap)?,
|
let serial = self.client.next_serial();
|
||||||
keymap.map_len as _,
|
p.send_enter(serial, surface.id, &self.global.pressed_keys.borrow())
|
||||||
);
|
}
|
||||||
|
}
|
||||||
if self.version >= REPEAT_INFO_SINCE {
|
if self.version >= REPEAT_INFO_SINCE {
|
||||||
let (rate, delay) = self.global.repeat_rate.get();
|
let (rate, delay) = self.global.repeat_rate.get();
|
||||||
p.send_repeat_info(rate, delay);
|
p.send_repeat_info(rate, delay);
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,20 @@ impl WlSeatGlobal {
|
||||||
time_usec,
|
time_usec,
|
||||||
key,
|
key,
|
||||||
state,
|
state,
|
||||||
} => self.key_event(time_usec, key, state),
|
} => {
|
||||||
|
let desired_kb_map_id = match dev.keymap_id.get() {
|
||||||
|
Some(id) => id,
|
||||||
|
None => self.seat_kb_map_id.get(),
|
||||||
|
};
|
||||||
|
if desired_kb_map_id != self.effective_kb_map_id.get() {
|
||||||
|
let map = match dev.keymap.get() {
|
||||||
|
Some(map) => map,
|
||||||
|
None => self.seat_kb_map.get(),
|
||||||
|
};
|
||||||
|
self.set_effective_keymap(&map);
|
||||||
|
}
|
||||||
|
self.key_event(time_usec, key, state)
|
||||||
|
}
|
||||||
InputEvent::ConnectorPosition {
|
InputEvent::ConnectorPosition {
|
||||||
time_usec,
|
time_usec,
|
||||||
connector,
|
connector,
|
||||||
|
|
@ -742,10 +755,10 @@ impl WlSeatGlobal {
|
||||||
// Focus callbacks
|
// Focus callbacks
|
||||||
impl WlSeatGlobal {
|
impl WlSeatGlobal {
|
||||||
pub fn focus_surface(&self, surface: &WlSurface) {
|
pub fn focus_surface(&self, surface: &WlSurface) {
|
||||||
let pressed_keys: Vec<_> = self.pressed_keys.borrow().iter().copied().collect();
|
let pressed_keys = &*self.pressed_keys.borrow();
|
||||||
let serial = surface.client.next_serial();
|
let serial = surface.client.next_serial();
|
||||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||||
k.send_enter(serial, surface.id, &pressed_keys)
|
k.send_enter(serial, surface.id, pressed_keys)
|
||||||
});
|
});
|
||||||
let ModifierState {
|
let ModifierState {
|
||||||
mods_depressed,
|
mods_depressed,
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,11 @@ use {
|
||||||
ifs::wl_seat::WlSeat,
|
ifs::wl_seat::WlSeat,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
utils::oserror::OsError,
|
utils::{errorfmt::ErrorFmt, numcell::NumCell, oserror::OsError},
|
||||||
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::OwnedFd,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const REPEAT_INFO_SINCE: Version = Version(4);
|
pub const REPEAT_INFO_SINCE: Version = Version(4);
|
||||||
|
|
@ -24,6 +23,7 @@ pub(super) const PRESSED: u32 = 1;
|
||||||
pub struct WlKeyboard {
|
pub struct WlKeyboard {
|
||||||
id: WlKeyboardId,
|
id: WlKeyboardId,
|
||||||
seat: Rc<WlSeat>,
|
seat: Rc<WlSeat>,
|
||||||
|
pub(super) keymap_version: NumCell<u32>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,20 +32,38 @@ impl WlKeyboard {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
|
keymap_version: NumCell::new(0),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_keymap(self: &Rc<Self>, format: u32, fd: Rc<OwnedFd>, size: u32) {
|
pub fn send_keymap(&self) {
|
||||||
|
let map = self.seat.global.effective_kb_map.get();
|
||||||
|
let fd = match self.seat.keymap_fd(&map) {
|
||||||
|
Ok(fd) => fd,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"Could not creat a file descriptor to transfer the keymap to client {}: {}",
|
||||||
|
self.seat.client.id,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
self.seat.client.event(Keymap {
|
self.seat.client.event(Keymap {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
format,
|
format: XKB_V1,
|
||||||
fd,
|
fd,
|
||||||
size,
|
size: map.map_len as _,
|
||||||
})
|
});
|
||||||
|
self.keymap_version
|
||||||
|
.set(self.seat.global.keymap_version.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_enter(self: &Rc<Self>, serial: u32, surface: WlSurfaceId, keys: &[u32]) {
|
pub fn send_enter(self: &Rc<Self>, serial: u32, surface: WlSurfaceId, keys: &[u32]) {
|
||||||
|
if self.keymap_version.get() != self.seat.global.keymap_version.get() {
|
||||||
|
self.send_keymap();
|
||||||
|
}
|
||||||
self.seat.client.event(Enter {
|
self.seat.client.event(Enter {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial,
|
serial,
|
||||||
|
|
|
||||||
|
|
@ -1399,7 +1399,7 @@ impl Node for WlSurface {
|
||||||
seat.scroll_surface(&self, event);
|
seat.scroll_surface(&self, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_on_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
fn node_on_focus(self: Rc<Self>, seat: &WlSeatGlobal) {
|
||||||
if let Some(tl) = self.toplevel.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
tl.tl_data().focus_node.insert(seat.id(), self.clone());
|
tl.tl_data().focus_node.insert(seat.id(), self.clone());
|
||||||
tl.tl_on_activate();
|
tl.tl_on_activate();
|
||||||
|
|
|
||||||
11
src/state.rs
11
src/state.rs
|
|
@ -74,7 +74,7 @@ use {
|
||||||
ExtForeignToplevelListV1Id, JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId,
|
ExtForeignToplevelListV1Id, JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId,
|
||||||
ZwpLinuxDmabufFeedbackV1Id,
|
ZwpLinuxDmabufFeedbackV1Id,
|
||||||
},
|
},
|
||||||
xkbcommon::{XkbContext, XkbKeymap},
|
xkbcommon::{KeymapId, XkbContext, XkbKeymap},
|
||||||
xwayland::{self, XWaylandEvent},
|
xwayland::{self, XWaylandEvent},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
@ -244,6 +244,15 @@ pub struct DeviceHandlerData {
|
||||||
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_id: Cell<Option<KeymapId>>,
|
||||||
|
pub keymap: CloneCell<Option<Rc<XkbKeymap>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceHandlerData {
|
||||||
|
pub fn set_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
||||||
|
self.keymap_id.set(Some(keymap.id));
|
||||||
|
self.keymap.set(Some(keymap.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConnectorData {
|
pub struct ConnectorData {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
|
||||||
device: dev.clone(),
|
device: dev.clone(),
|
||||||
syspath: props.syspath,
|
syspath: props.syspath,
|
||||||
devnode: props.devnode,
|
devnode: props.devnode,
|
||||||
|
keymap_id: Default::default(),
|
||||||
|
keymap: Default::default(),
|
||||||
});
|
});
|
||||||
let ae = Rc::new(AsyncEvent::default());
|
let ae = Rc::new(AsyncEvent::default());
|
||||||
let oh = DeviceHandler {
|
let oh = DeviceHandler {
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ pub trait Node: 'static {
|
||||||
let _ = event;
|
let _ = event;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_on_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
fn node_on_focus(self: Rc<Self>, seat: &WlSeatGlobal) {
|
||||||
let _ = seat;
|
let _ = seat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ 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;
|
||||||
|
pub mod vecset;
|
||||||
pub mod vecstorage;
|
pub mod vecstorage;
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
pub mod xrd;
|
pub mod xrd;
|
||||||
|
|
|
||||||
45
src/utils/vecset.rs
Normal file
45
src/utils/vecset.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub struct VecSet<T> {
|
||||||
|
vec: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for VecSet<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { vec: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for VecSet<T> {
|
||||||
|
type Target = [T];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> VecSet<T> {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.vec.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> VecSet<T> {
|
||||||
|
pub fn insert(&mut self, val: T) -> bool {
|
||||||
|
if self.vec.contains(&val) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.vec.push(val);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, val: &T) -> bool {
|
||||||
|
for i in 0..self.vec.len() {
|
||||||
|
if self.vec[i] == *val {
|
||||||
|
self.vec.swap_remove(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -101,12 +101,15 @@ extern "C" {
|
||||||
|
|
||||||
pub struct XkbContext {
|
pub struct XkbContext {
|
||||||
context: *mut xkb_context,
|
context: *mut xkb_context,
|
||||||
|
ids: KeymapIds,
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn jay_xkbcommon_log_handler_bridge();
|
fn jay_xkbcommon_log_handler_bridge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linear_ids!(KeymapIds, KeymapId, u64);
|
||||||
|
|
||||||
impl XkbContext {
|
impl XkbContext {
|
||||||
pub fn new() -> Result<Self, XkbCommonError> {
|
pub fn new() -> Result<Self, XkbCommonError> {
|
||||||
let res = unsafe { xkb_context_new(XKB_CONTEXT_NO_FLAGS.raw() as _) };
|
let res = unsafe { xkb_context_new(XKB_CONTEXT_NO_FLAGS.raw() as _) };
|
||||||
|
|
@ -117,10 +120,13 @@ impl XkbContext {
|
||||||
xkb_context_set_log_verbosity(res, 10);
|
xkb_context_set_log_verbosity(res, 10);
|
||||||
xkb_context_set_log_fn(res, jay_xkbcommon_log_handler_bridge);
|
xkb_context_set_log_fn(res, jay_xkbcommon_log_handler_bridge);
|
||||||
}
|
}
|
||||||
Ok(Self { context: res })
|
Ok(Self {
|
||||||
|
context: res,
|
||||||
|
ids: Default::default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raw_to_map(raw: *mut xkb_keymap) -> Result<Rc<XkbKeymap>, XkbCommonError> {
|
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 _) };
|
let res = unsafe { xkb_keymap_get_as_string(raw, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) };
|
||||||
if res.is_null() {
|
if res.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -142,6 +148,7 @@ impl XkbContext {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(Rc::new(XkbKeymap {
|
Ok(Rc::new(XkbKeymap {
|
||||||
|
id: self.ids.next(),
|
||||||
keymap: raw,
|
keymap: raw,
|
||||||
map: Rc::new(memfd),
|
map: Rc::new(memfd),
|
||||||
map_len: str.len() + 1,
|
map_len: str.len() + 1,
|
||||||
|
|
@ -164,7 +171,7 @@ impl XkbContext {
|
||||||
if keymap.is_null() {
|
if keymap.is_null() {
|
||||||
return Err(XkbCommonError::KeymapFromBuffer);
|
return Err(XkbCommonError::KeymapFromBuffer);
|
||||||
}
|
}
|
||||||
Self::raw_to_map(keymap)
|
self.raw_to_map(keymap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,6 +185,7 @@ impl Drop for XkbContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct XkbKeymap {
|
pub struct XkbKeymap {
|
||||||
|
pub id: KeymapId,
|
||||||
keymap: *mut xkb_keymap,
|
keymap: *mut xkb_keymap,
|
||||||
pub map: Rc<OwnedFd>,
|
pub map: Rc<OwnedFd>,
|
||||||
pub map_len: usize,
|
pub map_len: usize,
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,7 @@ pub struct Input {
|
||||||
pub natural_scrolling: Option<bool>,
|
pub natural_scrolling: Option<bool>,
|
||||||
pub px_per_wheel_scroll: Option<f64>,
|
pub px_per_wheel_scroll: Option<f64>,
|
||||||
pub transform_matrix: Option<[[f64; 2]; 2]>,
|
pub transform_matrix: Option<[[f64; 2]; 2]>,
|
||||||
|
pub keymap: Option<ConfigKeymap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ use {
|
||||||
context::Context,
|
context::Context,
|
||||||
extractor::{bol, fltorint, opt, recover, str, val, Extractor, ExtractorError},
|
extractor::{bol, fltorint, opt, recover, str, val, Extractor, ExtractorError},
|
||||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||||
parsers::input_match::{InputMatchParser, InputMatchParserError},
|
parsers::{
|
||||||
|
input_match::{InputMatchParser, InputMatchParserError},
|
||||||
|
keymap::KeymapParser,
|
||||||
|
},
|
||||||
Input,
|
Input,
|
||||||
},
|
},
|
||||||
toml::{
|
toml::{
|
||||||
|
|
@ -62,7 +65,7 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
natural_scrolling,
|
natural_scrolling,
|
||||||
px_per_wheel_scroll,
|
px_per_wheel_scroll,
|
||||||
),
|
),
|
||||||
(transform_matrix,),
|
(transform_matrix, keymap),
|
||||||
) = ext.extract((
|
) = ext.extract((
|
||||||
(
|
(
|
||||||
opt(str("tag")),
|
opt(str("tag")),
|
||||||
|
|
@ -76,7 +79,7 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
recover(opt(bol("natural-scrolling"))),
|
recover(opt(bol("natural-scrolling"))),
|
||||||
recover(opt(fltorint("px-per-wheel-scroll"))),
|
recover(opt(fltorint("px-per-wheel-scroll"))),
|
||||||
),
|
),
|
||||||
(recover(opt(val("transform-matrix"))),),
|
(recover(opt(val("transform-matrix"))), opt(val("keymap"))),
|
||||||
))?;
|
))?;
|
||||||
let accel_profile = match accel_profile {
|
let accel_profile = match accel_profile {
|
||||||
None => None,
|
None => None,
|
||||||
|
|
@ -109,6 +112,19 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let keymap = match keymap {
|
||||||
|
None => None,
|
||||||
|
Some(map) => match map.parse(&mut KeymapParser {
|
||||||
|
cx: self.cx,
|
||||||
|
definition: false,
|
||||||
|
}) {
|
||||||
|
Ok(v) => Some(v),
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Could not parse keymap: {}", self.cx.error(e));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
Ok(Input {
|
Ok(Input {
|
||||||
tag: tag.despan_into(),
|
tag: tag.despan_into(),
|
||||||
match_: match_val.parse_map(&mut InputMatchParser(self.cx))?,
|
match_: match_val.parse_map(&mut InputMatchParser(self.cx))?,
|
||||||
|
|
@ -121,6 +137,7 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
natural_scrolling: natural_scrolling.despan(),
|
natural_scrolling: natural_scrolling.despan(),
|
||||||
px_per_wheel_scroll: px_per_wheel_scroll.despan(),
|
px_per_wheel_scroll: px_per_wheel_scroll.despan(),
|
||||||
transform_matrix,
|
transform_matrix,
|
||||||
|
keymap,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ impl Action {
|
||||||
Box::new(move || {
|
Box::new(move || {
|
||||||
for c in input_devices() {
|
for c in input_devices() {
|
||||||
if input.match_.matches(c, &state) {
|
if input.match_.matches(c, &state) {
|
||||||
input.apply(c);
|
input.apply(c, &state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -361,7 +361,7 @@ impl InputMatch {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
fn apply(&self, c: InputDevice) {
|
fn apply(&self, c: InputDevice, state: &State) {
|
||||||
if let Some(v) = self.accel_profile {
|
if let Some(v) = self.accel_profile {
|
||||||
c.set_accel_profile(v);
|
c.set_accel_profile(v);
|
||||||
}
|
}
|
||||||
|
|
@ -389,6 +389,11 @@ impl Input {
|
||||||
if let Some(v) = self.transform_matrix {
|
if let Some(v) = self.transform_matrix {
|
||||||
c.set_transform_matrix(v);
|
c.set_transform_matrix(v);
|
||||||
}
|
}
|
||||||
|
if let Some(v) = &self.keymap {
|
||||||
|
if let Some(km) = state.get_keymap(v) {
|
||||||
|
c.set_keymap(km);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,19 +559,25 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_keymap(&self, map: &ConfigKeymap) {
|
fn get_keymap(&self, map: &ConfigKeymap) -> Option<Keymap> {
|
||||||
let map = match map {
|
let map = match map {
|
||||||
ConfigKeymap::Named(n) => match self.keymaps.get(n) {
|
ConfigKeymap::Named(n) => match self.keymaps.get(n) {
|
||||||
None => {
|
None => {
|
||||||
log::warn!("Unknown keymap {n}");
|
log::warn!("Unknown keymap {n}");
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
Some(m) => *m,
|
Some(m) => *m,
|
||||||
},
|
},
|
||||||
ConfigKeymap::Defined { map, .. } => *map,
|
ConfigKeymap::Defined { map, .. } => *map,
|
||||||
ConfigKeymap::Literal(map) => *map,
|
ConfigKeymap::Literal(map) => *map,
|
||||||
};
|
};
|
||||||
self.persistent.seat.set_keymap(map);
|
Some(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_keymap(&self, map: &ConfigKeymap) {
|
||||||
|
if let Some(map) = self.get_keymap(map) {
|
||||||
|
self.persistent.seat.set_keymap(map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_status(&self, status: &Option<Status>) {
|
fn set_status(&self, status: &Option<Status>) {
|
||||||
|
|
@ -816,7 +827,7 @@ fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
|
||||||
move |c| {
|
move |c| {
|
||||||
for input in &config.inputs {
|
for input in &config.inputs {
|
||||||
if input.match_.matches(c, &state) {
|
if input.match_.matches(c, &state) {
|
||||||
input.apply(c);
|
input.apply(c, &state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -790,6 +790,10 @@
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"keymap": {
|
||||||
|
"description": "The keymap to use for this device.\n\nThis overrides the global keymap. The keymap becomes active when a key is pressed.\n\n- Example:\n\n ```toml\n [[inputs]]\n match.name = \"ZSA Technology Labs Inc ErgoDox EZ\"\n keymap.name = \"external\"\n ```\n",
|
||||||
|
"$ref": "#/$defs/Keymap"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -1519,6 +1519,22 @@ The table has the following fields:
|
||||||
|
|
||||||
The value of this field should be an array of arrays of numbers.
|
The value of this field should be an array of arrays of numbers.
|
||||||
|
|
||||||
|
- `keymap` (optional):
|
||||||
|
|
||||||
|
The keymap to use for this device.
|
||||||
|
|
||||||
|
This overrides the global keymap. The keymap becomes active when a key is pressed.
|
||||||
|
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[inputs]]
|
||||||
|
match.name = "ZSA Technology Labs Inc ErgoDox EZ"
|
||||||
|
keymap.name = "external"
|
||||||
|
```
|
||||||
|
|
||||||
|
The value of this field should be a [Keymap](#types-Keymap).
|
||||||
|
|
||||||
|
|
||||||
<a name="types-InputMatch"></a>
|
<a name="types-InputMatch"></a>
|
||||||
### `InputMatch`
|
### `InputMatch`
|
||||||
|
|
|
||||||
|
|
@ -1206,6 +1206,21 @@ Input:
|
||||||
match.is-pointer = true
|
match.is-pointer = true
|
||||||
transform-matrix = [[0.35, 0], [0, 0.35]]
|
transform-matrix = [[0.35, 0], [0, 0.35]]
|
||||||
```
|
```
|
||||||
|
keymap:
|
||||||
|
ref: Keymap
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
The keymap to use for this device.
|
||||||
|
|
||||||
|
This overrides the global keymap. The keymap becomes active when a key is pressed.
|
||||||
|
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[inputs]]
|
||||||
|
match.name = "ZSA Technology Labs Inc ErgoDox EZ"
|
||||||
|
keymap.name = "external"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
AccelProfile:
|
AccelProfile:
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,16 @@ request get_device {
|
||||||
id: u32,
|
id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request set_device_keymap {
|
||||||
|
id: u32,
|
||||||
|
keymap: fd,
|
||||||
|
keymap_len: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
request get_device_keymap {
|
||||||
|
id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
# events
|
# events
|
||||||
|
|
||||||
event seat {
|
event seat {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue