1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
use x11rb::connection::{Connection, RequestConnection};
use x11rb::protocol::xkb::{self, ConnectionExt as XkbConnectionExt};
use x11rb::protocol::xproto::{AtomEnum, ConnectionExt};
use x11rb::rust_connection::RustConnection;
#[derive(Debug, Default)]
pub struct RuleNames {
pub rules: String,
pub model: String,
pub layout: String,
pub variant: String,
pub options: String,
}
pub struct X11Connection {
pub conn: RustConnection,
pub root: x11rb::protocol::xproto::Window,
xkb_ok: bool,
}
impl X11Connection {
pub fn open() -> Option<Self> {
let (conn, screen_num) = x11rb::connect(None).ok()?;
let root = conn.setup().roots[screen_num].root;
let xkb_ok = conn
.extension_information(xkb::X11_EXTENSION_NAME)
.ok()
.flatten()
.is_some();
if xkb_ok {
let _ = conn.xkb_use_extension(1, 0).ok();
}
Some(Self { conn, root, xkb_ok })
}
pub fn modifier_mask(&self) -> u16 {
self.conn
.query_pointer(self.root)
.ok()
.and_then(|c| c.reply().ok())
.map(|r| r.mask.into())
.unwrap_or(0)
}
pub fn active_group(&self) -> usize {
if !self.xkb_ok {
return 0;
}
self.conn
.xkb_get_state(0x0100)
.ok()
.and_then(|c| c.reply().ok())
.map(|r| u8::from(r.group) as usize)
.unwrap_or(0)
}
}
pub fn get_xkb_rule_names() -> Option<RuleNames> {
let (conn, screen_num) = x11rb::connect(None).ok()?;
let screen = &conn.setup().roots[screen_num];
let atom = conn
.intern_atom(false, b"_XKB_RULES_NAMES")
.ok()?
.reply()
.ok()?
.atom;
let prop = conn
.get_property(false, screen.root, atom, AtomEnum::ANY, 0, 1024)
.ok()?
.reply()
.ok()?;
if prop.value.is_empty() || prop.format == 0 {
return None;
}
let parts: Vec<&str> = prop
.value
.split(|&b| b == 0)
.filter_map(|s| std::str::from_utf8(s).ok())
.collect();
Some(RuleNames {
rules: parts.first().map(|s| s.to_string()).unwrap_or_default(),
model: parts.get(1).map(|s| s.to_string()).unwrap_or_default(),
layout: parts.get(2).map(|s| s.to_string()).unwrap_or_default(),
variant: parts.get(3).map(|s| s.to_string()).unwrap_or_default(),
options: parts.get(4).map(|s| s.to_string()).unwrap_or_default(),
})
}
|