diff --git a/src/cli/input.rs b/src/cli/input.rs index ee253ebf..2506cbb0 100644 --- a/src/cli/input.rs +++ b/src/cli/input.rs @@ -77,6 +77,8 @@ pub enum SeatCommand { SetRepeatRate(SetRepeatRateArgs), /// Set the keymap. SetKeymap(SetKeymapArgs), + /// Set the keymap from RMLVO names. + SetKeymapFromNames(SetKeymapFromNamesArgs), /// Retrieve the keymap. Keymap, /// Configure whether this seat uses the hardware cursor. @@ -145,6 +147,8 @@ pub enum DeviceCommand { SetTransformMatrix(SetTransformMatrixArgs), /// Set the keymap of this device. SetKeymap(SetKeymapArgs), + /// Set the keymap of this device from RMLVO names. + SetKeymapFromNames(SetKeymapFromNamesArgs), /// Retrieve the keymap of this device. Keymap, /// Attach the device to a seat. @@ -293,6 +297,25 @@ pub struct SetKeymapArgs { pub file: Option, } +#[derive(Args, Debug, Clone)] +pub struct SetKeymapFromNamesArgs { + /// The rules file. + #[clap(short, long)] + pub rules: Option, + /// The model name. + #[clap(short, long)] + pub model: Option, + /// The comma-separated list of layouts. + #[clap(short, long)] + pub layout: Option, + /// The comma-separated list of layout variants. + #[clap(short, long)] + pub variant: Option, + /// The comma-separated list of options. + #[clap(short, long)] + pub options: Option, +} + #[derive(Args, Debug, Clone)] pub struct UseHardwareCursorArgs { /// Whether the seat uses the hardware cursor. @@ -503,6 +526,20 @@ impl Input { }); } }, + SeatCommand::SetKeymapFromNames(a) => { + self.handle_error(input, |e| { + eprintln!("Could not set keymap: {}", e); + }); + tc.send(jay_input::SetKeymapFromNames { + self_id: input, + seat: &args.seat, + rules: a.rules.as_deref(), + model: a.model.as_deref(), + layout: a.layout.as_deref(), + variant: a.variant.as_deref(), + options: a.options.as_deref(), + }); + } } tc.round_trip().await; } @@ -725,6 +762,20 @@ impl Input { enabled: a.middle_button_emulation as _, }); } + DeviceCommand::SetKeymapFromNames(a) => { + self.handle_error(input, |e| { + eprintln!("Could not set keymap: {}", e); + }); + tc.send(jay_input::SetDeviceKeymapFromNames { + self_id: input, + id: args.device, + rules: a.rules.as_deref(), + model: a.model.as_deref(), + layout: a.layout.as_deref(), + variant: a.variant.as_deref(), + options: a.options.as_deref(), + }); + } } tc.round_trip().await; } diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index 46aa4393..611ab54c 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -79,7 +79,7 @@ impl Global for JayCompositorGlobal { } fn version(&self) -> u32 { - 23 + 24 } fn required_caps(&self) -> ClientCaps { diff --git a/src/ifs/jay_input.rs b/src/ifs/jay_input.rs index 531d2cd3..a06a2505 100644 --- a/src/ifs/jay_input.rs +++ b/src/ifs/jay_input.rs @@ -16,6 +16,7 @@ use { utils::errorfmt::ErrorFmt, wire::{JayInputId, jay_input::*}, }, + kbvm::xkb::rmlvo::Group, std::rc::Rc, thiserror::Error, uapi::OwnedFd, @@ -212,6 +213,44 @@ impl JayInput { Ok(()) }) } + + fn set_keymap_from_names_impl( + &self, + rules: Option<&str>, + model: Option<&str>, + layout: Option<&str>, + variant: Option<&str>, + options: Option<&str>, + f: F, + ) -> Result<(), JayInputError> + where + F: FnOnce(&Rc) -> Result<(), JayInputError>, + { + self.or_error(|| { + let mut groups = None::>; + if layout.is_some() || variant.is_some() { + groups = Some( + Group::from_layouts_and_variants( + layout.unwrap_or_default(), + variant.unwrap_or_default(), + ) + .collect(), + ); + } + let mut options_vec = None::>; + if let Some(options) = options { + options_vec = Some(options.split(",").collect()); + } + let keymap = self.client.state.kb_ctx.keymap_from_names( + rules, + model, + groups.as_deref(), + options_vec.as_deref(), + )?; + f(&keymap)?; + Ok(()) + }) + } } impl JayInputRequestHandler for JayInput { @@ -539,6 +578,44 @@ impl JayInputRequestHandler for JayInput { Ok(()) }) } + + fn set_keymap_from_names( + &self, + req: SetKeymapFromNames<'_>, + _slf: &Rc, + ) -> Result<(), Self::Error> { + self.set_keymap_from_names_impl( + req.rules, + req.model, + req.layout, + req.variant, + req.options, + |map| { + let seat = self.seat(req.seat)?; + seat.set_seat_keymap(&map); + Ok(()) + }, + ) + } + + fn set_device_keymap_from_names( + &self, + req: SetDeviceKeymapFromNames<'_>, + _slf: &Rc, + ) -> Result<(), Self::Error> { + self.set_keymap_from_names_impl( + req.rules, + req.model, + req.layout, + req.variant, + req.options, + |map| { + let dev = self.device(req.id)?; + dev.set_keymap(Some(map.clone())); + Ok(()) + }, + ) + } } object_base! { diff --git a/src/tools/tool_client.rs b/src/tools/tool_client.rs index 20b0eb48..32b307ec 100644 --- a/src/tools/tool_client.rs +++ b/src/tools/tool_client.rs @@ -335,7 +335,7 @@ impl ToolClient { self_id: s.registry, name: s.jay_compositor.0, interface: JayCompositor.name(), - version: s.jay_compositor.1.min(23), + version: s.jay_compositor.1.min(24), id: id.into(), }); self.jay_compositor.set(Some(id)); diff --git a/wire/jay_input.txt b/wire/jay_input.txt index 2f81bb75..73b0b65c 100644 --- a/wire/jay_input.txt +++ b/wire/jay_input.txt @@ -143,6 +143,24 @@ request reload_simple_im (since = 22) { seat: str, } +request set_keymap_from_names (since = 24) { + seat: str, + rules: optstr, + model: optstr, + layout: optstr, + variant: optstr, + options: optstr, +} + +request set_device_keymap_from_names (since = 24) { + id: u32, + rules: optstr, + model: optstr, + layout: optstr, + variant: optstr, + options: optstr, +} + # events event seat {