1#![allow(dead_code, non_camel_case_types)]
2#![cfg_attr(rustfmt, rustfmt_skip)]
3
4extern crate dlib;
5extern crate bitflags;
6extern crate xkeysym;
7
8#[doc(inline)]
9pub use xkeysym::key as keysyms;
10
11use std::os::raw::{c_char, c_int, c_uint, c_void};
12
13use bitflags::bitflags;
14use dlib::dlopen_external_library;
15use log::info;
16use once_cell::sync::OnceCell;
17
18#[cfg(feature = "x11")]
19pub mod x11;
20
21pub const XKB_MOD_NAME_SHIFT: &[u8] = b"Shift\0";
22pub const XKB_MOD_NAME_CAPS: &[u8] = b"Lock\0";
23pub const XKB_MOD_NAME_CTRL: &[u8] = b"Control\0";
24pub const XKB_MOD_NAME_ALT: &[u8] = b"Mod1\0";
25pub const XKB_MOD_NAME_NUM: &[u8] = b"Mod2\0";
26pub const XKB_MOD_NAME_LOGO: &[u8] = b"Mod4\0";
27
28pub const XKB_LED_NAME_CAPS: &[u8] = b"Caps Lock\0";
29pub const XKB_LED_NAME_NUM: &[u8] = b"Num Lock\0";
30pub const XKB_LED_NAME_SCROLL: &[u8] = b"Scroll Lock\0";
31
32pub struct xkb_context;
33pub struct xkb_keymap;
34pub struct xkb_state;
35pub struct xkb_compose_table;
36pub struct xkb_compose_state;
37
38pub type xkb_keycode_t = u32;
39pub type xkb_keysym_t = u32;
40pub type xkb_layout_index_t = u32;
41pub type xkb_layout_mask_t = u32;
42pub type xkb_level_index_t = u32;
43pub type xkb_mod_index_t = u32;
44pub type xkb_mod_mask_t = u32;
45pub type xkb_led_index_t = u32;
46pub type xkb_led_mask_t = u32;
47pub type xkb_keymap_key_iter_t = Option<extern "C" fn(*mut xkb_keymap, xkb_keycode_t, *mut c_void)>;
48
49pub const XKB_KEYCODE_INVALID: u32 = 0xffffffff;
50pub const XKB_LAYOUT_INVALID: u32 = 0xffffffff;
51pub const XKB_LEVEL_INVALID: u32 = 0xffffffff;
52pub const XKB_MOD_INVALID: u32 = 0xffffffff;
53pub const XKB_LED_INVALID: u32 = 0xffffffff;
54pub const XKB_KEYCODE_MAX: u32 = 0xffffffff - 1;
55
56#[repr(C)]
57pub 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)]
67pub 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)]
76pub 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)]
87pub 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)]
102pub 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)]
109pub 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)]
118pub 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)]
127pub enum xkb_compose_compile_flags {
128 XKB_COMPOSE_COMPILE_NO_FLAGS = 0,
129}
130
131#[repr(C)]
132#[derive(Copy, Clone, Debug, PartialEq)]
133pub enum xkb_compose_format {
134 XKB_COMPOSE_FORMAT_TEXT_V1 = 1,
135}
136
137#[repr(C)]
138#[derive(Copy, Clone, Debug, PartialEq)]
139pub enum xkb_compose_state_flags {
140 XKB_COMPOSE_STATE_NO_FLAGS = 0,
141}
142
143#[repr(C)]
144#[derive(Copy, Clone, Debug, PartialEq)]
145pub 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)]
154pub enum xkb_compose_feed_result {
155 XKB_COMPOSE_FEED_IGNORED,
156 XKB_COMPOSE_FEED_ACCEPTED,
157}
158
159bitflags!(
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
188dlopen_external_library!(XkbCommon,
189functions:
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
284dlopen_external_library!(XkbCommonCompose,
285functions:
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
304pub fn xkbcommon_handle() -> &'static XkbCommon {
305 xkbcommon_option().expect(msg:"Library libxkbcommon.so could not be loaded.")
306}
307
308pub 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
321pub fn xkbcommon_compose_handle() -> &'static XkbCommonCompose {
322 xkbcommon_compose_option().expect(msg:"Could not load compose module from libxkbcommon.so.")
323}
324
325pub 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
338fn open_with_sonames<T, F>(names: &[&str], module: Option<&str>, open: F) -> Option<T>
339where
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