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 support for the xkb-switch keyboard layout reader. #1386

Merged
merged 3 commits into from
Jan 8, 2022
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
12 changes: 12 additions & 0 deletions doc/blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,7 @@ Four drivers are available:
- `setxkbmap` which polls setxkbmap to get the current layout
- `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
- `xkbswitch` which uses [xkb-switch](https://github.com/grwlf/xkb-switch) to show the current layout and variant. This works when `setxkbmap` is used to set a comma separated list of layouts, such as `us,es,fr`.
- `sway` which can read asynchronous updates from the sway IPC

Which of these methods is appropriate will depend on your system setup.
Expand Down Expand Up @@ -985,6 +986,17 @@ block = "keyboard_layout"
driver = "kbddbus"
```

Poll `xkb-switch` for current layout and variant:

```toml
[[block]]
block = "keyboard_layout"
driver = "xkbswitch"
on_click = "xkb-switch -n"
format = "{layout} {variant}"
interval = 1
```

Listen to sway for changes:

```toml
Expand Down
55 changes: 55 additions & 0 deletions src/blocks/keyboard_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub enum KeyboardLayoutDriver {
SetXkbMap,
LocaleBus,
KbddBus,
XkbSwitch,
Sway,
}

Expand Down Expand Up @@ -413,6 +414,59 @@ impl KeyboardLayoutMonitor for Sway {
}
}

pub struct XkbSwitch;

impl XkbSwitch {
pub fn new() -> Result<XkbSwitch> {
Command::new("xkb-switch")
.output()
.block_error("keyboard_layout", "Failed to find xkb-switch in PATH")
.map(|_| XkbSwitch)
}
}

fn xkb_switch_show_layout_and_variant() -> Result<(String, Option<String>)> {
// This command should return a string like "layout(variant)" or "layout"
Command::new("xkb-switch")
.args(&["-p"])
.output()
.block_error("keyboard_layout", "Failed to execute `xkb-switch -p`.")
.and_then(|raw| {
String::from_utf8(raw.stdout).block_error("keyboard_layout", "Non-UTF8 input.")
})
.and_then(|layout_and_variant| {
let mut components = layout_and_variant.trim_end().split('(');

let layout = components
.next()
.ok_or("")
.block_error("keyboard_layout", "Unable to find keyboard layout")?
.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((layout, variant))
})
}

impl KeyboardLayoutMonitor for XkbSwitch {
fn keyboard_layout(&self) -> Result<String> {
xkb_switch_show_layout_and_variant().map(|layout_and_variant| layout_and_variant.0)
}

fn keyboard_variant(&self) -> Result<String> {
xkb_switch_show_layout_and_variant()
.map(|layout_and_variant| layout_and_variant.1.unwrap_or_else(|| "".into()))
}

fn must_poll(&self) -> bool {
true
}
}

#[derive(Deserialize, Debug, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct KeyboardLayoutConfig {
Expand Down Expand Up @@ -470,6 +524,7 @@ impl ConfigBlock for KeyboardLayout {
monitor.monitor(id, send);
Box::new(monitor)
}
KeyboardLayoutDriver::XkbSwitch => Box::new(XkbSwitch::new()?),
KeyboardLayoutDriver::Sway => {
let monitor = Sway::new(block_config.sway_kb_identifier)?;
monitor.monitor(id, send);
Expand Down