seat: implement per-device keymaps
This commit is contained in:
parent
225995eb2f
commit
826f40adca
21 changed files with 293 additions and 71 deletions
112
src/cli/input.rs
112
src/cli/input.rs
|
|
@ -19,7 +19,7 @@ use {
|
|||
ops::DerefMut,
|
||||
rc::Rc,
|
||||
},
|
||||
uapi::c,
|
||||
uapi::{c, OwnedFd},
|
||||
};
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
|
|
@ -119,6 +119,10 @@ pub enum DeviceCommand {
|
|||
SetPxPerWheelScroll(SetPxPerWheelScrollArgs),
|
||||
/// Set the transformation matrix.
|
||||
SetTransformMatrix(SetTransformMatrixArgs),
|
||||
/// Set the keymap of this device.
|
||||
SetKeymap(SetKeymapArgs),
|
||||
/// Retrieve the keymap of this device.
|
||||
Keymap,
|
||||
/// Attach the device to a seat.
|
||||
Attach(AttachArgs),
|
||||
/// 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) {
|
||||
let tc = &self.tc;
|
||||
match args.command.unwrap_or_default() {
|
||||
|
|
@ -318,40 +363,15 @@ impl Input {
|
|||
});
|
||||
}
|
||||
SeatCommand::SetKeymap(a) => {
|
||||
let (memfd, len) = self.prepare_keymap(&a);
|
||||
self.handle_error(input, |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 {
|
||||
self_id: input,
|
||||
seat: &args.seat,
|
||||
keymap: Rc::new(memfd),
|
||||
keymap_len: map.len() as _,
|
||||
keymap: memfd,
|
||||
keymap_len: len as _,
|
||||
});
|
||||
}
|
||||
SeatCommand::UseHardwareCursor(a) => {
|
||||
|
|
@ -368,20 +388,11 @@ impl Input {
|
|||
self.handle_error(input, |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 {
|
||||
self_id: input,
|
||||
seat: &args.seat,
|
||||
});
|
||||
tc.round_trip().await;
|
||||
let map = data.take();
|
||||
let map = self.handle_keymap(input).await;
|
||||
stdout().write_all(&map).unwrap();
|
||||
}
|
||||
SeatCommand::SetCursorSize(a) => {
|
||||
|
|
@ -530,6 +541,29 @@ impl Input {
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,23 @@ impl ConfigProxyHandler {
|
|||
} else {
|
||||
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(())
|
||||
}
|
||||
|
||||
|
|
@ -1746,6 +1762,9 @@ impl ConfigProxyHandler {
|
|||
self.handle_set_explicit_sync_enabled(enabled)
|
||||
}
|
||||
ClientMessage::GetSocketPath => self.handle_get_socket_path(),
|
||||
ClientMessage::DeviceSetKeymap { device, keymap } => self
|
||||
.handle_set_device_keymap(device, keymap)
|
||||
.wrn("set_device_keymap")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,11 @@ use {
|
|||
state::{DeviceHandlerData, InputDeviceData},
|
||||
utils::errorfmt::ErrorFmt,
|
||||
wire::{jay_input::*, JayInputId},
|
||||
xkbcommon::XkbCommonError,
|
||||
xkbcommon::{XkbCommonError, XkbKeymap},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
|
||||
pub struct JayInput {
|
||||
|
|
@ -67,8 +68,7 @@ impl JayInput {
|
|||
});
|
||||
}
|
||||
|
||||
fn send_keymap(&self, data: &WlSeatGlobal) {
|
||||
let map = data.keymap();
|
||||
fn send_keymap(&self, map: &XkbKeymap) {
|
||||
self.client.event(Keymap {
|
||||
self_id: self.id,
|
||||
keymap: map.map.clone(),
|
||||
|
|
@ -138,6 +138,20 @@ impl JayInput {
|
|||
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 {
|
||||
|
|
@ -174,13 +188,9 @@ impl JayInputRequestHandler for JayInput {
|
|||
}
|
||||
|
||||
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);
|
||||
let mut map = vec![];
|
||||
cm.read(&mut map)?;
|
||||
self.or_error(|| {
|
||||
let map = self.client.state.xkb_ctx.keymap_from_str(&map)?;
|
||||
self.set_keymap_impl(&req.keymap, req.keymap_len, |map| {
|
||||
let seat = self.seat(req.seat)?;
|
||||
seat.set_keymap(&map);
|
||||
seat.set_seat_keymap(&map);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -200,7 +210,7 @@ impl JayInputRequestHandler for JayInput {
|
|||
fn get_keymap(&self, req: GetKeymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let seat = self.seat(req.seat)?;
|
||||
self.send_keymap(&seat);
|
||||
self.send_keymap(&seat.keymap());
|
||||
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! {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ use {
|
|||
WlSeatId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
|
||||
ZwpRelativePointerV1Id,
|
||||
},
|
||||
xkbcommon::{XkbKeymap, XkbState},
|
||||
xkbcommon::{KeymapId, XkbKeymap, XkbState},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
jay_config::keyboard::mods::Modifiers,
|
||||
|
|
@ -141,7 +141,10 @@ pub struct WlSeatGlobal {
|
|||
wlr_data_devices:
|
||||
CopyHashMap<(ClientId, ZwlrDataControlDeviceV1Id), Rc<ZwlrDataControlDeviceV1>>,
|
||||
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>,
|
||||
cursor: CloneCell<Option<Rc<dyn Cursor>>>,
|
||||
tree_changed: Rc<AsyncEvent>,
|
||||
|
|
@ -197,7 +200,10 @@ impl WlSeatGlobal {
|
|||
data_devices: RefCell::new(Default::default()),
|
||||
primary_selection_devices: RefCell::new(Default::default()),
|
||||
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()),
|
||||
cursor: Default::default(),
|
||||
tree_changed: Default::default(),
|
||||
|
|
@ -238,7 +244,7 @@ impl WlSeatGlobal {
|
|||
}
|
||||
|
||||
pub fn keymap(&self) -> Rc<XkbKeymap> {
|
||||
self.kb_map.get()
|
||||
self.seat_kb_map.get()
|
||||
}
|
||||
|
||||
pub fn toplevel_drag(&self) -> Option<Rc<XdgToplevelDragV1>> {
|
||||
|
|
@ -507,7 +513,12 @@ impl WlSeatGlobal {
|
|||
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() {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
|
|
@ -516,7 +527,8 @@ impl WlSeatGlobal {
|
|||
}
|
||||
};
|
||||
self.keyboard_node.get().node_on_unfocus(self);
|
||||
self.kb_map.set(keymap.clone());
|
||||
self.effective_kb_map.set(keymap.clone());
|
||||
self.effective_kb_map_id.set(keymap.id);
|
||||
*self.kb_state.borrow_mut() = state;
|
||||
self.keymap_version.fetch_add(1);
|
||||
self.pressed_keys.borrow_mut().clear();
|
||||
|
|
|
|||
|
|
@ -196,7 +196,20 @@ impl WlSeatGlobal {
|
|||
time_usec,
|
||||
key,
|
||||
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 {
|
||||
time_usec,
|
||||
connector,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl WlKeyboard {
|
|||
}
|
||||
|
||||
pub fn send_keymap(&self) {
|
||||
let map = self.seat.global.kb_map.get();
|
||||
let map = self.seat.global.effective_kb_map.get();
|
||||
let fd = match self.seat.keymap_fd(&map) {
|
||||
Ok(fd) => fd,
|
||||
Err(e) => {
|
||||
|
|
|
|||
11
src/state.rs
11
src/state.rs
|
|
@ -74,7 +74,7 @@ use {
|
|||
ExtForeignToplevelListV1Id, JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId,
|
||||
ZwpLinuxDmabufFeedbackV1Id,
|
||||
},
|
||||
xkbcommon::{XkbContext, XkbKeymap},
|
||||
xkbcommon::{KeymapId, XkbContext, XkbKeymap},
|
||||
xwayland::{self, XWaylandEvent},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
|
|
@ -244,6 +244,15 @@ pub struct DeviceHandlerData {
|
|||
pub device: Rc<dyn InputDevice>,
|
||||
pub syspath: 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 {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
|
|||
device: dev.clone(),
|
||||
syspath: props.syspath,
|
||||
devnode: props.devnode,
|
||||
keymap_id: Default::default(),
|
||||
keymap: Default::default(),
|
||||
});
|
||||
let ae = Rc::new(AsyncEvent::default());
|
||||
let oh = DeviceHandler {
|
||||
|
|
|
|||
|
|
@ -101,12 +101,15 @@ extern "C" {
|
|||
|
||||
pub struct XkbContext {
|
||||
context: *mut xkb_context,
|
||||
ids: KeymapIds,
|
||||
}
|
||||
|
||||
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 _) };
|
||||
|
|
@ -117,10 +120,13 @@ impl XkbContext {
|
|||
xkb_context_set_log_verbosity(res, 10);
|
||||
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 _) };
|
||||
if res.is_null() {
|
||||
unsafe {
|
||||
|
|
@ -142,6 +148,7 @@ impl XkbContext {
|
|||
)
|
||||
.unwrap();
|
||||
Ok(Rc::new(XkbKeymap {
|
||||
id: self.ids.next(),
|
||||
keymap: raw,
|
||||
map: Rc::new(memfd),
|
||||
map_len: str.len() + 1,
|
||||
|
|
@ -164,7 +171,7 @@ impl XkbContext {
|
|||
if keymap.is_null() {
|
||||
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 id: KeymapId,
|
||||
keymap: *mut xkb_keymap,
|
||||
pub map: Rc<OwnedFd>,
|
||||
pub map_len: usize,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue