Skip to content

Commit

Permalink
seat: implement per-device keymaps
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Apr 12, 2024
1 parent 225995e commit 826f40a
Show file tree
Hide file tree
Showing 21 changed files with 293 additions and 71 deletions.
4 changes: 4 additions & 0 deletions deploy-notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Unreleased

- Needs jay-config release.
- Needs jay-toml-config release.
- Needs jay-compositor release.

# 1.0.3

- Needs jay-compositor release.
Expand Down
4 changes: 4 additions & 0 deletions jay-config/src/_private/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,10 @@ impl Client {
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) {
self.send(&ClientMessage::SetLeftHanded {
device,
Expand Down
4 changes: 4 additions & 0 deletions jay-config/src/_private/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,10 @@ pub enum ClientMessage<'a> {
enabled: bool,
},
GetSocketPath,
DeviceSetKeymap {
device: InputDevice,
keymap: Keymap,
},
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down
10 changes: 10 additions & 0 deletions jay-config/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ impl InputDevice {
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.
pub fn has_capability(self, cap: Capability) -> bool {
get!(false).has_capability(self, cap)
Expand Down
1 change: 1 addition & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Unreleased

- Add support for wp-alpha-modifier.
- Add support for per-device keymaps.

# 1.0.3 (2024-04-11)

Expand Down
112 changes: 73 additions & 39 deletions src/cli/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use {
ops::DerefMut,
rc::Rc,
},
uapi::c,
uapi::{c, OwnedFd},
};

#[derive(Args, Debug)]
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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() {
Expand All @@ -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) => {
Expand All @@ -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) => {
Expand Down Expand Up @@ -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;
}
Expand Down
21 changes: 20 additions & 1 deletion src/config/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down Expand Up @@ -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(())
}
Expand Down
48 changes: 38 additions & 10 deletions src/ifs/jay_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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(())
})
}
Expand All @@ -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(())
})
}
Expand Down Expand Up @@ -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! {
Expand Down
Loading

0 comments on commit 826f40a

Please sign in to comment.