| 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 | |