1//! XKB state.
2
3use std::os::raw::c_char;
4use std::ptr::NonNull;
5
6use smol_str::SmolStr;
7#[cfg(x11_platform)]
8use x11_dl::xlib_xcb::xcb_connection_t;
9use xkbcommon_dl::{
10 self as xkb, xkb_keycode_t, xkb_keysym_t, xkb_layout_index_t, xkb_state, xkb_state_component,
11};
12
13use crate::platform_impl::common::xkb::keymap::XkbKeymap;
14#[cfg(x11_platform)]
15use crate::platform_impl::common::xkb::XKBXH;
16use crate::platform_impl::common::xkb::{make_string_with, XKBH};
17
18#[derive(Debug)]
19pub struct XkbState {
20 state: NonNull<xkb_state>,
21 modifiers: ModifiersState,
22}
23
24impl XkbState {
25 #[cfg(wayland_platform)]
26 pub fn new_wayland(keymap: &XkbKeymap) -> Option<Self> {
27 let state = NonNull::new(unsafe { (XKBH.xkb_state_new)(keymap.as_ptr()) })?;
28 Some(Self::new_inner(state))
29 }
30
31 #[cfg(x11_platform)]
32 pub fn new_x11(xcb: *mut xcb_connection_t, keymap: &XkbKeymap) -> Option<Self> {
33 let state = unsafe {
34 (XKBXH.xkb_x11_state_new_from_device)(keymap.as_ptr(), xcb, keymap._core_keyboard_id)
35 };
36 let state = NonNull::new(state)?;
37 Some(Self::new_inner(state))
38 }
39
40 fn new_inner(state: NonNull<xkb_state>) -> Self {
41 let modifiers = ModifiersState::default();
42 let mut this = Self { state, modifiers };
43 this.reload_modifiers();
44 this
45 }
46
47 pub fn get_one_sym_raw(&mut self, keycode: xkb_keycode_t) -> xkb_keysym_t {
48 unsafe { (XKBH.xkb_state_key_get_one_sym)(self.state.as_ptr(), keycode) }
49 }
50
51 pub fn layout(&mut self, key: xkb_keycode_t) -> xkb_layout_index_t {
52 unsafe { (XKBH.xkb_state_key_get_layout)(self.state.as_ptr(), key) }
53 }
54
55 #[cfg(x11_platform)]
56 pub fn depressed_modifiers(&mut self) -> xkb::xkb_mod_mask_t {
57 unsafe {
58 (XKBH.xkb_state_serialize_mods)(
59 self.state.as_ptr(),
60 xkb_state_component::XKB_STATE_MODS_DEPRESSED,
61 )
62 }
63 }
64
65 #[cfg(x11_platform)]
66 pub fn latched_modifiers(&mut self) -> xkb::xkb_mod_mask_t {
67 unsafe {
68 (XKBH.xkb_state_serialize_mods)(
69 self.state.as_ptr(),
70 xkb_state_component::XKB_STATE_MODS_LATCHED,
71 )
72 }
73 }
74
75 #[cfg(x11_platform)]
76 pub fn locked_modifiers(&mut self) -> xkb::xkb_mod_mask_t {
77 unsafe {
78 (XKBH.xkb_state_serialize_mods)(
79 self.state.as_ptr(),
80 xkb_state_component::XKB_STATE_MODS_LOCKED,
81 )
82 }
83 }
84
85 pub fn get_utf8_raw(
86 &mut self,
87 keycode: xkb_keycode_t,
88 scratch_buffer: &mut Vec<u8>,
89 ) -> Option<SmolStr> {
90 make_string_with(scratch_buffer, |ptr, len| unsafe {
91 (XKBH.xkb_state_key_get_utf8)(self.state.as_ptr(), keycode, ptr, len)
92 })
93 }
94
95 pub fn modifiers(&self) -> ModifiersState {
96 self.modifiers
97 }
98
99 pub fn update_modifiers(
100 &mut self,
101 mods_depressed: u32,
102 mods_latched: u32,
103 mods_locked: u32,
104 depressed_group: u32,
105 latched_group: u32,
106 locked_group: u32,
107 ) {
108 let mask = unsafe {
109 (XKBH.xkb_state_update_mask)(
110 self.state.as_ptr(),
111 mods_depressed,
112 mods_latched,
113 mods_locked,
114 depressed_group,
115 latched_group,
116 locked_group,
117 )
118 };
119
120 if mask.contains(xkb_state_component::XKB_STATE_MODS_EFFECTIVE) {
121 // Effective value of mods have changed, we need to update our state.
122 self.reload_modifiers();
123 }
124 }
125
126 /// Reload the modifiers.
127 fn reload_modifiers(&mut self) {
128 self.modifiers.ctrl = self.mod_name_is_active(xkb::XKB_MOD_NAME_CTRL);
129 self.modifiers.alt = self.mod_name_is_active(xkb::XKB_MOD_NAME_ALT);
130 self.modifiers.shift = self.mod_name_is_active(xkb::XKB_MOD_NAME_SHIFT);
131 self.modifiers.caps_lock = self.mod_name_is_active(xkb::XKB_MOD_NAME_CAPS);
132 self.modifiers.logo = self.mod_name_is_active(xkb::XKB_MOD_NAME_LOGO);
133 self.modifiers.num_lock = self.mod_name_is_active(xkb::XKB_MOD_NAME_NUM);
134 }
135
136 /// Check if the modifier is active within xkb.
137 fn mod_name_is_active(&mut self, name: &[u8]) -> bool {
138 unsafe {
139 (XKBH.xkb_state_mod_name_is_active)(
140 self.state.as_ptr(),
141 name.as_ptr() as *const c_char,
142 xkb_state_component::XKB_STATE_MODS_EFFECTIVE,
143 ) > 0
144 }
145 }
146}
147
148impl Drop for XkbState {
149 fn drop(&mut self) {
150 unsafe {
151 (XKBH.xkb_state_unref)(self.state.as_ptr());
152 }
153 }
154}
155
156/// Represents the current state of the keyboard modifiers
157///
158/// Each field of this struct represents a modifier and is `true` if this modifier is active.
159///
160/// For some modifiers, this means that the key is currently pressed, others are toggled
161/// (like caps lock).
162#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
163pub struct ModifiersState {
164 /// The "control" key
165 pub ctrl: bool,
166 /// The "alt" key
167 pub alt: bool,
168 /// The "shift" key
169 pub shift: bool,
170 /// The "Caps lock" key
171 pub caps_lock: bool,
172 /// The "logo" key
173 ///
174 /// Also known as the "windows" key on most keyboards
175 pub logo: bool,
176 /// The "Num lock" key
177 pub num_lock: bool,
178}
179
180impl From<ModifiersState> for crate::keyboard::ModifiersState {
181 fn from(mods: ModifiersState) -> crate::keyboard::ModifiersState {
182 let mut to_mods: ModifiersState = crate::keyboard::ModifiersState::empty();
183 to_mods.set(other:crate::keyboard::ModifiersState::SHIFT, value:mods.shift);
184 to_mods.set(other:crate::keyboard::ModifiersState::CONTROL, value:mods.ctrl);
185 to_mods.set(other:crate::keyboard::ModifiersState::ALT, value:mods.alt);
186 to_mods.set(other:crate::keyboard::ModifiersState::SUPER, value:mods.logo);
187 to_mods
188 }
189}
190