1extern crate swayipc;
2
3use std::ffi::{CStr, CString};
4
5use std::os::raw::c_char;
6
7use swayipc::{Connection, Input};
8
9#[derive(Debug)]
10enum Error {
11 InconsistentLayouts,
12 NoKeyboards,
13}
14
15#[no_mangle]
16pub extern "C" fn Xkb_Switch_getXkbLayout() -> *const c_char {
17 let mut conn = Connection::new().unwrap();
18 let layout = get_cur_layout(&mut conn).unwrap();
19 CString::new(layout).unwrap().into_raw()
21}
22
23fn get_cur_layout(conn: &mut Connection) -> Result<String, Error> {
24 let mut layouts: Vec<String> = get_keyboards(conn)
25 .drain(..)
26 .filter_map(|kb| kb.xkb_active_layout_name)
27 .collect();
28 layouts.dedup();
29 match layouts.leak() {
30 [] => Err(Error::NoKeyboards),
31 [layout] => Ok(layout.to_string()),
32 _ => Err(Error::InconsistentLayouts),
33 }
34}
35
36fn get_keyboards(conn: &mut Connection) -> Vec<Input> {
37 let mut all_inputs = conn.get_inputs().unwrap_or_default();
38 all_inputs.retain(|input_device| input_device.input_type == "keyboard");
39 all_inputs
40}
41
42#[no_mangle]
43pub extern "C" fn Xkb_Switch_setXkbLayout(layout_ptr: *const c_char) {
44 match Connection::new() {
45 Ok(mut conn) => {
46 let layout = unsafe { CStr::from_ptr(layout_ptr).to_string_lossy().to_string() };
47 switch_layout(&mut conn, &layout);
48 }
50 Err(_) => (),
51 };
52}
53
54fn switch_layout(conn: &mut Connection, layout: &String) {
55 get_keyboards(conn).iter().for_each(|kb| {
56 let layout_index = kb
57 .xkb_layout_names
58 .iter()
59 .position(|x| x == layout)
60 .unwrap();
61
62 let _ = conn.run_command(format!(
63 "input {} xkb_switch_layout {}",
64 kb.identifier, layout_index
65 ));
66 });
68}