Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add xkbswitch support for keyboard layout #1985

Merged
merged 5 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/blocks/keyboard_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//!
//! Four drivers are available:
//! - `setxkbmap` which polls setxkbmap to get the current layout
//! - `xkbswitch` which utilizes [XkbSwitch](https://github.com/grwlf/xkb-switch) to monitor and retrieve the current layout and variant
//! - `localebus` which can read asynchronous updates from the systemd `org.freedesktop.locale1` D-Bus path
//! - `kbddbus` which uses [kbdd](https://github.com/qnikst/kbdd) to monitor per-window layout changes via DBus
//! - `sway` which can read asynchronous updates from the sway IPC
Expand All @@ -12,7 +13,7 @@
//!
//! Key | Values | Default
//! ----|--------|--------
//! `driver` | One of `"setxkbmap"`, `"localebus"`, `"kbddbus"` or `"sway"`, depending on your system. | `"setxkbmap"`
//! `driver` | One of `"setxkbmap"`, `"xkbswitch"`, "localebus"`, `"kbddbus"` or `"sway"`, depending on your system. | `"setxkbmap"`
//! `interval` | Update interval, in seconds. Only used by the `"setxkbmap"` driver. | `60`
//! `format` | A string to customise the output of this block. See below for available placeholders. | `" $layout "`
//! `sway_kb_identifier` | Identifier of the device you want to monitor, as found in the output of `swaymsg -t get_inputs`. | Defaults to first input found
Expand All @@ -34,6 +35,15 @@
//! interval = 15
//! ```
//!
//! Check `xkbswitch` every 15 seconds
//!
//! ```toml
//! [[block]]
//! block = "keyboard_layout"
//! driver = "xkbswitch"
//! interval = 15
//! ```
//!
//! Listen to D-Bus for changes:
//!
//! ```toml
Expand Down Expand Up @@ -82,6 +92,9 @@
mod set_xkb_map;
use set_xkb_map::SetXkbMap;

mod xkb_switch;
use xkb_switch::XkbSwitch;

mod locale_bus;
use locale_bus::LocaleBus;

Expand Down Expand Up @@ -109,6 +122,7 @@ pub struct Config {
pub enum KeyboardLayoutDriver {
#[default]
SetXkbMap,
XkbSwitch,
LocaleBus,
KbddBus,
Sway,
Expand All @@ -119,6 +133,7 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {

let mut backend: Box<dyn Backend> = match config.driver {
KeyboardLayoutDriver::SetXkbMap => Box::new(SetXkbMap::new(config.interval)),
KeyboardLayoutDriver::XkbSwitch => Box::new(XkbSwitch::new(config.interval)),
KeyboardLayoutDriver::LocaleBus => Box::new(LocaleBus::new().await?),
KeyboardLayoutDriver::KbddBus => Box::new(KbddBus::new().await?),
KeyboardLayoutDriver::Sway => Box::new(Sway::new(config.sway_kb_identifier.clone()).await?),
Expand Down
44 changes: 44 additions & 0 deletions src/blocks/keyboard_layout/xkb_switch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use super::*;
use tokio::process::Command;

pub(super) struct XkbSwitch(Seconds);

impl XkbSwitch {
pub(super) fn new(update_interval: Seconds) -> Self {
Self(update_interval)
}
}

#[async_trait]
impl Backend for XkbSwitch {
async fn get_info(&mut self) -> Result<Info> {
// This command output is in the format of "layout(variant)" or "layout"
let output = Command::new("xkb-switch")
.arg("-p")
.output()
.await
.error("Failed to execute 'xkb-switch -p'")?;

let output =
String::from_utf8(output.stdout).error("xkb-switch produces a non-UTF8 output")?;

let mut components = output.trim_end().split('(');

let layout = components
.next()
.error("Could not find layout entry in xkb-switch")?
.to_string();

let variant = components
.last()
// Remove the trailing parenthesis ")"
.map(|variant_str| variant_str.split_at(variant_str.len() - 1).0.to_string());

Ok(Info { layout, variant })
}

async fn wait_for_change(&mut self) -> Result<()> {
sleep(self.0 .0).await;
Ok(())
}
}