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 i8 = &mut buf[0] as *mut c_char;
305 let len: usize = xkb_keysym_get_name(keysym.raw(), buffer:ptr, BUF_LEN);
306 if len <= 0 {
307 return String::new();
308 }
309 let slice: &[u8] = slice::from_raw_parts(data:ptr as *const _, (len as usize).min(BUF_LEN));
310 String::from_utf8_unchecked(bytes: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 = CString::new(name.as_bytes().to_owned()).unwrap();
335 Keysym::new(raw:xkb_keysym_from_name(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 i8 = &mut buf[0] as *mut c_char;
348 match xkb_keysym_to_utf8(keysym.raw(), buffer:ptr, size:8) {
349 0 => String::from(""),
350 -1 => {
351 panic!("Key doesn't fit in buffer")
352 }
353 len: i32 => {
354 let slice: &[u8] = slice::from_raw_parts(data:ptr as *const _, len:len as usize - 1);
355 String::from_utf8_unchecked(bytes: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: *const {unknown} = xkb_context_include_path_get(self.context.ptr, self.ind);
555 self.ind += 1;
556 let cstr: &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: *const {unknown} = xkb_keymap_mod_get_name(self.keymap.ptr, self.ind);
1104 self.ind += 1;
1105 let cstr: &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: *const {unknown} = xkb_keymap_layout_get_name(self.keymap.ptr, self.ind);
1127 self.ind += 1;
1128 let cstr: &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: *const {unknown} = xkb_keymap_led_get_name(self.keymap.ptr, self.ind);
1150 self.ind += 1;
1151 let cstr: &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}
1537