xkbcommon/xkb/
mod.rs

1#![warn(clippy::all)]
2#![allow(
3    clippy::similar_names,
4    clippy::wildcard_imports,
5    clippy::cast_sign_loss,
6    clippy::too_many_arguments
7)]
8pub mod compose;
9pub mod ffi;
10pub mod keysyms;
11
12#[cfg(feature = "x11")]
13pub mod x11;
14
15pub use self::compose::*;
16use crate::xkb::ffi::*;
17
18#[cfg(feature = "wayland")]
19use memmap2::MmapOptions;
20#[cfg(feature = "wayland")]
21use std::os::unix::io::OwnedFd;
22
23use libc::{self, c_char, c_int, c_uint};
24use std::borrow::Borrow;
25use std::ffi::{CStr, CString};
26use std::fs;
27use std::io::Read;
28use std::iter::Iterator;
29use std::mem;
30use std::os::raw;
31use std::path::Path;
32use std::ptr::{null, null_mut};
33use std::slice;
34use std::str;
35
36/// A number used to represent a physical key on a keyboard.
37///
38/// A standard PC-compatible keyboard might have 102 keys. An appropriate
39/// keymap would assign each of them a keycode, by which the user should
40/// refer to the key throughout the library.
41///
42/// Historically, the X11 protocol, and consequentially the XKB protocol,
43/// assign only 8 bits for keycodes. This limits the number of different
44/// keys that can be used simultaneously in a single keymap to 256
45/// (disregarding other limitations). This library does not share this limit;
46/// keycodes beyond 255 ('extended keycodes') are not treated specially.
47/// Keymaps and applications which are compatible with X11 should not use
48/// these keycodes.
49///
50/// The values of specific keycodes are determined by the keymap and the
51/// underlying input system. For example, with an X11-compatible keymap
52/// and Linux evdev scan codes (see linux/input.h), a fixed offset is used:
53///
54/// ```no_run
55/// # use xkbcommon::xkb::keysyms::KEY_A;
56/// # use xkbcommon::xkb::Keycode;
57/// let keycode_A: Keycode = Keycode::new(KEY_A as u32 + 8);
58/// ```
59///
60/// See `xkb::keycode_is_legal_ext()` and `xkb::keycode_is_legal_x11()`
61pub use xkeysym::KeyCode as Keycode;
62
63/// A number used to represent the symbols generated from a key on a keyboard.
64///
65/// A key, represented by a keycode, may generate different symbols according
66/// to keyboard state. For example, on a QWERTY keyboard, pressing the key
67/// labled \<A\> generates the symbol 'a'. If the Shift key is held, it
68/// generates the symbol 'A'. If a different layout is used, say Greek,
69/// it generates the symbol 'α'. And so on.
70///
71/// Each such symbol is represented by a keysym. Note that keysyms are
72/// somewhat more general, in that they can also represent some "function",
73/// such as "Left" or "Right" for the arrow keys. For more information,
74/// see:
75/// <http://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#keysym_encoding>
76///
77/// Specifically named keysyms can be found in the
78/// xkbcommon/xkbcommon-keysyms.h header file. Their name does not include
79/// the `xkb::KEY_` prefix.
80///
81/// Besides those, any Unicode/ISO 10646 character in the range U0100 to
82/// U10FFFF can be represented by a keysym value in the range 0x01000100 to
83/// 0x0110FFFF. The name of Unicode keysyms is "`U<codepoint>`", e.g. "UA1B2".
84///
85/// The name of other unnamed keysyms is the hexadecimal representation of
86/// their value, e.g. "0xabcd1234".
87///
88/// Keysym names are case-sensitive.
89pub use xkeysym::Keysym;
90
91/// Index of a keyboard layout.
92///
93/// The layout index is a state component which detemines which _keyboard
94/// layout_ active. These may be different alphabets, different key
95/// arrangements, etc.
96///
97/// Layout indices are consecutive. The first layout has index 0.
98///
99/// Each layout is not required to have a name, and the names are not
100/// guaranteed to be unique (though they are usually provided and unique).
101/// Therefore, it is not safe to use the name as a unique identifier for a
102/// layout. Layout names are case-sensitive.
103///
104/// Layouts are also called "groups" by XKB.
105pub type LayoutIndex = u32;
106/// A mask of layout indices
107pub type LayoutMask = u32;
108
109/// Index of a shift level.
110///
111/// Any key, in any layout, can have several _shift levels_  Each
112/// shift level can assign different keysyms to the key. The shift level
113/// to use is chosen according to the current keyboard state; for example,
114/// if no keys are pressed, the first level may be used; if the Left Shift
115/// key is pressed, the second; if Num Lock is pressed, the third; and
116/// many such combinations are possible (see `ModIndex`).
117///
118/// Level indices are consecutive. The first level has index 0.
119pub type LevelIndex = u32;
120
121/// Index of a modifier.
122///
123/// A modifier is a state component which changes the way keys are
124/// interpreted. A keymap defines a set of modifiers, such as Alt, Shift,
125/// Num Lock or Meta, and specifies which keys may activate which
126/// modifiers (in a many-to-many relationship, i.e. a key can activate
127/// several modifiers, and a modifier may be activated by several keys.
128/// Different keymaps do this differently).
129///
130/// When retrieving the keysyms for a key, the active modifier set is
131/// consulted; this detemines the correct shift level to use within the
132/// currently active layout (see `LevelIndex`).
133///
134/// Modifier indices are consecutive. The first modifier has index 0.
135///
136/// Each modifier must have a name, and the names are unique. Therefore, it
137/// is safe to use the name as a unique identifier for a modifier.
138/// Modifier names are case-sensitive.
139pub type ModIndex = u32;
140/// A mask of modifier indices.
141pub type ModMask = u32;
142
143/// Index of a keyboard LED.
144///
145/// LEDs are logical objects which may be  active or  inactive. They
146/// typically correspond to the lights on the keyboard. Their state is
147/// determined by the current keyboard state.
148///
149/// LED indices are non-consecutive. The first LED has index 0.
150///
151/// Each LED must have a name, and the names are unique. Therefore,
152/// it is safe to use the name as a unique identifier for a LED. The names
153/// of some common LEDs are provided in the xkbcommon/xkbcommon-names.h
154/// header file. LED names are case-sensitive.
155///
156/// # Warning
157///
158/// A given keymap may specify an exact index for a given LED.
159/// Therefore, LED indexing is not necessarily sequential, as opposed to
160/// modifiers and layouts. This means that when iterating over the LEDs
161/// in a keymap using e.g. `xkb_keymap_num_leds()`, some indices might be
162/// invalid. Given such an index, functions like `xkb_keymap_led_get_name()`
163/// will return `NULL`, and `xkb_state_led_index_is_active()` will return -1.
164///
165/// LEDs are also called "indicators" by XKB.
166pub type LedIndex = u32;
167/// A mask of LED indices.
168pub type LedMask = u32;
169
170pub const KEYCODE_INVALID: u32 = 0xffff_ffff;
171pub const LAYOUT_INVALID: u32 = 0xffff_ffff;
172pub const LEVEL_INVALID: u32 = 0xffff_ffff;
173pub const MOD_INVALID: u32 = 0xffff_ffff;
174pub const LED_INVALID: u32 = 0xffff_ffff;
175
176pub const KEYCODE_MAX: u32 = 0xffff_fffe;
177
178pub type KeysymFlags = u32;
179pub const KEYSYM_NO_FLAGS: u32 = 0;
180pub const KEYSYM_CASE_INSENSITIVE: u32 = 1 << 0;
181
182/// Flags for context creation.
183pub type ContextFlags = u32;
184/// Do not apply any context flags.
185pub const CONTEXT_NO_FLAGS: u32 = 0;
186/// Create this context with an empty include path.
187pub const CONTEXT_NO_DEFAULT_INCLUDES: u32 = 1 << 0;
188/// Don't take RMLVO names from the environment.
189pub const CONTEXT_NO_ENVIRONMENT_NAMES: u32 = 1 << 1;
190
191#[repr(C)]
192pub enum LogLevel {
193    Critical = 10,
194    Error = 20,
195    Warning = 30,
196    Info = 40,
197    Debug = 50,
198}
199
200/// Flags for keymap compilation.
201pub type KeymapCompileFlags = u32;
202/// Do not apply any flags.
203pub const KEYMAP_COMPILE_NO_FLAGS: u32 = 0;
204
205/// The possible keymap formats.
206pub type KeymapFormat = u32;
207/// The current/classic XKB text format, as generated by xkbcomp -xkb.
208pub const KEYMAP_FORMAT_TEXT_V1: u32 = 1;
209/// Get the keymap as a string in the format from which it was created.
210pub const KEYMAP_FORMAT_USE_ORIGINAL: u32 = 0xffff_ffff;
211
212/// Specifies the direction of the key (press / release).
213#[repr(C)]
214pub enum KeyDirection {
215    /// the key was released
216    Up,
217    /// the key was pressed
218    Down,
219}
220
221/// Modifier and layout types for state objects. This enum is bitmaskable,
222/// e.g. `(xkb::STATE_MODS_DEPRESSED | xkb::STATE_MODS_LATCHED)` is valid to
223/// exclude locked modifiers.
224///
225/// In XKB, the DEPRESSED components are also known as 'base'.
226pub type StateComponent = u32;
227/// Depressed modifiers, i.e. a key is physically holding them.
228pub const STATE_MODS_DEPRESSED: u32 = 1 << 0;
229/// Latched modifiers, i.e. will be unset after the next non-modifier
230///  key press.
231pub const STATE_MODS_LATCHED: u32 = 1 << 1;
232/// Locked modifiers, i.e. will be unset after the key provoking the
233///  lock has been pressed again.
234pub const STATE_MODS_LOCKED: u32 = 1 << 2;
235/// Effective modifiers, i.e. currently active and affect key
236///  processing (derived from the other state components).
237///  Use this unless you explictly care how the state came about.
238pub const STATE_MODS_EFFECTIVE: u32 = 1 << 3;
239/// Depressed layout, i.e. a key is physically holding it.
240pub const STATE_LAYOUT_DEPRESSED: u32 = 1 << 4;
241/// Latched layout, i.e. will be unset after the next non-modifier
242///  key press.
243pub const STATE_LAYOUT_LATCHED: u32 = 1 << 5;
244/// Locked layout, i.e. will be unset after the key provoking the lock
245///  has been pressed again.
246pub const STATE_LAYOUT_LOCKED: u32 = 1 << 6;
247/// Effective layout, i.e. currently active and affects key processing
248///  (derived from the other state components).
249///  Use this unless you explictly care how the state came about.
250pub const STATE_LAYOUT_EFFECTIVE: u32 = 1 << 7;
251/// LEDs (derived from the other state components).
252pub const STATE_LEDS: u32 = 1 << 8;
253
254/// Match flags for `xkb_state_mod_indices_are_active` and
255/// `xkb_state_mod_names_are_active`, specifying how the conditions for a
256/// successful match. `xkb::STATE_MATCH_NON_EXCLUSIVE` is bitmaskable with
257/// the other modes.
258pub type StateMatch = u32;
259///Returns true if any of the modifiers are active.
260pub const STATE_MATCH_ANY: u32 = 1 << 0;
261///Returns true if all of the modifiers are active.
262pub const STATE_MATCH_ALL: u32 = 1 << 1;
263/// Makes matching non-exclusive, i.e. will not return false if a
264///  modifier not specified in the arguments is active.
265pub const STATE_MATCH_NON_EXCLUSIVE: u32 = 1 << 16;
266
267pub const MOD_NAME_SHIFT: &str = "Shift";
268pub const MOD_NAME_CAPS: &str = "Lock";
269pub const MOD_NAME_CTRL: &str = "Control";
270pub const MOD_NAME_ALT: &str = "Mod1";
271pub const MOD_NAME_NUM: &str = "Mod2";
272pub const MOD_NAME_MOD3: &str = "Mod3";
273pub const MOD_NAME_LOGO: &str = "Mod4";
274pub const MOD_NAME_ISO_LEVEL3_SHIFT: &str = "Mod5";
275pub const LED_NAME_CAPS: &str = "Caps Lock";
276pub const LED_NAME_NUM: &str = "Num Lock";
277pub const LED_NAME_SCROLL: &str = "Scroll Lock";
278
279/// Test whether a value is a valid extended keycode.
280/// See `xkb_keycode_t`.
281#[must_use]
282pub fn keycode_is_legal_ext(key: u32) -> bool {
283    key <= KEYCODE_MAX
284}
285
286/// Names to compile a keymap with, also known as RMLVO.
287///
288/// The names are the common configuration values by which a user picks
289/// a keymap.
290///
291/// If the entire struct is NULL, then each field is taken to be NULL.
292/// You should prefer passing NULL instead of choosing your own defaults.
293#[must_use]
294pub fn keycode_is_legal_x11(key: u32) -> bool {
295    (8..=255).contains(&key)
296}
297
298/// Get the name of a keysym.
299#[must_use]
300pub fn keysym_get_name(keysym: Keysym) -> String {
301    unsafe {
302        const BUF_LEN: usize = 64;
303        let buf: &mut [c_char] = &mut [0; BUF_LEN];
304        let ptr = &mut buf[0] as *mut c_char;
305        let len = xkb_keysym_get_name(keysym.raw(), ptr, BUF_LEN);
306        if len <= 0 {
307            return String::new();
308        }
309        let slice: &[u8] = slice::from_raw_parts(ptr as *const _, (len as usize).min(BUF_LEN));
310        String::from_utf8_unchecked(slice.to_owned())
311    }
312}
313
314/// Get a keysym from its name.
315///
316///  name The name of a keysym. See remarks in `xkb_keysym_get_name()`;
317/// this function will accept any name returned by that function.
318///  flags A set of flags controlling how the search is done. If
319/// invalid flags are passed, this will fail with `xkb::KEY_NoSymbol`.
320///
321/// If you use the `xkb::KEYSYM_CASE_INSENSITIVE` flag and two keysym names
322/// differ only by case, then the lower-case keysym is returned. For
323/// instance, for `KEY_a` and `KEY_A`, this function would return `KEY_a` for
324/// the case-insensitive search. If this functionality is needed, it is
325/// recommended to first call this function without this flag; and if that
326/// fails, only then to try with this flag, while possibly warning the user
327/// he had misspelled the name, and might get wrong results.
328///
329/// Returns The keysym. If the name is invalid, returns `xkb::KEY_NoSymbol`.
330#[allow(clippy::missing_panics_doc)]
331#[must_use]
332pub fn keysym_from_name(name: &str, flags: KeysymFlags) -> Keysym {
333    unsafe {
334        let cname = CString::new(name.as_bytes().to_owned()).unwrap();
335        Keysym::new(xkb_keysym_from_name(cname.as_ptr(), flags))
336    }
337}
338
339/// Get the Unicode/UTF-8 representation of a keysym.
340///
341/// Prefer not to use this function on keysyms obtained from an
342/// `xkb_state`. In this case, use `xkb_state_key_get_utf8()` instead.
343#[must_use]
344pub fn keysym_to_utf8(keysym: Keysym) -> String {
345    unsafe {
346        let buf: &mut [c_char] = &mut [0; 8];
347        let ptr = &mut buf[0] as *mut c_char;
348        match xkb_keysym_to_utf8(keysym.raw(), ptr, 8) {
349            0 => String::from(""),
350            -1 => {
351                panic!("Key doesn't fit in buffer")
352            }
353            len => {
354                let slice: &[u8] = slice::from_raw_parts(ptr as *const _, len as usize - 1);
355                String::from_utf8_unchecked(slice.to_owned())
356            }
357        }
358    }
359}
360
361/// Get the Unicode/UTF-32 representation of a keysym.
362///
363/// Returns The Unicode/UTF-32 representation of keysym, which is also
364/// compatible with UCS-4. If the keysym does not have a Unicode
365/// representation, returns 0.
366///
367/// Prefer not to use this function on keysyms obtained from an
368/// `xkb_state`. In this case, `use xkb_state_key_get_utf32()` instead.
369#[must_use]
370pub fn keysym_to_utf32(keysym: Keysym) -> u32 {
371    unsafe { xkb_keysym_to_utf32(keysym.raw()) }
372}
373
374/// Get the keysym corresponding to a Unicode/UTF-32 codepoint.
375///
376/// Returns the keysym corresponding to the specified Unicode codepoint,
377/// or `KEY_NoSymbol` if there is none.
378///
379/// This function is the inverse of `keysym_to_utf32`. In cases where a
380/// single codepoint corresponds to multiple keysyms, returns the keysym
381/// with the lowest value.
382///
383/// Unicode codepoints which do not have a special (legacy) keysym
384/// encoding use a direct encoding scheme. These keysyms don't usually
385/// have an associated keysym constant (`XKB_KEY_*`).
386///
387/// For noncharacter Unicode codepoints and codepoints outside of the
388/// defined Unicode planes this function returns `KEY_NoSymbol`.
389#[must_use]
390pub fn utf32_to_keysym(ucs: u32) -> Keysym {
391    unsafe { xkb_utf32_to_keysym(ucs) }.into()
392}
393
394/// Top level library context object.
395///
396/// The context contains various general library data and state, like
397/// logging level and include paths.
398///
399/// Objects are created in a specific context, and multiple contexts may
400/// coexist simultaneously. Objects from different contexts are completely
401/// separated and do not share any memory or state.
402pub struct Context {
403    ptr: *mut xkb_context,
404}
405
406impl Context {
407    /// contruct a context from a raw ffi pointer. This context must already been
408    /// referenced as `xkb_context_unref` will be called at drop time
409    #[allow(clippy::missing_safety_doc)]
410    pub unsafe fn from_raw_ptr(ptr: *mut xkb_context) -> Context {
411        Context { ptr }
412    }
413
414    /// get the raw pointer from this context
415    #[must_use]
416    pub fn get_raw_ptr(&self) -> *mut xkb_context {
417        self.ptr
418    }
419
420    /// Create a new context.
421    ///
422    ///  flags Optional flags for the context, or 0.
423    ///
424    /// The user may set some environment variables to affect default values in
425    /// the context.
426    #[must_use]
427    pub fn new(flags: ContextFlags) -> Context {
428        unsafe {
429            Context {
430                ptr: xkb_context_new(flags),
431            }
432        }
433    }
434
435    /// append a new entry to the context's include path
436    /// returns true on success, or false if the include path could not be added
437    /// or is inaccessible
438    pub fn include_path_append(&mut self, path: &Path) -> bool {
439        path.to_str().map_or(false, |s| unsafe {
440            let cstr = CString::from_vec_unchecked(s.as_bytes().to_owned());
441            xkb_context_include_path_append(self.ptr, cstr.as_ptr()) == 1
442        })
443    }
444
445    /// Append the default include paths to the context's include path.
446    ///
447    /// Returns true on success.
448    pub fn include_path_append_default(&mut self) -> bool {
449        unsafe { xkb_context_include_path_append_default(self.ptr) == 1 }
450    }
451
452    /// Reset the context's include path to the default.
453    ///
454    /// Removes all entries from the context's include path, and inserts the
455    /// default paths.
456    ///
457    /// Returns true on success.yy
458    pub fn include_path_reset_defaults(&mut self) -> bool {
459        unsafe { xkb_context_include_path_reset_defaults(self.ptr) == 1 }
460    }
461
462    /// Remove all entries from the context's include path.
463    pub fn include_path_clear(&mut self) {
464        unsafe {
465            xkb_context_include_path_clear(self.ptr);
466        }
467    }
468
469    /// get an iterator on the include paths of this context
470    #[must_use]
471    pub fn include_paths(&self) -> ContextIncludePaths {
472        unsafe {
473            ContextIncludePaths {
474                context: self,
475                ind: 0,
476                len: xkb_context_num_include_paths(self.ptr),
477            }
478        }
479    }
480
481    /// Set the current logging level.
482    ///
483    /// The default level is `xkb::LogLevel::Error`. The environment variable
484    /// `XKB_LOG_LEVEL`, if set in the time the context was created, overrides the
485    /// default value. It may be specified as a level number or name.
486    pub fn set_log_level(&mut self, level: LogLevel) {
487        unsafe {
488            xkb_context_set_log_level(self.ptr, mem::transmute(level));
489        }
490    }
491
492    #[must_use]
493    pub fn get_log_level(&self) -> LogLevel {
494        unsafe { mem::transmute(xkb_context_get_log_level(self.ptr)) }
495    }
496
497    /// Sets the current logging verbosity.
498    ///
499    /// The library can generate a number of warnings which are not helpful to
500    /// ordinary users of the library. The verbosity may be increased if more
501    /// information is desired (e.g. when developing a new keymap).
502    ///
503    /// The default verbosity is 0. The environment variable `XKB_LOG_VERBOSITY`,
504    /// if set in the time the context was created, overrides the default value.
505    ///
506    /// verbosity can be set from 1 to 10, higher values being more verbose.
507    /// 0 would result in no verbose messages being logged.
508    ///
509    /// Most verbose messages are of level `xkb::LogLevel::Warning` or lower.
510    pub fn set_log_verbosity(&mut self, verbosity: i32) {
511        unsafe {
512            xkb_context_set_log_verbosity(self.ptr, verbosity as c_int);
513        }
514    }
515
516    #[must_use]
517    pub fn get_log_verbosity(&self) -> i32 {
518        unsafe { xkb_context_get_log_verbosity(self.ptr) as i32 }
519    }
520}
521
522impl Clone for Context {
523    fn clone(&self) -> Context {
524        unsafe {
525            Context {
526                ptr: xkb_context_ref(self.ptr),
527            }
528        }
529    }
530}
531
532impl Drop for Context {
533    fn drop(&mut self) {
534        unsafe {
535            xkb_context_unref(self.ptr);
536        }
537    }
538}
539
540/// Iterator to a Context include paths
541pub struct ContextIncludePaths<'a> {
542    context: &'a Context,
543    ind: c_uint,
544    len: c_uint,
545}
546
547impl<'a> Iterator for ContextIncludePaths<'a> {
548    type Item = &'a Path;
549    fn next(&mut self) -> Option<&'a Path> {
550        if self.ind == self.len {
551            None
552        } else {
553            unsafe {
554                let ptr = xkb_context_include_path_get(self.context.ptr, self.ind);
555                self.ind += 1;
556                let cstr = CStr::from_ptr(ptr);
557                Some(Path::new(str::from_utf8_unchecked(cstr.to_bytes())))
558            }
559        }
560    }
561}
562
563#[test]
564fn check_include_paths() {
565    let mut c = Context::new(CONTEXT_NO_DEFAULT_INCLUDES);
566    let test_path = Path::new("/");
567    assert_eq!(true, c.include_path_append(&test_path));
568    assert_eq!(test_path, c.include_paths().nth(0).unwrap());
569}
570
571/// Compiled keymap object.
572///
573/// The keymap object holds all of the static keyboard information obtained
574/// from compiling XKB files.
575///
576/// A keymap is immutable after it is created (besides reference counts, etc.);
577/// if you need to change it, you must create a new one.
578pub struct Keymap {
579    ptr: *mut xkb_keymap,
580}
581
582impl Keymap {
583    #[allow(clippy::missing_safety_doc)]
584    pub unsafe fn from_raw_ptr(ptr: *mut xkb_keymap) -> Keymap {
585        Keymap { ptr }
586    }
587
588    #[must_use]
589    pub fn get_raw_ptr(&self) -> *mut xkb_keymap {
590        self.ptr
591    }
592
593    /// Create a keymap from RMLVO names.
594    ///
595    /// The primary keymap entry point: creates a new XKB keymap from a set of
596    /// RMLVO (Rules + Model + Layouts + Variants + Options) names.
597    ///
598    /// __context__
599    ///  The context in which to create the keymap.
600    ///
601    /// __rules__
602    ///  The rules file to use. The rules file describes how to interpret
603    ///  the values of the model, layout, variant and options fields.
604    ///
605    ///  If empty string "", a default value is used.
606    ///  If the `XKB_DEFAULT_RULES` environment variable is set, it is used
607    ///  as the default. Otherwise the system default is used.
608    ///
609    /// __model__
610    ///  The keyboard model by which to interpret keycodes and LEDs.
611    ///
612    ///  If empty string "", a default value is used.
613    ///  If the `XKB_DEFAULT_MODEL` environment variable is set, it is used
614    ///  as the default. Otherwise the system default is used.
615    ///
616    /// __layout__
617    ///  A comma separated list of layouts (languages) to include in the
618    ///  keymap.
619    ///
620    ///  If empty string "", a default value is used.
621    ///  If the `XKB_DEFAULT_LAYOUT` environment variable is set, it is used
622    ///  as the default. Otherwise the system default is used.
623    ///
624    /// __variant__
625    ///  A comma separated list of variants, one per layout, which may
626    ///  modify or augment the respective layout in various ways.
627    ///
628    ///  If empty string "", and a default value is also used
629    ///  for the layout, a default value is used. Otherwise no variant is
630    ///  used.
631    ///  If the `XKB_DEFAULT_VARIANT` environment variable is set, it is used
632    ///  as the default. Otherwise the system default is used.
633    ///
634    /// __options__
635    ///  A comma separated list of options, through which the user specifies
636    ///  non-layout related preferences, like which key combinations are used
637    ///  for switching layouts, or which key is the Compose key.
638    ///
639    ///  If `None`, a default value is used. If `Some("")` (empty string), no
640    ///  options are used.
641    ///  If the `XKB_DEFAULT_OPTIONS` environment variable is set, it is used
642    ///  as the default. Otherwise the system default is used.
643    ///
644    /// __flags__
645    ///  Optional flags for the keymap, or 0.
646    ///
647    /// Returns a keymap compiled according to the `RMLVO` names, or `None` if
648    /// the compilation failed.
649    #[allow(clippy::missing_panics_doc)]
650    pub fn new_from_names<S: Borrow<str> + ?Sized>(
651        context: &Context,
652        rules: &S,
653        model: &S,
654        layout: &S,
655        variant: &S,
656        mut options: Option<String>,
657        flags: KeymapCompileFlags,
658    ) -> Option<Keymap> {
659        let crules = CString::new(rules.borrow().as_bytes()).unwrap();
660        let cmodel = CString::new(model.borrow().as_bytes()).unwrap();
661        let clayout = CString::new(layout.borrow().as_bytes()).unwrap();
662        let cvariant = CString::new(variant.borrow().as_bytes()).unwrap();
663        let poptions = match &mut options {
664            None => null(),
665            Some(s) => {
666                s.push('\0');
667                s.as_ptr().cast()
668            }
669        };
670        let rule_names = xkb_rule_names {
671            rules: crules.as_ptr(),
672            model: cmodel.as_ptr(),
673            layout: clayout.as_ptr(),
674            variant: cvariant.as_ptr(),
675            options: poptions,
676        };
677        unsafe {
678            let pkeymap = xkb_keymap_new_from_names(context.ptr, &rule_names, flags);
679            if pkeymap.is_null() {
680                None
681            } else {
682                Some(Keymap { ptr: pkeymap })
683            }
684        }
685    }
686
687    ///  Create a keymap from a keymap file.
688    ///
689    ///  Returns `None` if compilation fails.
690    ///
691    ///  The file must contain a complete keymap. For example, in the
692    ///  `XKB_KEYMAP_FORMAT_TEXT_V1` format, this means the file must contain one
693    ///  top level `%xkb_keymap` section, which in turn contains other required
694    ///  sections.
695    ///
696    ///  bindings implementation get the content in a `String`
697    ///  and call `new_from_string()`.
698    pub fn new_from_file(
699        context: &Context,
700        file: &mut fs::File,
701        format: KeymapFormat,
702        flags: KeymapCompileFlags,
703    ) -> Option<Keymap> {
704        let mut string = String::new();
705        file.read_to_string(&mut string)
706            .ok()
707            .and_then(|_| Keymap::new_from_string(context, string, format, flags))
708    }
709
710    ///  Create a keymap from a keymap string.
711    ///
712    ///  This is just like `xkb_keymap_new_from_file()`, but instead of a file, gets
713    ///  the keymap as one enormous string.
714    #[allow(clippy::missing_panics_doc)]
715    #[must_use]
716    pub fn new_from_string(
717        context: &Context,
718        string: String,
719        format: KeymapFormat,
720        flags: KeymapCompileFlags,
721    ) -> Option<Keymap> {
722        unsafe {
723            let cstr = CString::new(string.into_bytes()).unwrap();
724            let ptr = xkb_keymap_new_from_string(context.ptr, cstr.as_ptr(), format, flags);
725            if ptr.is_null() {
726                None
727            } else {
728                Some(Keymap { ptr })
729            }
730        }
731    }
732
733    #[cfg(feature = "wayland")]
734    /// Create a keymap from a file descriptor.
735    /// The file is mapped to memory and the keymap is created from the mapped memory buffer.
736    ///
737    /// # Safety
738    /// The file descriptor must be valid and all safety concerns of mapping files to memory
739    /// apply here.
740    #[allow(clippy::missing_panics_doc)]
741    pub unsafe fn new_from_fd(
742        context: &Context,
743        fd: OwnedFd,
744        size: usize,
745        format: KeymapFormat,
746        flags: KeymapCompileFlags,
747    ) -> std::io::Result<Option<Keymap>> {
748        let map = MmapOptions::new()
749            .len(size as usize)
750            // Starting in version 7 of the wl_keyboard protocol, the keymap must be mapped using MAP_PRIVATE.
751            .map_copy_read_only(&fs::File::from(fd))?;
752        let ptr =
753            xkb_keymap_new_from_buffer(context.ptr, map.as_ptr().cast(), size - 1, format, flags);
754        if ptr.is_null() {
755            Ok(None)
756        } else {
757            Ok(Some(Keymap { ptr }))
758        }
759    }
760
761    /// Get the compiled keymap as a string.
762    ///
763    ///  keymap The keymap to get as a string.
764    ///  format The keymap format to use for the string. You can pass
765    /// in the special value `xkb::KEYMAP_USE_ORIGINAL_FORMAT` to use the format
766    /// from which the keymap was originally created.
767    ///
768    /// Returns The keymap as a NUL-terminated string, or `NULL` if unsuccessful.
769    ///
770    /// The returned string may be fed back into `xkb_map_new_from_string()` to get
771    /// the exact same keymap (possibly in another process, etc).
772    ///
773    /// The returned string is dynamically allocated and should be freed by the
774    /// caller.
775    #[must_use]
776    pub fn get_as_string(&self, format: KeymapFormat) -> String {
777        unsafe {
778            let ffistr = xkb_keymap_get_as_string(self.ptr, format);
779            let cstr = CStr::from_ptr(ffistr);
780            let res = String::from_utf8_unchecked(cstr.to_bytes().to_owned());
781            libc::free(ffistr.cast());
782            res
783        }
784    }
785
786    /// Get the minimum keycode in the keymap.
787    #[must_use]
788    pub fn min_keycode(&self) -> Keycode {
789        Keycode::new(unsafe { xkb_keymap_min_keycode(self.ptr) })
790    }
791
792    /// Get the maximum keycode in the keymap.
793    #[must_use]
794    pub fn max_keycode(&self) -> Keycode {
795        Keycode::new(unsafe { xkb_keymap_max_keycode(self.ptr) })
796    }
797
798    #[allow(unused_variables)]
799    unsafe extern "C" fn callback<F>(
800        pkeymap: *mut ffi::xkb_keymap,
801        key: ffi::xkb_keycode_t,
802        data: *mut raw::c_void,
803    ) where
804        F: FnMut(&Keymap, Keycode),
805    {
806        let mut data_box: Box<(&Keymap, F)> = mem::transmute(Box::from_raw(data));
807        {
808            let (keymap, ref mut closure) = *data_box;
809            closure(keymap, key.into());
810        }
811        let _ = Box::into_raw(data_box);
812    }
813
814    /// Run a specified closure for every valid keycode in the keymap.
815    pub fn key_for_each<F>(&self, closure: F)
816    where
817        F: FnMut(&Keymap, Keycode),
818    {
819        let data_box = Box::new((self, closure));
820        let data_ptr = Box::into_raw(data_box).cast();
821
822        unsafe {
823            ffi::xkb_keymap_key_for_each(self.get_raw_ptr(), Self::callback::<F>, data_ptr);
824            mem::drop(Box::from_raw(data_ptr.cast::<(&Keymap, F)>()));
825        }
826    }
827
828    /// Get an iterator to the modifiers of this keymap
829    #[must_use]
830    pub fn mods(&self) -> KeymapMods {
831        unsafe {
832            KeymapMods {
833                keymap: self,
834                ind: 0,
835                len: xkb_keymap_num_mods(self.ptr),
836            }
837        }
838    }
839
840    /// Get the number of modifiers in the keymap.
841    #[must_use]
842    pub fn num_mods(&self) -> ModIndex {
843        unsafe { xkb_keymap_num_mods(self.ptr) }
844    }
845
846    /// Get the name of a modifier by index.
847    ///
848    /// Returns The name. If the index is invalid, returns "".
849    #[must_use]
850    pub fn mod_get_name(&self, idx: ModIndex) -> &str {
851        unsafe {
852            let ptr = xkb_keymap_mod_get_name(self.ptr, idx);
853            if ptr.is_null() {
854                ""
855            } else {
856                let cstr = CStr::from_ptr(ptr);
857                str::from_utf8_unchecked(cstr.to_bytes())
858            }
859        }
860    }
861
862    /// Get the index of a modifier by name.
863    ///
864    /// Returns The index. If no modifier with this name exists, returns
865    /// `xkb::MOD_INVALID`.
866    #[allow(clippy::missing_panics_doc)]
867    pub fn mod_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> ModIndex {
868        unsafe {
869            let cstr = CString::new(name.borrow().as_bytes()).unwrap();
870            xkb_keymap_mod_get_index(self.ptr, cstr.as_ptr())
871        }
872    }
873
874    /// Returns an iterator to the layouts in this keymap
875    #[must_use]
876    pub fn layouts(&self) -> KeymapLayouts {
877        unsafe {
878            KeymapLayouts {
879                keymap: self,
880                ind: 0,
881                len: xkb_keymap_num_layouts(self.ptr),
882            }
883        }
884    }
885
886    /// Get the number of layouts in the keymap.
887    #[must_use]
888    pub fn num_layouts(&self) -> LayoutIndex {
889        unsafe { xkb_keymap_num_layouts(self.ptr) }
890    }
891
892    /// Get the name of a layout by index.
893    ///
894    /// Returns The name. If the index is invalid, or the layout does not have
895    /// a name, returns "".
896    #[must_use]
897    pub fn layout_get_name(&self, idx: LayoutIndex) -> &str {
898        unsafe {
899            let ptr = xkb_keymap_layout_get_name(self.ptr, idx);
900            if ptr.is_null() {
901                ""
902            } else {
903                let cstr = CStr::from_ptr(ptr);
904                str::from_utf8_unchecked(cstr.to_bytes())
905            }
906        }
907    }
908
909    /// Find the name of the key with the given keycode.
910    /// This function always returns the canonical name of the key (see description in [Keycode]).
911    pub fn key_get_name(&self, key: Keycode) -> Option<&str> {
912        unsafe {
913            let ptr = xkb_keymap_key_get_name(self.ptr, key.into());
914            if ptr.is_null() {
915                None
916            } else {
917                let cstr = CStr::from_ptr(ptr);
918                Some(str::from_utf8_unchecked(cstr.to_bytes()))
919            }
920        }
921    }
922
923    /// Find the keycode of the key with the given name.
924    /// The name can be either a canonical name or an alias.
925    pub fn key_by_name<S: Borrow<str> + ?Sized>(&self, name: &S) -> Option<Keycode> {
926        unsafe {
927            let cstr = CString::new(name.borrow().as_bytes()).unwrap();
928            let code = xkb_keymap_key_by_name(self.ptr, cstr.as_ptr());
929            if code == XKB_KEYCODE_INVALID {
930                None
931            } else {
932                Some(Keycode::new(code))
933            }
934        }
935    }
936
937    /// Get the index of a layout by name.
938    ///
939    /// Returns The index. If no layout exists with this name, returns
940    /// `xkb::LAYOUT_INVALID`. If more than one layout in the keymap has this name,
941    /// returns the lowest index among them.
942    #[allow(clippy::missing_panics_doc)]
943    pub fn layout_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> LayoutIndex {
944        unsafe {
945            let cstr = CString::new(name.borrow().as_bytes()).unwrap();
946            xkb_keymap_layout_get_index(self.ptr, cstr.as_ptr())
947        }
948    }
949
950    /// Returns an iterator to the leds in this keymap
951    #[must_use]
952    pub fn leds(&self) -> KeymapLeds {
953        unsafe {
954            KeymapLeds {
955                keymap: self,
956                ind: 0,
957                len: xkb_keymap_num_leds(self.ptr),
958            }
959        }
960    }
961
962    /// Get the number of LEDs in the keymap.
963    ///
964    /// # warning
965    /// The range `[0..num_leds())` includes all of the LEDs
966    /// in the keymap, but may also contain inactive LEDs. When iterating over
967    /// this range, you need the handle this case when calling functions such as
968    /// `led_get_name()` or `led_index_is_active()`.
969    #[must_use]
970    pub fn num_leds(&self) -> LedIndex {
971        unsafe { xkb_keymap_num_leds(self.ptr) }
972    }
973
974    /// Get the name of a LED by index.
975    ///
976    /// Returns the name. If the index is invalid, returns `""`.
977    #[must_use]
978    pub fn led_get_name(&self, idx: LedIndex) -> &str {
979        unsafe {
980            let ptr = xkb_keymap_led_get_name(self.ptr, idx);
981            if ptr.is_null() {
982                ""
983            } else {
984                let cstr = CStr::from_ptr(ptr);
985                str::from_utf8_unchecked(cstr.to_bytes())
986            }
987        }
988    }
989
990    /// Get the index of a LED by name.
991    ///
992    /// Returns The index. If no LED with this name exists, returns
993    /// `xkb::LED_INVALID`.
994    #[allow(clippy::missing_panics_doc)]
995    pub fn led_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> LedIndex {
996        unsafe {
997            let cstr = CString::new(name.borrow().as_bytes()).unwrap();
998            xkb_keymap_led_get_index(self.ptr, cstr.as_ptr())
999        }
1000    }
1001
1002    /// Get the number of layouts for a specific key.
1003    ///
1004    /// This number can be different `from num_layouts()`, but is always
1005    /// smaller. It is the appropriate value to use when iterating over the
1006    /// layouts of a key.
1007    #[must_use]
1008    pub fn num_layouts_for_key(&self, key: Keycode) -> LayoutIndex {
1009        unsafe { xkb_keymap_num_layouts_for_key(self.ptr, key.raw()) }
1010    }
1011
1012    /// Get the number of shift levels for a specific key and layout.
1013    ///
1014    /// If layout is out of range for this key (that is, larger or equal to
1015    /// the value returned by `num_layouts_for_key()`), it is brought
1016    /// back into range in a manner consistent with `State::key_get_layout()`.
1017    #[must_use]
1018    pub fn num_levels_for_key(&self, key: Keycode, layout: LayoutIndex) -> LevelIndex {
1019        unsafe { xkb_keymap_num_levels_for_key(self.ptr, key.into(), layout) }
1020    }
1021
1022    /// Get the keysyms obtained from pressing a key in a given layout and
1023    /// shift level.
1024    ///
1025    /// This function is like `xkb_state_key_get_syms()`, only the layout and
1026    /// shift level are not derived from the keyboard state but are instead
1027    /// specified explicitly.
1028    ///
1029    /// If layout is out of range for this key (that is, larger or equal to
1030    /// the value returned by `num_layouts_for_key()`), it is brought
1031    /// back into range in a manner consistent with `State::key_get_layout()`.
1032    #[must_use]
1033    pub fn key_get_syms_by_level(
1034        &self,
1035        key: Keycode,
1036        layout: LayoutIndex,
1037        level: LevelIndex,
1038    ) -> &[Keysym] {
1039        unsafe {
1040            let mut syms_out: *const Keysym = null_mut();
1041            let len = xkb_keymap_key_get_syms_by_level(
1042                self.ptr,
1043                key.raw(),
1044                layout,
1045                level,
1046                &mut syms_out as *mut *const Keysym as *mut *const xkeysym::RawKeysym,
1047            );
1048            if syms_out.is_null() {
1049                &[]
1050            } else {
1051                slice::from_raw_parts(syms_out, len as usize)
1052            }
1053        }
1054    }
1055
1056    /// Determine whether a key should repeat or not.
1057    ///
1058    /// A keymap may specify different repeat behaviors for different keys.
1059    /// Most keys should generally exhibit repeat behavior; for example, holding
1060    /// the 'a' key down in a text editor should normally insert a single 'a'
1061    /// character every few milliseconds, until the key is released. However,
1062    /// there are keys which should not or do not need to be repeated. For
1063    /// example, repeating modifier keys such as Left/Right Shift or Caps Lock
1064    /// is not generally useful or desired.
1065    #[must_use]
1066    pub fn key_repeats(&self, key: Keycode) -> bool {
1067        unsafe { xkb_keymap_key_repeats(self.ptr, key.into()) != 0 }
1068    }
1069}
1070
1071impl Clone for Keymap {
1072    fn clone(&self) -> Keymap {
1073        unsafe {
1074            Keymap {
1075                ptr: xkb_keymap_ref(self.ptr),
1076            }
1077        }
1078    }
1079}
1080
1081impl Drop for Keymap {
1082    fn drop(&mut self) {
1083        unsafe {
1084            xkb_keymap_unref(self.ptr);
1085        }
1086    }
1087}
1088
1089/// iterator to the modifiers in a Keymap
1090pub struct KeymapMods<'a> {
1091    keymap: &'a Keymap,
1092    ind: ModIndex,
1093    len: ModIndex,
1094}
1095
1096impl<'a> Iterator for KeymapMods<'a> {
1097    type Item = &'a str;
1098    fn next(&mut self) -> Option<&'a str> {
1099        if self.ind == self.len {
1100            None
1101        } else {
1102            unsafe {
1103                let ptr = xkb_keymap_mod_get_name(self.keymap.ptr, self.ind);
1104                self.ind += 1;
1105                let cstr = CStr::from_ptr(ptr);
1106                Some(str::from_utf8_unchecked(cstr.to_bytes()))
1107            }
1108        }
1109    }
1110}
1111
1112/// iterator to the layouts in Keymap
1113pub struct KeymapLayouts<'a> {
1114    keymap: &'a Keymap,
1115    ind: LayoutIndex,
1116    len: LayoutIndex,
1117}
1118
1119impl<'a> Iterator for KeymapLayouts<'a> {
1120    type Item = &'a str;
1121    fn next(&mut self) -> Option<&'a str> {
1122        if self.ind == self.len {
1123            None
1124        } else {
1125            unsafe {
1126                let ptr = xkb_keymap_layout_get_name(self.keymap.ptr, self.ind);
1127                self.ind += 1;
1128                let cstr = CStr::from_ptr(ptr);
1129                Some(str::from_utf8_unchecked(cstr.to_bytes()))
1130            }
1131        }
1132    }
1133}
1134
1135/// iterator to the leds in a Keymap
1136pub struct KeymapLeds<'a> {
1137    keymap: &'a Keymap,
1138    ind: LedIndex,
1139    len: LedIndex,
1140}
1141
1142impl<'a> Iterator for KeymapLeds<'a> {
1143    type Item = &'a str;
1144    fn next(&mut self) -> Option<&'a str> {
1145        if self.ind == self.len {
1146            None
1147        } else {
1148            unsafe {
1149                let ptr = xkb_keymap_led_get_name(self.keymap.ptr, self.ind);
1150                self.ind += 1;
1151                let cstr = CStr::from_ptr(ptr);
1152                Some(str::from_utf8_unchecked(cstr.to_bytes()))
1153            }
1154        }
1155    }
1156}
1157
1158/// Keyboard state object.
1159///
1160/// State objects contain the active state of a keyboard (or keyboards), such
1161/// as the currently effective layout and the active modifiers. It acts as a
1162/// simple state machine, wherein key presses and releases are the input, and
1163/// key symbols (keysyms) are the output.
1164pub struct State {
1165    ptr: *mut xkb_state,
1166}
1167
1168impl State {
1169    #[allow(clippy::missing_safety_doc)]
1170    pub unsafe fn from_raw_ptr(ptr: *mut xkb_state) -> State {
1171        State { ptr }
1172    }
1173
1174    #[must_use]
1175    pub fn get_raw_ptr(&self) -> *mut xkb_state {
1176        self.ptr
1177    }
1178
1179    /// Create a new keyboard state object from a keymap.
1180    #[must_use]
1181    pub fn new(keymap: &Keymap) -> State {
1182        unsafe {
1183            State {
1184                ptr: xkb_state_new(keymap.ptr),
1185            }
1186        }
1187    }
1188
1189    /// Get the keymap which a keyboard state object is using.
1190    ///
1191    /// Returns the keymap which was passed to `xkb_state_new()` when creating
1192    /// this state object.
1193    ///
1194    /// This keymap can safely be used beyond the lifetime of this state
1195    #[must_use]
1196    pub fn get_keymap(&self) -> Keymap {
1197        unsafe {
1198            let keymap = xkb_state_get_keymap(self.ptr);
1199            xkb_keymap_ref(keymap);
1200            Keymap::from_raw_ptr(keymap)
1201        }
1202    }
1203
1204    /// Update the keyboard state to reflect a given key being pressed or
1205    /// released.
1206    ///
1207    /// This entry point is intended for programs which track the keyboard state
1208    /// explictly (like an evdev client). If the state is serialized to you by
1209    /// a master process (like a Wayland compositor) using functions like
1210    /// `xkb_state_serialize_mods()`, you should use `xkb_state_update_mask()`
1211    /// instead. The two functins should not generally be used together.
1212    ///
1213    /// A series of calls to this function should be consistent; that is, a call
1214    /// with `xkb::KEY_DOWN` for a key should be matched by an `xkb::KEY_UP`; if
1215    /// a key is pressed twice, it should be released twice; etc. Otherwise (e.g.
1216    /// due to missed input events), situations like "stuck modifiers" may occur.
1217    ///
1218    /// This function is often used in conjunction with the function
1219    /// `xkb_state_key_get_syms()` (or `xkb_state_key_get_one_sym()`), for
1220    /// example, when handling a key event. In this case, you should prefer to
1221    /// get the keysyms *before* updating the key, such that the keysyms reported
1222    /// for the key event are not affected by the event itself. This is the
1223    /// conventional behavior.
1224    ///
1225    /// Returns A mask of state components that have changed as a result of
1226    /// the update. If nothing in the state has changed, returns 0.
1227    pub fn update_key(&mut self, key: Keycode, direction: KeyDirection) -> StateComponent {
1228        unsafe { xkb_state_update_key(self.ptr, key.into(), mem::transmute(direction)) }
1229    }
1230
1231    /// Update a keyboard state from a set of explicit masks.
1232    ///
1233    /// This entry point is intended for window systems and the like, where a
1234    /// master process holds an `xkb_state`, then serializes it over a wire
1235    /// protocol, and clients then use the serialization to feed in to their own
1236    /// `xkb_state`.
1237    ///
1238    /// All parameters must always be passed, or the resulting state may be
1239    /// incoherent.
1240    ///
1241    /// The serialization is lossy and will not survive round trips; it must only
1242    /// be used to feed slave state objects, and must not be used to update the
1243    /// master state.
1244    ///
1245    /// If you do not fit the description above, you should use
1246    /// `xkb_state_update_key()` instead. The two functions should not generally be
1247    /// used together.
1248    ///
1249    /// Returns a mask of state components that have changed as a result of
1250    /// the update. If nothing in the state has changed, returns 0.
1251    pub fn update_mask(
1252        &mut self,
1253        depressed_mods: ModMask,
1254        latched_mods: ModMask,
1255        locked_mods: ModMask,
1256        depressed_layout: LayoutIndex,
1257        latched_layout: LayoutIndex,
1258        locked_layout: LayoutIndex,
1259    ) -> StateComponent {
1260        unsafe {
1261            xkb_state_update_mask(
1262                self.ptr,
1263                depressed_mods,
1264                latched_mods,
1265                locked_mods,
1266                depressed_layout,
1267                latched_layout,
1268                locked_layout,
1269            )
1270        }
1271    }
1272
1273    /// Get the keysyms obtained from pressing a particular key in a given
1274    /// keyboard state.
1275    ///
1276    /// Get the keysyms for a key according to the current active layout,
1277    /// modifiers and shift level for the key, as determined by a keyboard
1278    /// state.
1279    ///
1280    /// # Arguments
1281    /// * `state`: The keyboard state object.
1282    /// * `key`: The keycode of the key.
1283    ///
1284    /// # Return
1285    /// * `syms_out`: An immutable array of keysyms corresponding the
1286    /// key in the given keyboard state.
1287    ///
1288    /// As an extension to XKB, this function can return more than one keysym.
1289    /// If you do not want to handle this case, you should use
1290    /// `xkb_state_key_get_one_sym()`, which additionally performs transformations
1291    /// which are specific to the one-keysym case.
1292    #[must_use]
1293    pub fn key_get_syms(&self, key: Keycode) -> &[Keysym] {
1294        unsafe {
1295            let mut syms_out: *const Keysym = null_mut();
1296            let len = xkb_state_key_get_syms(
1297                self.ptr,
1298                key.into(),
1299                &mut syms_out as *mut *const Keysym as *mut *const xkeysym::RawKeysym,
1300            );
1301            if syms_out.is_null() {
1302                &[]
1303            } else {
1304                slice::from_raw_parts(syms_out, len as usize)
1305            }
1306        }
1307    }
1308
1309    /// Get the Unicode/UTF-8 string obtained from pressing a particular key
1310    /// in a given keyboard state.
1311    #[must_use]
1312    pub fn key_get_utf8(&self, key: Keycode) -> String {
1313        unsafe {
1314            const BUF_LEN: usize = 64;
1315            let buf: &mut [c_char] = &mut [0; BUF_LEN];
1316            let ptr = &mut buf[0] as *mut c_char;
1317            let ret = xkb_state_key_get_utf8(self.ptr, key.into(), ptr, BUF_LEN);
1318            // ret is similar to the return value of snprintf.
1319            // it may be negative on unspecified errors, or >64 if the buffer is too small.
1320            let len = ret.max(0).min(BUF_LEN as i32);
1321            let slice: &[u8] = slice::from_raw_parts(ptr as *const _, len as usize);
1322            String::from_utf8_unchecked(slice.to_owned())
1323        }
1324    }
1325
1326    /// Get the Unicode/UTF-32 codepoint obtained from pressing a particular
1327    /// key in a a given keyboard state.
1328    ///
1329    /// Returns The UTF-32 representation for the key, if it consists of only
1330    /// a single codepoint. Otherwise, returns 0.
1331    #[must_use]
1332    pub fn key_get_utf32(&self, key: Keycode) -> u32 {
1333        unsafe { xkb_state_key_get_utf32(self.ptr, key.into()) }
1334    }
1335
1336    /// Get the single keysym obtained from pressing a particular key in a
1337    /// given keyboard state.
1338    ///
1339    /// This function is similar to `xkb_state_key_get_syms()`, but intended
1340    /// for users which cannot or do not want to handle the case where
1341    /// multiple keysyms are returned (in which case this function is
1342    /// preferred).
1343    ///
1344    /// Returns the keysym. If the key does not have exactly one keysym,
1345    /// returns `xkb::KEY_NoSymbol`.
1346    #[must_use]
1347    pub fn key_get_one_sym(&self, key: Keycode) -> Keysym {
1348        unsafe { xkb_state_key_get_one_sym(self.ptr, key.into()) }.into()
1349    }
1350
1351    /// Get the effective layout index for a key in a given keyboard state.
1352    ///
1353    /// Returns the layout index for the key in the given keyboard state. If
1354    /// the given keycode is invalid, or if the key is not included in any
1355    /// layout at all, returns `xkb::LAYOUT_INVALID`.
1356    #[must_use]
1357    pub fn key_get_layout(&self, key: Keycode) -> LayoutIndex {
1358        unsafe { xkb_state_key_get_layout(self.ptr, key.into()) }
1359    }
1360
1361    /// Get the effective shift level for a key in a given keyboard state and
1362    /// layout.
1363    ///
1364    /// Return the shift level index. If the key or layout are invalid,
1365    /// returns `xkb::LEVEL_INVALID`.
1366    #[must_use]
1367    pub fn key_get_level(&self, key: Keycode, layout: LayoutIndex) -> LevelIndex {
1368        unsafe { xkb_state_key_get_level(self.ptr, key.into(), layout) }
1369    }
1370
1371    /// The counterpart to `xkb_state_update_mask` for modifiers, to be used on
1372    /// the server side of serialization.
1373    ///
1374    /// State components other than `xkb::STATE_MODS_*` are ignored.
1375    /// If `xkb::STATE_MODS_EFFECTIVE` is included, all other state components are
1376    /// ignored.
1377    ///
1378    /// Returns a `ModMask` representing the given components of the
1379    /// modifier state.
1380    ///
1381    /// This function should not be used in regular clients; please use the
1382    /// `xkb::State::mod_*_is_active` API instead.
1383    #[must_use]
1384    pub fn serialize_mods(&self, components: StateComponent) -> ModMask {
1385        unsafe { xkb_state_serialize_mods(self.ptr, components) }
1386    }
1387
1388    #[must_use]
1389    pub fn serialize_layout(&self, components: StateComponent) -> LayoutIndex {
1390        unsafe { xkb_state_serialize_layout(self.ptr, components) }
1391    }
1392
1393    /// Test whether a modifier is active in a given keyboard state by name.
1394    #[allow(clippy::missing_panics_doc)]
1395    pub fn mod_name_is_active<S: Borrow<str> + ?Sized>(
1396        &self,
1397        name: &S,
1398        type_: StateComponent,
1399    ) -> bool {
1400        unsafe {
1401            let cname = CString::new(name.borrow().as_bytes()).unwrap();
1402            xkb_state_mod_name_is_active(self.ptr, cname.as_ptr(), type_) == 1
1403        }
1404    }
1405
1406    /// Test whether a modifier is active in a given keyboard state by index.
1407    #[must_use]
1408    pub fn mod_index_is_active(&self, idx: ModIndex, type_: StateComponent) -> bool {
1409        unsafe { xkb_state_mod_index_is_active(self.ptr, idx, type_) == 1 }
1410    }
1411
1412    /// Test whether a modifier is consumed by keyboard state translation for
1413    /// a key.
1414    ///
1415    /// Some functions, like `xkb_state_key_get_syms()`, look at the state of
1416    /// the modifiers in the keymap and derive from it the correct shift level
1417    /// to use for the key. For example, in a US layout, pressing the key
1418    /// labeled \<A\> while the Shift modifier is active, generates the keysym 'A'.
1419    /// In this case, the Shift modifier is said to be consumed. However, the
1420    /// Num Lock modifier does not affect this translation at all, even if it
1421    /// active, so it is not consumed by this translation.
1422    ///
1423    /// It may be desirable for some application to not reuse consumed modifiers
1424    /// for further processing, e.g. for hotkeys or keyboard shortcuts. To
1425    /// understand why, consider some requirements from a standard shortcut
1426    /// mechanism, and how they are implemented:
1427    ///
1428    /// 1. The shortcut's modifiers must match exactly to the state. For example,
1429    ///    it is possible to bind separate actions to \<Alt\>\<Tab\> and to
1430    ///    \<Alt\>\<Shift\>\<Tab\>. Further, if only \<Alt\>\<Tab\> is bound to
1431    ///    an action, pressing \<Alt\>\<Shift\>\<Tab\> should not trigger the
1432    ///    shortcut.
1433    ///    Effectively, this means that the modifiers are compared using the
1434    ///    equality operator (==).
1435    /// 2. Only relevant modifiers are considered for the matching. For example,
1436    ///    Caps Lock and Num Lock should not generally affect the matching, e.g.
1437    ///    when matching \<Alt\>\<Tab\> against the state, it does not matter
1438    ///    whether Num Lock is active or not. These relevant, or significant,
1439    ///    modifiers usually include Alt, Control, Shift, Super and similar.
1440    ///    Effectively, this means that non-significant modifiers are masked out,
1441    ///    before doing the comparison as described above.
1442    /// 3. The matching must be independent of the layout/keymap. For example,
1443    ///    the \<Plus\> (+) symbol is found on the first level on some layouts,
1444    ///    and requires holding Shift on others. If you simply bind the action
1445    ///    to the \<Plus\> keysym, it would work for the unshifted kind, but
1446    ///    not for the others, because the match against Shift would fail. If
1447    ///    you bind the action to \<Shift\>\<Plus\>, only the shifted kind would
1448    ///    work. So what is needed is to recognize that Shift is used up in the
1449    ///    translation of the keysym itself, and therefore should not be included
1450    ///    in the matching.
1451    ///    Effectively, this means that consumed modifiers (Shift in this example)
1452    ///    are masked out as well, before doing the comparison.
1453    ///
1454    /// `state_modifiers` are the modifiers reported by
1455    /// `xkb::State::mod_index_is_active()` and similar functions.
1456    /// `consumed_modifiers` are the modifiers reported by
1457    /// `xkb::State::mod_index_is_consumed()`.
1458    /// `significant_modifiers` are decided upon by the application/toolkit/user;
1459    /// it is up to them to decide whether these are configurable or hard-coded.
1460    #[must_use]
1461    pub fn mod_index_is_consumed(&self, key: Keycode, idx: ModIndex) -> bool {
1462        unsafe { xkb_state_mod_index_is_consumed(self.ptr, key.into(), idx) == 1 }
1463    }
1464
1465    /// Remove consumed modifiers from a modifier mask for a key.
1466    ///
1467    /// Takes the given modifier mask, and removes all modifiers which are
1468    /// consumed for that particular key (as in `xkb_state_mod_index_is_consumed()`).
1469    #[must_use]
1470    pub fn mod_mask_remove_consumed(&self, key: Keycode, mask: ModMask) -> ModMask {
1471        unsafe { xkb_state_mod_mask_remove_consumed(self.ptr, key.into(), mask) }
1472    }
1473
1474    /// Get the mask of modifiers consumed by translating a given key.
1475    ///
1476    /// Returns a mask of the consumed modifiers.
1477    #[must_use]
1478    pub fn key_get_consumed_mods(&self, key: Keycode) -> ModMask {
1479        unsafe { xkb_state_key_get_consumed_mods(self.ptr, key.into()) }
1480    }
1481
1482    /// Test whether a layout is active in a given keyboard state by name.
1483    ///
1484    /// If multiple layouts in the keymap have this name, the one with the lowest
1485    /// index is tested.
1486    #[allow(clippy::missing_panics_doc)]
1487    pub fn layout_name_is_active<S: Borrow<str> + ?Sized>(
1488        &self,
1489        name: &S,
1490        type_: StateComponent,
1491    ) -> bool {
1492        unsafe {
1493            let cname = CString::new(name.borrow().as_bytes()).unwrap();
1494            xkb_state_layout_name_is_active(self.ptr, cname.as_ptr(), type_) != 0
1495        }
1496    }
1497
1498    /// Test whether a layout is active in a given keyboard state by index.
1499    #[must_use]
1500    pub fn layout_index_is_active(&self, idx: LayoutIndex, type_: StateComponent) -> bool {
1501        unsafe { xkb_state_layout_index_is_active(self.ptr, idx, type_) != 0 }
1502    }
1503
1504    /// Test whether a LED is active in a given keyboard state by name.
1505    #[allow(clippy::missing_panics_doc)]
1506    pub fn led_name_is_active<S: Borrow<str> + ?Sized>(&self, name: &S) -> bool {
1507        unsafe {
1508            let cname = CString::new(name.borrow().as_bytes()).unwrap();
1509            xkb_state_led_name_is_active(self.ptr, cname.as_ptr()) != 0
1510        }
1511    }
1512
1513    /// Test whether a LED is active in a given keyboard state by index.
1514    #[must_use]
1515    pub fn led_index_is_active(&self, idx: LedIndex) -> bool {
1516        unsafe { xkb_state_led_index_is_active(self.ptr, idx) != 0 }
1517    }
1518}
1519
1520impl Clone for State {
1521    fn clone(&self) -> State {
1522        unsafe {
1523            State {
1524                ptr: xkb_state_ref(self.ptr),
1525            }
1526        }
1527    }
1528}
1529
1530impl Drop for State {
1531    fn drop(&mut self) {
1532        unsafe {
1533            xkb_state_unref(self.ptr);
1534        }
1535    }
1536}