1 | #![allow (dead_code, non_camel_case_types)] |
2 | #![cfg_attr (rustfmt, rustfmt_skip)] |
3 | |
4 | extern crate dlib; |
5 | extern crate bitflags; |
6 | extern crate xkeysym; |
7 | |
8 | #[doc (inline)] |
9 | pub use xkeysym::key as keysyms; |
10 | |
11 | use std::os::raw::{c_char, c_int, c_uint, c_void}; |
12 | |
13 | use bitflags::bitflags; |
14 | use dlib::dlopen_external_library; |
15 | use log::info; |
16 | use once_cell::sync::OnceCell; |
17 | |
18 | #[cfg (feature = "x11" )] |
19 | pub mod x11; |
20 | |
21 | pub const XKB_MOD_NAME_SHIFT: &[u8] = b"Shift \0" ; |
22 | pub const XKB_MOD_NAME_CAPS: &[u8] = b"Lock \0" ; |
23 | pub const XKB_MOD_NAME_CTRL: &[u8] = b"Control \0" ; |
24 | pub const XKB_MOD_NAME_ALT: &[u8] = b"Mod1 \0" ; |
25 | pub const XKB_MOD_NAME_NUM: &[u8] = b"Mod2 \0" ; |
26 | pub const XKB_MOD_NAME_LOGO: &[u8] = b"Mod4 \0" ; |
27 | |
28 | pub const XKB_LED_NAME_CAPS: &[u8] = b"Caps Lock \0" ; |
29 | pub const XKB_LED_NAME_NUM: &[u8] = b"Num Lock \0" ; |
30 | pub const XKB_LED_NAME_SCROLL: &[u8] = b"Scroll Lock \0" ; |
31 | |
32 | pub struct xkb_context; |
33 | pub struct xkb_keymap; |
34 | pub struct xkb_state; |
35 | pub struct xkb_compose_table; |
36 | pub struct xkb_compose_state; |
37 | |
38 | pub type xkb_keycode_t = u32; |
39 | pub type xkb_keysym_t = u32; |
40 | pub type xkb_layout_index_t = u32; |
41 | pub type xkb_layout_mask_t = u32; |
42 | pub type xkb_level_index_t = u32; |
43 | pub type xkb_mod_index_t = u32; |
44 | pub type xkb_mod_mask_t = u32; |
45 | pub type xkb_led_index_t = u32; |
46 | pub type xkb_led_mask_t = u32; |
47 | pub type xkb_keymap_key_iter_t = Option<extern "C" fn(*mut xkb_keymap, xkb_keycode_t, *mut c_void)>; |
48 | |
49 | pub const XKB_KEYCODE_INVALID: u32 = 0xffffffff; |
50 | pub const XKB_LAYOUT_INVALID: u32 = 0xffffffff; |
51 | pub const XKB_LEVEL_INVALID: u32 = 0xffffffff; |
52 | pub const XKB_MOD_INVALID: u32 = 0xffffffff; |
53 | pub const XKB_LED_INVALID: u32 = 0xffffffff; |
54 | pub const XKB_KEYCODE_MAX: u32 = 0xffffffff - 1; |
55 | |
56 | #[repr (C)] |
57 | pub struct xkb_rule_names { |
58 | pub rules: *const c_char, |
59 | pub model: *const c_char, |
60 | pub layout: *const c_char, |
61 | pub variant: *const c_char, |
62 | pub options: *const c_char, |
63 | } |
64 | |
65 | #[repr (C)] |
66 | #[derive (Copy, Clone, Debug, PartialEq)] |
67 | pub enum xkb_keysym_flags { |
68 | /// Do not apply any flags. |
69 | XKB_KEYSYM_NO_FLAGS = 0, |
70 | /// Find keysym by case-insensitive search. |
71 | XKB_KEYSYM_CASE_INSENSITIVE = (1 << 0), |
72 | } |
73 | |
74 | #[repr (C)] |
75 | #[derive (Copy, Clone, Debug, PartialEq)] |
76 | pub enum xkb_context_flags { |
77 | /// Do not apply any context flags. |
78 | XKB_CONTEXT_NO_FLAGS = 0, |
79 | /// Create this context with an empty include path. |
80 | XKB_CONTEXT_NO_DEFAULT_INCLUDES = (1 << 0), |
81 | /// Don't take RMLVO names from the environment. |
82 | XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 << 1), |
83 | } |
84 | |
85 | #[repr (C)] |
86 | #[derive (Copy, Clone, Debug, PartialEq)] |
87 | pub enum xkb_log_level { |
88 | /// Log critical internal errors only. |
89 | XKB_LOG_LEVEL_CRITICAL = 10, |
90 | /// Log all errors. */ |
91 | XKB_LOG_LEVEL_ERROR = 20, |
92 | /// Log warnings and errors. |
93 | XKB_LOG_LEVEL_WARNING = 30, |
94 | /// Log information, warnings, and errors. |
95 | XKB_LOG_LEVEL_INFO = 40, |
96 | /// Log everything. |
97 | XKB_LOG_LEVEL_DEBUG = 50, |
98 | } |
99 | |
100 | #[repr (C)] |
101 | #[derive (Copy, Clone, Debug, PartialEq)] |
102 | pub enum xkb_keymap_compile_flags { |
103 | /// Do not apply any flags. |
104 | XKB_KEYMAP_COMPILE_NO_FLAGS = 0, |
105 | } |
106 | |
107 | #[repr (C)] |
108 | #[derive (Copy, Clone, Debug, PartialEq)] |
109 | pub enum xkb_keymap_format { |
110 | /// Cannot be used for creation. |
111 | XKB_KEYMAP_USE_ORIGINAL_FORMAT = 0, |
112 | /// The current/classic XKB text format, as generated by xkbcomp -xkb. |
113 | XKB_KEYMAP_FORMAT_TEXT_V1 = 1, |
114 | } |
115 | |
116 | #[repr (C)] |
117 | #[derive (Copy, Clone, Debug, PartialEq)] |
118 | pub enum xkb_key_direction { |
119 | /// The key was released. |
120 | XKB_KEY_UP, |
121 | /// The key was pressed. |
122 | XKB_KEY_DOWN, |
123 | } |
124 | |
125 | #[repr (C)] |
126 | #[derive (Copy, Clone, Debug, PartialEq)] |
127 | pub enum xkb_compose_compile_flags { |
128 | XKB_COMPOSE_COMPILE_NO_FLAGS = 0, |
129 | } |
130 | |
131 | #[repr (C)] |
132 | #[derive (Copy, Clone, Debug, PartialEq)] |
133 | pub enum xkb_compose_format { |
134 | XKB_COMPOSE_FORMAT_TEXT_V1 = 1, |
135 | } |
136 | |
137 | #[repr (C)] |
138 | #[derive (Copy, Clone, Debug, PartialEq)] |
139 | pub enum xkb_compose_state_flags { |
140 | XKB_COMPOSE_STATE_NO_FLAGS = 0, |
141 | } |
142 | |
143 | #[repr (C)] |
144 | #[derive (Copy, Clone, Debug, PartialEq)] |
145 | pub enum xkb_compose_status { |
146 | XKB_COMPOSE_NOTHING, |
147 | XKB_COMPOSE_COMPOSING, |
148 | XKB_COMPOSE_COMPOSED, |
149 | XKB_COMPOSE_CANCELLED, |
150 | } |
151 | |
152 | #[repr (C)] |
153 | #[derive (Copy, Clone, Debug, PartialEq)] |
154 | pub enum xkb_compose_feed_result { |
155 | XKB_COMPOSE_FEED_IGNORED, |
156 | XKB_COMPOSE_FEED_ACCEPTED, |
157 | } |
158 | |
159 | bitflags!( |
160 | pub struct xkb_state_component: u32 { |
161 | /// Depressed modifiers, i.e. a key is physically holding them. |
162 | const XKB_STATE_MODS_DEPRESSED = (1 << 0); |
163 | /// Latched modifiers, i.e. will be unset after the next non-modifier key press. |
164 | const XKB_STATE_MODS_LATCHED = (1 << 1); |
165 | /// Locked modifiers, i.e. will be unset after the key provoking the lock has been |
166 | /// pressed again. |
167 | const XKB_STATE_MODS_LOCKED = (1 << 2); |
168 | /// Effective modifiers, i.e. currently active and affect key processing |
169 | /// (derived from the other state components). |
170 | /// Use this unless you explictly care how the state came about. |
171 | const XKB_STATE_MODS_EFFECTIVE = (1 << 3); |
172 | /// Depressed layout, i.e. a key is physically holding it. |
173 | const XKB_STATE_LAYOUT_DEPRESSED = (1 << 4); |
174 | /// Latched layout, i.e. will be unset after the next non-modifier key press. |
175 | const XKB_STATE_LAYOUT_LATCHED = (1 << 5); |
176 | /// Locked layout, i.e. will be unset after the key provoking the lock has been pressed |
177 | /// again. |
178 | const XKB_STATE_LAYOUT_LOCKED = (1 << 6); |
179 | /// Effective layout, i.e. currently active and affects key processing |
180 | /// (derived from the other state components). |
181 | /// Use this unless you explictly care how the state came about. |
182 | const XKB_STATE_LAYOUT_EFFECTIVE = (1 << 7); |
183 | /// LEDs (derived from the other state components). |
184 | const XKB_STATE_LEDS = (1 << 8); |
185 | } |
186 | ); |
187 | |
188 | dlopen_external_library!(XkbCommon, |
189 | functions: |
190 | fn xkb_keysym_get_name(xkb_keysym_t, *mut c_char, usize) -> c_int, |
191 | fn xkb_keysym_from_name(*const c_char, xkb_keysym_flags) -> xkb_keysym_t, |
192 | fn xkb_keysym_to_utf8(xkb_keysym_t, *mut c_char, usize) -> c_int, |
193 | fn xkb_keysym_to_utf32(xkb_keysym_t) -> u32, |
194 | |
195 | fn xkb_context_new(xkb_context_flags) -> *mut xkb_context, |
196 | fn xkb_context_ref(*mut xkb_context) -> *mut xkb_context, |
197 | fn xkb_context_unref(*mut xkb_context) -> (), |
198 | fn xkb_context_set_user_data(*mut xkb_context, *mut c_void) -> (), |
199 | fn xkb_context_get_user_data(*mut xkb_context) -> *mut c_void, |
200 | fn xkb_context_include_path_append(*mut xkb_context, *const c_char) -> c_int, |
201 | fn xkb_context_include_path_append_default(*mut xkb_context) -> c_int, |
202 | fn xkb_context_include_path_reset_defaults(*mut xkb_context) -> c_int, |
203 | fn xkb_context_include_path_clear(*mut xkb_context) -> (), |
204 | fn xkb_context_num_include_paths(*mut xkb_context) -> c_uint, |
205 | fn xkb_context_include_path_get(*mut xkb_context, c_uint) -> *const c_char, |
206 | fn xkb_context_set_log_level(*mut xkb_context, xkb_log_level) -> (), |
207 | fn xkb_context_get_log_level(*mut xkb_context) -> xkb_log_level, |
208 | fn xkb_context_set_log_verbosity(*mut xkb_context, c_int) -> (), |
209 | fn xkb_context_get_log_verbosity(*mut xkb_context) -> c_int, |
210 | |
211 | fn xkb_keymap_new_from_names( |
212 | *mut xkb_context, |
213 | *const xkb_rule_names, |
214 | xkb_keymap_compile_flags |
215 | ) -> *mut xkb_keymap, |
216 | fn xkb_keymap_new_from_string( |
217 | *mut xkb_context, |
218 | *const c_char, |
219 | xkb_keymap_format, |
220 | xkb_keymap_compile_flags |
221 | ) -> *mut xkb_keymap, |
222 | fn xkb_keymap_new_from_buffer( |
223 | *mut xkb_context, |
224 | *const c_char, |
225 | usize, |
226 | xkb_keymap_format, |
227 | xkb_keymap_compile_flags |
228 | ) -> *mut xkb_keymap, |
229 | fn xkb_keymap_ref(*mut xkb_keymap) -> *mut xkb_keymap, |
230 | fn xkb_keymap_unref(*mut xkb_keymap) -> (), |
231 | fn xkb_keymap_get_as_string(*mut xkb_keymap, xkb_keymap_format) -> *const c_char, |
232 | fn xkb_keymap_key_get_syms_by_level(*mut xkb_keymap, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, *mut *const xkb_keysym_t) -> c_int, |
233 | fn xkb_keymap_key_repeats(*mut xkb_keymap, xkb_keycode_t) -> c_int, |
234 | |
235 | fn xkb_keymap_min_keycode(*mut xkb_keymap) -> xkb_keycode_t, |
236 | fn xkb_keymap_max_keycode(*mut xkb_keymap) -> xkb_keycode_t, |
237 | fn xkb_keymap_key_for_each(*mut xkb_keymap, xkb_keymap_key_iter_t, *mut c_void) -> (), |
238 | fn xkb_keymap_num_layouts(*mut xkb_keymap) -> xkb_layout_index_t, |
239 | fn xkb_keymap_num_layouts_for_key(*mut xkb_keymap, xkb_keycode_t) -> xkb_layout_index_t, |
240 | fn xkb_keymap_num_levels_for_key(*mut xkb_keymap, xkb_keycode_t, xkb_layout_index_t) -> xkb_level_index_t, |
241 | |
242 | fn xkb_keymap_mod_get_name(*mut xkb_keymap, xkb_mod_index_t) -> *const c_char, |
243 | fn xkb_keymap_mod_get_index(*mut xkb_keymap, *const c_char) -> xkb_mod_index_t, |
244 | |
245 | fn xkb_state_new(*mut xkb_keymap) -> *mut xkb_state, |
246 | fn xkb_state_ref(*mut xkb_state) -> *mut xkb_state, |
247 | fn xkb_state_unref(*mut xkb_state) -> (), |
248 | fn xkb_state_update_mask( |
249 | *mut xkb_state, |
250 | xkb_mod_mask_t, |
251 | xkb_mod_mask_t, |
252 | xkb_mod_mask_t, |
253 | xkb_layout_index_t, |
254 | xkb_layout_index_t, |
255 | xkb_layout_index_t |
256 | ) -> xkb_state_component, |
257 | fn xkb_state_update_key( |
258 | *mut xkb_state, |
259 | xkb_keycode_t, |
260 | xkb_key_direction |
261 | ) -> xkb_state_component, |
262 | fn xkb_state_key_get_syms( |
263 | *mut xkb_state, |
264 | xkb_keycode_t, |
265 | *const *mut xkb_keysym_t |
266 | ) -> c_int, |
267 | fn xkb_state_key_get_utf8( |
268 | *mut xkb_state, |
269 | xkb_keycode_t, |
270 | *mut c_char, |
271 | usize |
272 | ) -> c_int, |
273 | fn xkb_state_key_get_utf32(*mut xkb_state, xkb_keycode_t) -> u32, |
274 | fn xkb_state_key_get_one_sym(*mut xkb_state, xkb_keycode_t) -> xkb_keysym_t, |
275 | fn xkb_state_key_get_layout(*mut xkb_state, xkb_keycode_t) -> xkb_layout_index_t, |
276 | fn xkb_state_key_get_level(*mut xkb_state, xkb_keycode_t, xkb_layout_index_t) -> xkb_level_index_t, |
277 | fn xkb_state_mod_name_is_active(*mut xkb_state, *const c_char, xkb_state_component) -> c_int, |
278 | fn xkb_state_mod_index_is_active(*mut xkb_state, xkb_mod_index_t, xkb_state_component) -> c_int, |
279 | fn xkb_state_serialize_mods(*mut xkb_state, xkb_state_component) -> xkb_mod_mask_t, |
280 | fn xkb_state_serialize_layout(*mut xkb_state, xkb_state_component) -> xkb_layout_index_t, |
281 | ); |
282 | |
283 | // Compose and dead-keys support module |
284 | dlopen_external_library!(XkbCommonCompose, |
285 | functions: |
286 | fn xkb_compose_table_new_from_locale( |
287 | *mut xkb_context, |
288 | *const c_char, |
289 | xkb_compose_compile_flags |
290 | ) -> *mut xkb_compose_table, |
291 | fn xkb_compose_table_unref(*mut xkb_compose_table) -> (), |
292 | fn xkb_compose_state_new( |
293 | *mut xkb_compose_table, |
294 | xkb_compose_state_flags |
295 | ) -> *mut xkb_compose_state, |
296 | fn xkb_compose_state_unref(*mut xkb_compose_state) -> (), |
297 | fn xkb_compose_state_feed(*mut xkb_compose_state, xkb_keysym_t) -> xkb_compose_feed_result, |
298 | fn xkb_compose_state_reset(*mut xkb_compose_state) -> (), |
299 | fn xkb_compose_state_get_status(*mut xkb_compose_state) -> xkb_compose_status, |
300 | fn xkb_compose_state_get_utf8(*mut xkb_compose_state, *mut c_char, usize) -> c_int, |
301 | fn xkb_compose_state_get_one_sym(*mut xkb_compose_state) -> xkb_keysym_t, |
302 | ); |
303 | |
304 | pub fn xkbcommon_handle() -> &'static XkbCommon { |
305 | xkbcommon_option().expect(msg:"Library libxkbcommon.so could not be loaded." ) |
306 | } |
307 | |
308 | pub fn xkbcommon_option() -> Option<&'static XkbCommon> { |
309 | static XKBCOMMON_OPTION: OnceCell<Option<XkbCommon>> = OnceCell::new(); |
310 | XKBCOMMON_OPTION&Option |
311 | .get_or_init(|| { |
312 | open_with_sonames( |
313 | &["libxkbcommon.so.0" , "libxkbcommon.so" ], |
314 | module:None, |
315 | |name: &str| unsafe { XkbCommon::open(name) }, |
316 | ) |
317 | }) |
318 | .as_ref() |
319 | } |
320 | |
321 | pub fn xkbcommon_compose_handle() -> &'static XkbCommonCompose { |
322 | xkbcommon_compose_option().expect(msg:"Could not load compose module from libxkbcommon.so." ) |
323 | } |
324 | |
325 | pub fn xkbcommon_compose_option() -> Option<&'static XkbCommonCompose> { |
326 | static XKBCOMMON_COMPOSE_OPTION: OnceCell<Option<XkbCommonCompose>> = OnceCell::new(); |
327 | XKBCOMMON_COMPOSE_OPTION&Option |
328 | .get_or_init(|| { |
329 | open_with_sonames( |
330 | &["libxkbcommon.so.0" , "libxkbcommon.so" ], |
331 | module:Some("compose" ), |
332 | |name: &str| unsafe { XkbCommonCompose::open(name) }, |
333 | ) |
334 | }) |
335 | .as_ref() |
336 | } |
337 | |
338 | fn open_with_sonames<T, F>(names: &[&str], module: Option<&str>, open: F) -> Option<T> |
339 | where |
340 | F: Fn(&str) -> Result<T, dlib::DlError>, |
341 | { |
342 | for name: &&str in names { |
343 | match open(name) { |
344 | Ok(l: T) => return Some(l), |
345 | Err(e: DlError) => { |
346 | if let Some(module: &str) = module { |
347 | info!( |
348 | "Failed loading {} module from ` {}`. Error: {:?}" , |
349 | module, name, e |
350 | ) |
351 | } else { |
352 | info!("Failed loading ` {}`. Error: {:?}" , name, e) |
353 | } |
354 | } |
355 | } |
356 | } |
357 | None |
358 | } |
359 | |