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 let buf: &mut [c_char] = &mut [0; 64];
303 let ptr: *mut i8 = &mut buf[0] as *mut c_char;
304 let len: i32 = xkb_keysym_get_name(keysym:keysym.raw(), buffer:ptr, size:64);
305 let slice: &[u8] = slice::from_raw_parts(data:ptr as *const _, len as usize);
306 String::from_utf8_unchecked(bytes:slice.to_owned())
307 }
308}
309
310/// Get a keysym from its name.
311///
312/// name The name of a keysym. See remarks in `xkb_keysym_get_name()`;
313/// this function will accept any name returned by that function.
314/// flags A set of flags controlling how the search is done. If
315/// invalid flags are passed, this will fail with `xkb::KEY_NoSymbol`.
316///
317/// If you use the `xkb::KEYSYM_CASE_INSENSITIVE` flag and two keysym names
318/// differ only by case, then the lower-case keysym is returned. For
319/// instance, for `KEY_a` and `KEY_A`, this function would return `KEY_a` for
320/// the case-insensitive search. If this functionality is needed, it is
321/// recommended to first call this function without this flag; and if that
322/// fails, only then to try with this flag, while possibly warning the user
323/// he had misspelled the name, and might get wrong results.
324///
325/// Returns The keysym. If the name is invalid, returns `xkb::KEY_NoSymbol`.
326#[allow(clippy::missing_panics_doc)]
327#[must_use]
328pub fn keysym_from_name(name: &str, flags: KeysymFlags) -> Keysym {
329 unsafe {
330 let cname: CString = CString::new(name.as_bytes().to_owned()).unwrap();
331 Keysym::new(raw:xkb_keysym_from_name(name:cname.as_ptr(), flags))
332 }
333}
334
335/// Get the Unicode/UTF-8 representation of a keysym.
336///
337/// Prefer not to use this function on keysyms obtained from an
338/// `xkb_state`. In this case, use `xkb_state_key_get_utf8()` instead.
339#[must_use]
340pub fn keysym_to_utf8(keysym: Keysym) -> String {
341 unsafe {
342 let buf: &mut [c_char] = &mut [0; 8];
343 let ptr: *mut i8 = &mut buf[0] as *mut c_char;
344 let len: i32 = xkb_keysym_to_utf8(keysym:keysym.raw(), buffer:ptr, size:8);
345 let slice: &[u8] = slice::from_raw_parts(data:ptr as *const _, len as usize);
346 String::from_utf8_unchecked(bytes:slice.to_owned())
347 }
348}
349
350/// Get the Unicode/UTF-32 representation of a keysym.
351///
352/// Returns The Unicode/UTF-32 representation of keysym, which is also
353/// compatible with UCS-4. If the keysym does not have a Unicode
354/// representation, returns 0.
355///
356/// Prefer not to use this function on keysyms obtained from an
357/// `xkb_state`. In this case, `use xkb_state_key_get_utf32()` instead.
358#[must_use]
359pub fn keysym_to_utf32(keysym: Keysym) -> u32 {
360 unsafe { xkb_keysym_to_utf32(keysym:keysym.raw()) }
361}
362
363/// Get the keysym corresponding to a Unicode/UTF-32 codepoint.
364///
365/// Returns the keysym corresponding to the specified Unicode codepoint,
366/// or `KEY_NoSymbol` if there is none.
367///
368/// This function is the inverse of `keysym_to_utf32`. In cases where a
369/// single codepoint corresponds to multiple keysyms, returns the keysym
370/// with the lowest value.
371///
372/// Unicode codepoints which do not have a special (legacy) keysym
373/// encoding use a direct encoding scheme. These keysyms don't usually
374/// have an associated keysym constant (`XKB_KEY_*`).
375///
376/// For noncharacter Unicode codepoints and codepoints outside of the
377/// defined Unicode planes this function returns `KEY_NoSymbol`.
378#[must_use]
379pub fn utf32_to_keysym(ucs: u32) -> Keysym {
380 unsafe { xkb_utf32_to_keysym(ucs) }.into()
381}
382
383/// Top level library context object.
384///
385/// The context contains various general library data and state, like
386/// logging level and include paths.
387///
388/// Objects are created in a specific context, and multiple contexts may
389/// coexist simultaneously. Objects from different contexts are completely
390/// separated and do not share any memory or state.
391pub struct Context {
392 ptr: *mut xkb_context,
393}
394
395impl Context {
396 /// contruct a context from a raw ffi pointer. This context must already been
397 /// referenced as `xkb_context_unref` will be called at drop time
398 #[allow(clippy::missing_safety_doc)]
399 pub unsafe fn from_raw_ptr(ptr: *mut xkb_context) -> Context {
400 Context { ptr }
401 }
402
403 /// get the raw pointer from this context
404 #[must_use]
405 pub fn get_raw_ptr(&self) -> *mut xkb_context {
406 self.ptr
407 }
408
409 /// Create a new context.
410 ///
411 /// flags Optional flags for the context, or 0.
412 ///
413 /// The user may set some environment variables to affect default values in
414 /// the context.
415 #[must_use]
416 pub fn new(flags: ContextFlags) -> Context {
417 unsafe {
418 Context {
419 ptr: xkb_context_new(flags),
420 }
421 }
422 }
423
424 /// append a new entry to the context's include path
425 /// returns true on success, or false if the include path could not be added
426 /// or is inaccessible
427 pub fn include_path_append(&mut self, path: &Path) -> bool {
428 path.to_str().map_or(false, |s| unsafe {
429 let cstr = CString::from_vec_unchecked(s.as_bytes().to_owned());
430 xkb_context_include_path_append(self.ptr, cstr.as_ptr()) == 1
431 })
432 }
433
434 /// Append the default include paths to the context's include path.
435 ///
436 /// Returns true on success.
437 pub fn include_path_append_default(&mut self) -> bool {
438 unsafe { xkb_context_include_path_append_default(self.ptr) == 1 }
439 }
440
441 /// Reset the context's include path to the default.
442 ///
443 /// Removes all entries from the context's include path, and inserts the
444 /// default paths.
445 ///
446 /// Returns true on success.yy
447 pub fn include_path_reset_defaults(&mut self) -> bool {
448 unsafe { xkb_context_include_path_reset_defaults(self.ptr) == 1 }
449 }
450
451 /// Remove all entries from the context's include path.
452 pub fn include_path_clear(&mut self) {
453 unsafe {
454 xkb_context_include_path_clear(self.ptr);
455 }
456 }
457
458 /// get an iterator on the include paths of this context
459 #[must_use]
460 pub fn include_paths(&self) -> ContextIncludePaths {
461 unsafe {
462 ContextIncludePaths {
463 context: self,
464 ind: 0,
465 len: xkb_context_num_include_paths(self.ptr),
466 }
467 }
468 }
469
470 /// Set the current logging level.
471 ///
472 /// The default level is `xkb::LogLevel::Error`. The environment variable
473 /// `XKB_LOG_LEVEL`, if set in the time the context was created, overrides the
474 /// default value. It may be specified as a level number or name.
475 pub fn set_log_level(&mut self, level: LogLevel) {
476 unsafe {
477 xkb_context_set_log_level(self.ptr, mem::transmute(level));
478 }
479 }
480
481 #[must_use]
482 pub fn get_log_level(&self) -> LogLevel {
483 unsafe { mem::transmute(xkb_context_get_log_level(self.ptr)) }
484 }
485
486 /// Sets the current logging verbosity.
487 ///
488 /// The library can generate a number of warnings which are not helpful to
489 /// ordinary users of the library. The verbosity may be increased if more
490 /// information is desired (e.g. when developing a new keymap).
491 ///
492 /// The default verbosity is 0. The environment variable `XKB_LOG_VERBOSITY`,
493 /// if set in the time the context was created, overrides the default value.
494 ///
495 /// verbosity can be set from 1 to 10, higher values being more verbose.
496 /// 0 would result in no verbose messages being logged.
497 ///
498 /// Most verbose messages are of level `xkb::LogLevel::Warning` or lower.
499 pub fn set_log_verbosity(&mut self, verbosity: i32) {
500 unsafe {
501 xkb_context_set_log_verbosity(self.ptr, verbosity as c_int);
502 }
503 }
504
505 #[must_use]
506 pub fn get_log_verbosity(&self) -> i32 {
507 unsafe { xkb_context_get_log_verbosity(self.ptr) as i32 }
508 }
509}
510
511impl Clone for Context {
512 fn clone(&self) -> Context {
513 unsafe {
514 Context {
515 ptr: xkb_context_ref(self.ptr),
516 }
517 }
518 }
519}
520
521impl Drop for Context {
522 fn drop(&mut self) {
523 unsafe {
524 xkb_context_unref(self.ptr);
525 }
526 }
527}
528
529/// Iterator to a Context include paths
530pub struct ContextIncludePaths<'a> {
531 context: &'a Context,
532 ind: c_uint,
533 len: c_uint,
534}
535
536impl<'a> Iterator for ContextIncludePaths<'a> {
537 type Item = &'a Path;
538 fn next(&mut self) -> Option<&'a Path> {
539 if self.ind == self.len {
540 None
541 } else {
542 unsafe {
543 let ptr: *const i8 = xkb_context_include_path_get(self.context.ptr, self.ind);
544 self.ind += 1;
545 let cstr: &CStr = CStr::from_ptr(ptr);
546 Some(Path::new(str::from_utf8_unchecked(cstr.to_bytes())))
547 }
548 }
549 }
550}
551
552#[test]
553fn check_include_paths() {
554 let mut c: Context = Context::new(CONTEXT_NO_DEFAULT_INCLUDES);
555 let test_path: &Path = Path::new("/");
556 assert_eq!(true, c.include_path_append(&test_path));
557 assert_eq!(test_path, c.include_paths().nth(0).unwrap());
558}
559
560/// Compiled keymap object.
561///
562/// The keymap object holds all of the static keyboard information obtained
563/// from compiling XKB files.
564///
565/// A keymap is immutable after it is created (besides reference counts, etc.);
566/// if you need to change it, you must create a new one.
567pub struct Keymap {
568 ptr: *mut xkb_keymap,
569}
570
571impl Keymap {
572 #[allow(clippy::missing_safety_doc)]
573 pub unsafe fn from_raw_ptr(ptr: *mut xkb_keymap) -> Keymap {
574 Keymap { ptr }
575 }
576
577 #[must_use]
578 pub fn get_raw_ptr(&self) -> *mut xkb_keymap {
579 self.ptr
580 }
581
582 /// Create a keymap from RMLVO names.
583 ///
584 /// The primary keymap entry point: creates a new XKB keymap from a set of
585 /// RMLVO (Rules + Model + Layouts + Variants + Options) names.
586 ///
587 /// __context__
588 /// The context in which to create the keymap.
589 ///
590 /// __rules__
591 /// The rules file to use. The rules file describes how to interpret
592 /// the values of the model, layout, variant and options fields.
593 ///
594 /// If empty string "", a default value is used.
595 /// If the `XKB_DEFAULT_RULES` environment variable is set, it is used
596 /// as the default. Otherwise the system default is used.
597 ///
598 /// __model__
599 /// The keyboard model by which to interpret keycodes and LEDs.
600 ///
601 /// If empty string "", a default value is used.
602 /// If the `XKB_DEFAULT_MODEL` environment variable is set, it is used
603 /// as the default. Otherwise the system default is used.
604 ///
605 /// __layout__
606 /// A comma separated list of layouts (languages) to include in the
607 /// keymap.
608 ///
609 /// If empty string "", a default value is used.
610 /// If the `XKB_DEFAULT_LAYOUT` environment variable is set, it is used
611 /// as the default. Otherwise the system default is used.
612 ///
613 /// __variant__
614 /// A comma separated list of variants, one per layout, which may
615 /// modify or augment the respective layout in various ways.
616 ///
617 /// If empty string "", and a default value is also used
618 /// for the layout, a default value is used. Otherwise no variant is
619 /// used.
620 /// If the `XKB_DEFAULT_VARIANT` environment variable is set, it is used
621 /// as the default. Otherwise the system default is used.
622 ///
623 /// __options__
624 /// A comma separated list of options, through which the user specifies
625 /// non-layout related preferences, like which key combinations are used
626 /// for switching layouts, or which key is the Compose key.
627 ///
628 /// If `None`, a default value is used. If `Some("")` (empty string), no
629 /// options are used.
630 /// If the `XKB_DEFAULT_OPTIONS` environment variable is set, it is used
631 /// as the default. Otherwise the system default is used.
632 ///
633 /// __flags__
634 /// Optional flags for the keymap, or 0.
635 ///
636 /// Returns a keymap compiled according to the `RMLVO` names, or `None` if
637 /// the compilation failed.
638 #[allow(clippy::missing_panics_doc)]
639 pub fn new_from_names<S: Borrow<str> + ?Sized>(
640 context: &Context,
641 rules: &S,
642 model: &S,
643 layout: &S,
644 variant: &S,
645 mut options: Option<String>,
646 flags: KeymapCompileFlags,
647 ) -> Option<Keymap> {
648 let crules = CString::new(rules.borrow().as_bytes()).unwrap();
649 let cmodel = CString::new(model.borrow().as_bytes()).unwrap();
650 let clayout = CString::new(layout.borrow().as_bytes()).unwrap();
651 let cvariant = CString::new(variant.borrow().as_bytes()).unwrap();
652 let poptions = match &mut options {
653 None => null(),
654 Some(s) => {
655 s.push('\0');
656 s.as_ptr().cast()
657 }
658 };
659 let rule_names = xkb_rule_names {
660 rules: crules.as_ptr(),
661 model: cmodel.as_ptr(),
662 layout: clayout.as_ptr(),
663 variant: cvariant.as_ptr(),
664 options: poptions,
665 };
666 unsafe {
667 let pkeymap = xkb_keymap_new_from_names(context.ptr, &rule_names, flags);
668 if pkeymap.is_null() {
669 None
670 } else {
671 Some(Keymap { ptr: pkeymap })
672 }
673 }
674 }
675
676 /// Create a keymap from a keymap file.
677 ///
678 /// Returns `None` if compilation fails.
679 ///
680 /// The file must contain a complete keymap. For example, in the
681 /// `XKB_KEYMAP_FORMAT_TEXT_V1` format, this means the file must contain one
682 /// top level `%xkb_keymap` section, which in turn contains other required
683 /// sections.
684 ///
685 /// bindings implementation get the content in a `String`
686 /// and call `new_from_string()`.
687 pub fn new_from_file(
688 context: &Context,
689 file: &mut fs::File,
690 format: KeymapFormat,
691 flags: KeymapCompileFlags,
692 ) -> Option<Keymap> {
693 let mut string = String::new();
694 file.read_to_string(&mut string)
695 .ok()
696 .and_then(|_| Keymap::new_from_string(context, string, format, flags))
697 }
698
699 /// Create a keymap from a keymap string.
700 ///
701 /// This is just like `xkb_keymap_new_from_file()`, but instead of a file, gets
702 /// the keymap as one enormous string.
703 #[allow(clippy::missing_panics_doc)]
704 #[must_use]
705 pub fn new_from_string(
706 context: &Context,
707 string: String,
708 format: KeymapFormat,
709 flags: KeymapCompileFlags,
710 ) -> Option<Keymap> {
711 unsafe {
712 let cstr = CString::new(string.into_bytes()).unwrap();
713 let ptr = xkb_keymap_new_from_string(context.ptr, cstr.as_ptr(), format, flags);
714 if ptr.is_null() {
715 None
716 } else {
717 Some(Keymap { ptr })
718 }
719 }
720 }
721
722 #[cfg(feature = "wayland")]
723 /// Create a keymap from a file descriptor.
724 /// The file is mapped to memory and the keymap is created from the mapped memory buffer.
725 ///
726 /// # Safety
727 /// The file descriptor must be valid and all safety concerns of mapping files to memory
728 /// apply here.
729 #[allow(clippy::missing_panics_doc)]
730 pub unsafe fn new_from_fd(
731 context: &Context,
732 fd: OwnedFd,
733 size: usize,
734 format: KeymapFormat,
735 flags: KeymapCompileFlags,
736 ) -> std::io::Result<Option<Keymap>> {
737 let map = MmapOptions::new()
738 .len(size as usize)
739 // Starting in version 7 of the wl_keyboard protocol, the keymap must be mapped using MAP_PRIVATE.
740 .map_copy_read_only(&fs::File::from(fd))?;
741 let ptr =
742 xkb_keymap_new_from_buffer(context.ptr, map.as_ptr().cast(), size - 1, format, flags);
743 if ptr.is_null() {
744 Ok(None)
745 } else {
746 Ok(Some(Keymap { ptr }))
747 }
748 }
749
750 /// Get the compiled keymap as a string.
751 ///
752 /// keymap The keymap to get as a string.
753 /// format The keymap format to use for the string. You can pass
754 /// in the special value `xkb::KEYMAP_USE_ORIGINAL_FORMAT` to use the format
755 /// from which the keymap was originally created.
756 ///
757 /// Returns The keymap as a NUL-terminated string, or `NULL` if unsuccessful.
758 ///
759 /// The returned string may be fed back into `xkb_map_new_from_string()` to get
760 /// the exact same keymap (possibly in another process, etc).
761 ///
762 /// The returned string is dynamically allocated and should be freed by the
763 /// caller.
764 #[must_use]
765 pub fn get_as_string(&self, format: KeymapFormat) -> String {
766 unsafe {
767 let ffistr = xkb_keymap_get_as_string(self.ptr, format);
768 let cstr = CStr::from_ptr(ffistr);
769 let res = String::from_utf8_unchecked(cstr.to_bytes().to_owned());
770 libc::free(ffistr.cast());
771 res
772 }
773 }
774
775 /// Get the minimum keycode in the keymap.
776 #[must_use]
777 pub fn min_keycode(&self) -> Keycode {
778 Keycode::new(unsafe { xkb_keymap_min_keycode(self.ptr) })
779 }
780
781 /// Get the maximum keycode in the keymap.
782 #[must_use]
783 pub fn max_keycode(&self) -> Keycode {
784 Keycode::new(unsafe { xkb_keymap_max_keycode(self.ptr) })
785 }
786
787 #[allow(unused_variables)]
788 unsafe extern "C" fn callback<F>(
789 pkeymap: *mut ffi::xkb_keymap,
790 key: ffi::xkb_keycode_t,
791 data: *mut raw::c_void,
792 ) where
793 F: FnMut(&Keymap, Keycode),
794 {
795 let mut data_box: Box<(&Keymap, F)> = mem::transmute(Box::from_raw(data));
796 {
797 let (keymap, ref mut closure) = *data_box;
798 closure(keymap, key.into());
799 }
800 let _ = Box::into_raw(data_box);
801 }
802
803 /// Run a specified closure for every valid keycode in the keymap.
804 pub fn key_for_each<F>(&self, closure: F)
805 where
806 F: FnMut(&Keymap, Keycode),
807 {
808 let data_box = Box::new((self, closure));
809 let data_ptr = Box::into_raw(data_box).cast();
810
811 unsafe {
812 ffi::xkb_keymap_key_for_each(self.get_raw_ptr(), Self::callback::<F>, data_ptr);
813 mem::drop(Box::from_raw(data_ptr.cast::<(&Keymap, F)>()));
814 }
815 }
816
817 /// Get an iterator to the modifiers of this keymap
818 #[must_use]
819 pub fn mods(&self) -> KeymapMods {
820 unsafe {
821 KeymapMods {
822 keymap: self,
823 ind: 0,
824 len: xkb_keymap_num_mods(self.ptr),
825 }
826 }
827 }
828
829 /// Get the number of modifiers in the keymap.
830 #[must_use]
831 pub fn num_mods(&self) -> ModIndex {
832 unsafe { xkb_keymap_num_mods(self.ptr) }
833 }
834
835 /// Get the name of a modifier by index.
836 ///
837 /// Returns The name. If the index is invalid, returns "".
838 #[must_use]
839 pub fn mod_get_name(&self, idx: ModIndex) -> &str {
840 unsafe {
841 let ptr = xkb_keymap_mod_get_name(self.ptr, idx);
842 if ptr.is_null() {
843 ""
844 } else {
845 let cstr = CStr::from_ptr(ptr);
846 str::from_utf8_unchecked(cstr.to_bytes())
847 }
848 }
849 }
850
851 /// Get the index of a modifier by name.
852 ///
853 /// Returns The index. If no modifier with this name exists, returns
854 /// `xkb::MOD_INVALID`.
855 #[allow(clippy::missing_panics_doc)]
856 pub fn mod_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> ModIndex {
857 unsafe {
858 let cstr = CString::new(name.borrow().as_bytes()).unwrap();
859 xkb_keymap_mod_get_index(self.ptr, cstr.as_ptr())
860 }
861 }
862
863 /// Returns an iterator to the layouts in this keymap
864 #[must_use]
865 pub fn layouts(&self) -> KeymapLayouts {
866 unsafe {
867 KeymapLayouts {
868 keymap: self,
869 ind: 0,
870 len: xkb_keymap_num_layouts(self.ptr),
871 }
872 }
873 }
874
875 /// Get the number of layouts in the keymap.
876 #[must_use]
877 pub fn num_layouts(&self) -> LayoutIndex {
878 unsafe { xkb_keymap_num_layouts(self.ptr) }
879 }
880
881 /// Get the name of a layout by index.
882 ///
883 /// Returns The name. If the index is invalid, or the layout does not have
884 /// a name, returns "".
885 #[must_use]
886 pub fn layout_get_name(&self, idx: LayoutIndex) -> &str {
887 unsafe {
888 let ptr = xkb_keymap_layout_get_name(self.ptr, idx);
889 if ptr.is_null() {
890 ""
891 } else {
892 let cstr = CStr::from_ptr(ptr);
893 str::from_utf8_unchecked(cstr.to_bytes())
894 }
895 }
896 }
897
898 /// Find the name of the key with the given keycode.
899 /// This function always returns the canonical name of the key (see description in [Keycode]).
900 pub fn key_get_name(&self, key: Keycode) -> Option<&str> {
901 unsafe {
902 let ptr = xkb_keymap_key_get_name(self.ptr, key.into());
903 if ptr.is_null() {
904 None
905 } else {
906 let cstr = CStr::from_ptr(ptr);
907 Some(str::from_utf8_unchecked(cstr.to_bytes()))
908 }
909 }
910 }
911
912 /// Find the keycode of the key with the given name.
913 /// The name can be either a canonical name or an alias.
914 pub fn key_by_name<S: Borrow<str> + ?Sized>(&self, name: &S) -> Option<Keycode> {
915 unsafe {
916 let cstr = CString::new(name.borrow().as_bytes()).unwrap();
917 let code = xkb_keymap_key_by_name(self.ptr, cstr.as_ptr());
918 if code == XKB_KEYCODE_INVALID {
919 None
920 } else {
921 Some(Keycode::new(code))
922 }
923 }
924 }
925
926 /// Get the index of a layout by name.
927 ///
928 /// Returns The index. If no layout exists with this name, returns
929 /// `xkb::LAYOUT_INVALID`. If more than one layout in the keymap has this name,
930 /// returns the lowest index among them.
931 #[allow(clippy::missing_panics_doc)]
932 pub fn layout_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> LayoutIndex {
933 unsafe {
934 let cstr = CString::new(name.borrow().as_bytes()).unwrap();
935 xkb_keymap_layout_get_index(self.ptr, cstr.as_ptr())
936 }
937 }
938
939 /// Returns an iterator to the leds in this keymap
940 #[must_use]
941 pub fn leds(&self) -> KeymapLeds {
942 unsafe {
943 KeymapLeds {
944 keymap: self,
945 ind: 0,
946 len: xkb_keymap_num_leds(self.ptr),
947 }
948 }
949 }
950
951 /// Get the number of LEDs in the keymap.
952 ///
953 /// # warning
954 /// The range `[0..num_leds())` includes all of the LEDs
955 /// in the keymap, but may also contain inactive LEDs. When iterating over
956 /// this range, you need the handle this case when calling functions such as
957 /// `led_get_name()` or `led_index_is_active()`.
958 #[must_use]
959 pub fn num_leds(&self) -> LedIndex {
960 unsafe { xkb_keymap_num_leds(self.ptr) }
961 }
962
963 /// Get the name of a LED by index.
964 ///
965 /// Returns the name. If the index is invalid, returns `""`.
966 #[must_use]
967 pub fn led_get_name(&self, idx: LedIndex) -> &str {
968 unsafe {
969 let ptr = xkb_keymap_led_get_name(self.ptr, idx);
970 if ptr.is_null() {
971 ""
972 } else {
973 let cstr = CStr::from_ptr(ptr);
974 str::from_utf8_unchecked(cstr.to_bytes())
975 }
976 }
977 }
978
979 /// Get the index of a LED by name.
980 ///
981 /// Returns The index. If no LED with this name exists, returns
982 /// `xkb::LED_INVALID`.
983 #[allow(clippy::missing_panics_doc)]
984 pub fn led_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> LedIndex {
985 unsafe {
986 let cstr = CString::new(name.borrow().as_bytes()).unwrap();
987 xkb_keymap_led_get_index(self.ptr, cstr.as_ptr())
988 }
989 }
990
991 /// Get the number of layouts for a specific key.
992 ///
993 /// This number can be different `from num_layouts()`, but is always
994 /// smaller. It is the appropriate value to use when iterating over the
995 /// layouts of a key.
996 #[must_use]
997 pub fn num_layouts_for_key(&self, key: Keycode) -> LayoutIndex {
998 unsafe { xkb_keymap_num_layouts_for_key(self.ptr, key.raw()) }
999 }
1000
1001 /// Get the number of shift levels for a specific key and layout.
1002 ///
1003 /// If layout is out of range for this key (that is, larger or equal to
1004 /// the value returned by `num_layouts_for_key()`), it is brought
1005 /// back into range in a manner consistent with `State::key_get_layout()`.
1006 #[must_use]
1007 pub fn num_levels_for_key(&self, key: Keycode, layout: LayoutIndex) -> LevelIndex {
1008 unsafe { xkb_keymap_num_levels_for_key(self.ptr, key.into(), layout) }
1009 }
1010
1011 /// Get the keysyms obtained from pressing a key in a given layout and
1012 /// shift level.
1013 ///
1014 /// This function is like `xkb_state_key_get_syms()`, only the layout and
1015 /// shift level are not derived from the keyboard state but are instead
1016 /// specified explicitly.
1017 ///
1018 /// If layout is out of range for this key (that is, larger or equal to
1019 /// the value returned by `num_layouts_for_key()`), it is brought
1020 /// back into range in a manner consistent with `State::key_get_layout()`.
1021 #[must_use]
1022 pub fn key_get_syms_by_level(
1023 &self,
1024 key: Keycode,
1025 layout: LayoutIndex,
1026 level: LevelIndex,
1027 ) -> &[Keysym] {
1028 unsafe {
1029 let mut syms_out: *const Keysym = null_mut();
1030 let len = xkb_keymap_key_get_syms_by_level(
1031 self.ptr,
1032 key.raw(),
1033 layout,
1034 level,
1035 &mut syms_out as *mut *const Keysym as *mut *const xkeysym::RawKeysym,
1036 );
1037 if syms_out.is_null() {
1038 &[]
1039 } else {
1040 slice::from_raw_parts(syms_out, len as usize)
1041 }
1042 }
1043 }
1044
1045 /// Determine whether a key should repeat or not.
1046 ///
1047 /// A keymap may specify different repeat behaviors for different keys.
1048 /// Most keys should generally exhibit repeat behavior; for example, holding
1049 /// the 'a' key down in a text editor should normally insert a single 'a'
1050 /// character every few milliseconds, until the key is released. However,
1051 /// there are keys which should not or do not need to be repeated. For
1052 /// example, repeating modifier keys such as Left/Right Shift or Caps Lock
1053 /// is not generally useful or desired.
1054 #[must_use]
1055 pub fn key_repeats(&self, key: Keycode) -> bool {
1056 unsafe { xkb_keymap_key_repeats(self.ptr, key.into()) != 0 }
1057 }
1058}
1059
1060impl Clone for Keymap {
1061 fn clone(&self) -> Keymap {
1062 unsafe {
1063 Keymap {
1064 ptr: xkb_keymap_ref(self.ptr),
1065 }
1066 }
1067 }
1068}
1069
1070impl Drop for Keymap {
1071 fn drop(&mut self) {
1072 unsafe {
1073 xkb_keymap_unref(self.ptr);
1074 }
1075 }
1076}
1077
1078/// iterator to the modifiers in a Keymap
1079pub struct KeymapMods<'a> {
1080 keymap: &'a Keymap,
1081 ind: ModIndex,
1082 len: ModIndex,
1083}
1084
1085impl<'a> Iterator for KeymapMods<'a> {
1086 type Item = &'a str;
1087 fn next(&mut self) -> Option<&'a str> {
1088 if self.ind == self.len {
1089 None
1090 } else {
1091 unsafe {
1092 let ptr: *const i8 = xkb_keymap_mod_get_name(self.keymap.ptr, self.ind);
1093 self.ind += 1;
1094 let cstr: &CStr = CStr::from_ptr(ptr);
1095 Some(str::from_utf8_unchecked(cstr.to_bytes()))
1096 }
1097 }
1098 }
1099}
1100
1101/// iterator to the layouts in Keymap
1102pub struct KeymapLayouts<'a> {
1103 keymap: &'a Keymap,
1104 ind: LayoutIndex,
1105 len: LayoutIndex,
1106}
1107
1108impl<'a> Iterator for KeymapLayouts<'a> {
1109 type Item = &'a str;
1110 fn next(&mut self) -> Option<&'a str> {
1111 if self.ind == self.len {
1112 None
1113 } else {
1114 unsafe {
1115 let ptr: *const i8 = xkb_keymap_layout_get_name(self.keymap.ptr, self.ind);
1116 self.ind += 1;
1117 let cstr: &CStr = CStr::from_ptr(ptr);
1118 Some(str::from_utf8_unchecked(cstr.to_bytes()))
1119 }
1120 }
1121 }
1122}
1123
1124/// iterator to the leds in a Keymap
1125pub struct KeymapLeds<'a> {
1126 keymap: &'a Keymap,
1127 ind: LedIndex,
1128 len: LedIndex,
1129}
1130
1131impl<'a> Iterator for KeymapLeds<'a> {
1132 type Item = &'a str;
1133 fn next(&mut self) -> Option<&'a str> {
1134 if self.ind == self.len {
1135 None
1136 } else {
1137 unsafe {
1138 let ptr: *const i8 = xkb_keymap_led_get_name(self.keymap.ptr, self.ind);
1139 self.ind += 1;
1140 let cstr: &CStr = CStr::from_ptr(ptr);
1141 Some(str::from_utf8_unchecked(cstr.to_bytes()))
1142 }
1143 }
1144 }
1145}
1146
1147/// Keyboard state object.
1148///
1149/// State objects contain the active state of a keyboard (or keyboards), such
1150/// as the currently effective layout and the active modifiers. It acts as a
1151/// simple state machine, wherein key presses and releases are the input, and
1152/// key symbols (keysyms) are the output.
1153pub struct State {
1154 ptr: *mut xkb_state,
1155}
1156
1157impl State {
1158 #[allow(clippy::missing_safety_doc)]
1159 pub unsafe fn from_raw_ptr(ptr: *mut xkb_state) -> State {
1160 State { ptr }
1161 }
1162
1163 #[must_use]
1164 pub fn get_raw_ptr(&self) -> *mut xkb_state {
1165 self.ptr
1166 }
1167
1168 /// Create a new keyboard state object from a keymap.
1169 #[must_use]
1170 pub fn new(keymap: &Keymap) -> State {
1171 unsafe {
1172 State {
1173 ptr: xkb_state_new(keymap.ptr),
1174 }
1175 }
1176 }
1177
1178 /// Get the keymap which a keyboard state object is using.
1179 ///
1180 /// Returns the keymap which was passed to `xkb_state_new()` when creating
1181 /// this state object.
1182 ///
1183 /// This keymap can safely be used beyond the lifetime of this state
1184 #[must_use]
1185 pub fn get_keymap(&self) -> Keymap {
1186 unsafe {
1187 let keymap = xkb_state_get_keymap(self.ptr);
1188 xkb_keymap_ref(keymap);
1189 Keymap::from_raw_ptr(keymap)
1190 }
1191 }
1192
1193 /// Update the keyboard state to reflect a given key being pressed or
1194 /// released.
1195 ///
1196 /// This entry point is intended for programs which track the keyboard state
1197 /// explictly (like an evdev client). If the state is serialized to you by
1198 /// a master process (like a Wayland compositor) using functions like
1199 /// `xkb_state_serialize_mods()`, you should use `xkb_state_update_mask()`
1200 /// instead. The two functins should not generally be used together.
1201 ///
1202 /// A series of calls to this function should be consistent; that is, a call
1203 /// with `xkb::KEY_DOWN` for a key should be matched by an `xkb::KEY_UP`; if
1204 /// a key is pressed twice, it should be released twice; etc. Otherwise (e.g.
1205 /// due to missed input events), situations like "stuck modifiers" may occur.
1206 ///
1207 /// This function is often used in conjunction with the function
1208 /// `xkb_state_key_get_syms()` (or `xkb_state_key_get_one_sym()`), for
1209 /// example, when handling a key event. In this case, you should prefer to
1210 /// get the keysyms *before* updating the key, such that the keysyms reported
1211 /// for the key event are not affected by the event itself. This is the
1212 /// conventional behavior.
1213 ///
1214 /// Returns A mask of state components that have changed as a result of
1215 /// the update. If nothing in the state has changed, returns 0.
1216 pub fn update_key(&mut self, key: Keycode, direction: KeyDirection) -> StateComponent {
1217 unsafe { xkb_state_update_key(self.ptr, key.into(), mem::transmute(direction)) }
1218 }
1219
1220 /// Update a keyboard state from a set of explicit masks.
1221 ///
1222 /// This entry point is intended for window systems and the like, where a
1223 /// master process holds an `xkb_state`, then serializes it over a wire
1224 /// protocol, and clients then use the serialization to feed in to their own
1225 /// `xkb_state`.
1226 ///
1227 /// All parameters must always be passed, or the resulting state may be
1228 /// incoherent.
1229 ///
1230 /// The serialization is lossy and will not survive round trips; it must only
1231 /// be used to feed slave state objects, and must not be used to update the
1232 /// master state.
1233 ///
1234 /// If you do not fit the description above, you should use
1235 /// `xkb_state_update_key()` instead. The two functions should not generally be
1236 /// used together.
1237 ///
1238 /// Returns a mask of state components that have changed as a result of
1239 /// the update. If nothing in the state has changed, returns 0.
1240 pub fn update_mask(
1241 &mut self,
1242 depressed_mods: ModMask,
1243 latched_mods: ModMask,
1244 locked_mods: ModMask,
1245 depressed_layout: LayoutIndex,
1246 latched_layout: LayoutIndex,
1247 locked_layout: LayoutIndex,
1248 ) -> StateComponent {
1249 unsafe {
1250 xkb_state_update_mask(
1251 self.ptr,
1252 depressed_mods,
1253 latched_mods,
1254 locked_mods,
1255 depressed_layout,
1256 latched_layout,
1257 locked_layout,
1258 )
1259 }
1260 }
1261
1262 /// Get the keysyms obtained from pressing a particular key in a given
1263 /// keyboard state.
1264 ///
1265 /// Get the keysyms for a key according to the current active layout,
1266 /// modifiers and shift level for the key, as determined by a keyboard
1267 /// state.
1268 ///
1269 /// # Arguments
1270 /// * `state`: The keyboard state object.
1271 /// * `key`: The keycode of the key.
1272 ///
1273 /// # Return
1274 /// * `syms_out`: An immutable array of keysyms corresponding the
1275 /// key in the given keyboard state.
1276 ///
1277 /// As an extension to XKB, this function can return more than one keysym.
1278 /// If you do not want to handle this case, you should use
1279 /// `xkb_state_key_get_one_sym()`, which additionally performs transformations
1280 /// which are specific to the one-keysym case.
1281 #[must_use]
1282 pub fn key_get_syms(&self, key: Keycode) -> &[Keysym] {
1283 unsafe {
1284 let mut syms_out: *const Keysym = null_mut();
1285 let len = xkb_state_key_get_syms(
1286 self.ptr,
1287 key.into(),
1288 &mut syms_out as *mut *const Keysym as *mut *const xkeysym::RawKeysym,
1289 );
1290 if syms_out.is_null() {
1291 &[]
1292 } else {
1293 slice::from_raw_parts(syms_out, len as usize)
1294 }
1295 }
1296 }
1297
1298 /// Get the Unicode/UTF-8 string obtained from pressing a particular key
1299 /// in a given keyboard state.
1300 #[must_use]
1301 pub fn key_get_utf8(&self, key: Keycode) -> String {
1302 unsafe {
1303 let buf: &mut [c_char] = &mut [0; 64];
1304 let ptr = &mut buf[0] as *mut c_char;
1305 let len = xkb_state_key_get_utf8(self.ptr, key.into(), ptr, 64);
1306 let slice: &[u8] = slice::from_raw_parts(ptr as *const _, len as usize);
1307 String::from_utf8_unchecked(slice.to_owned())
1308 }
1309 }
1310
1311 /// Get the Unicode/UTF-32 codepoint obtained from pressing a particular
1312 /// key in a a given keyboard state.
1313 ///
1314 /// Returns The UTF-32 representation for the key, if it consists of only
1315 /// a single codepoint. Otherwise, returns 0.
1316 #[must_use]
1317 pub fn key_get_utf32(&self, key: Keycode) -> u32 {
1318 unsafe { xkb_state_key_get_utf32(self.ptr, key.into()) }
1319 }
1320
1321 /// Get the single keysym obtained from pressing a particular key in a
1322 /// given keyboard state.
1323 ///
1324 /// This function is similar to `xkb_state_key_get_syms()`, but intended
1325 /// for users which cannot or do not want to handle the case where
1326 /// multiple keysyms are returned (in which case this function is
1327 /// preferred).
1328 ///
1329 /// Returns the keysym. If the key does not have exactly one keysym,
1330 /// returns `xkb::KEY_NoSymbol`.
1331 #[must_use]
1332 pub fn key_get_one_sym(&self, key: Keycode) -> Keysym {
1333 unsafe { xkb_state_key_get_one_sym(self.ptr, key.into()) }.into()
1334 }
1335
1336 /// Get the effective layout index for a key in a given keyboard state.
1337 ///
1338 /// Returns the layout index for the key in the given keyboard state. If
1339 /// the given keycode is invalid, or if the key is not included in any
1340 /// layout at all, returns `xkb::LAYOUT_INVALID`.
1341 #[must_use]
1342 pub fn key_get_layout(&self, key: Keycode) -> LayoutIndex {
1343 unsafe { xkb_state_key_get_layout(self.ptr, key.into()) }
1344 }
1345
1346 /// Get the effective shift level for a key in a given keyboard state and
1347 /// layout.
1348 ///
1349 /// Return the shift level index. If the key or layout are invalid,
1350 /// returns `xkb::LEVEL_INVALID`.
1351 #[must_use]
1352 pub fn key_get_level(&self, key: Keycode, layout: LayoutIndex) -> LevelIndex {
1353 unsafe { xkb_state_key_get_level(self.ptr, key.into(), layout) }
1354 }
1355
1356 /// The counterpart to `xkb_state_update_mask` for modifiers, to be used on
1357 /// the server side of serialization.
1358 ///
1359 /// State components other than `xkb::STATE_MODS_*` are ignored.
1360 /// If `xkb::STATE_MODS_EFFECTIVE` is included, all other state components are
1361 /// ignored.
1362 ///
1363 /// Returns a `ModMask` representing the given components of the
1364 /// modifier state.
1365 ///
1366 /// This function should not be used in regular clients; please use the
1367 /// `xkb::State::mod_*_is_active` API instead.
1368 #[must_use]
1369 pub fn serialize_mods(&self, components: StateComponent) -> ModMask {
1370 unsafe { xkb_state_serialize_mods(self.ptr, components) }
1371 }
1372
1373 #[must_use]
1374 pub fn serialize_layout(&self, components: StateComponent) -> LayoutIndex {
1375 unsafe { xkb_state_serialize_layout(self.ptr, components) }
1376 }
1377
1378 /// Test whether a modifier is active in a given keyboard state by name.
1379 #[allow(clippy::missing_panics_doc)]
1380 pub fn mod_name_is_active<S: Borrow<str> + ?Sized>(
1381 &self,
1382 name: &S,
1383 type_: StateComponent,
1384 ) -> bool {
1385 unsafe {
1386 let cname = CString::new(name.borrow().as_bytes()).unwrap();
1387 xkb_state_mod_name_is_active(self.ptr, cname.as_ptr(), type_) == 1
1388 }
1389 }
1390
1391 /// Test whether a modifier is active in a given keyboard state by index.
1392 #[must_use]
1393 pub fn mod_index_is_active(&self, idx: ModIndex, type_: StateComponent) -> bool {
1394 unsafe { xkb_state_mod_index_is_active(self.ptr, idx, type_) == 1 }
1395 }
1396
1397 /// Test whether a modifier is consumed by keyboard state translation for
1398 /// a key.
1399 ///
1400 /// Some functions, like `xkb_state_key_get_syms()`, look at the state of
1401 /// the modifiers in the keymap and derive from it the correct shift level
1402 /// to use for the key. For example, in a US layout, pressing the key
1403 /// labeled \<A\> while the Shift modifier is active, generates the keysym 'A'.
1404 /// In this case, the Shift modifier is said to be consumed. However, the
1405 /// Num Lock modifier does not affect this translation at all, even if it
1406 /// active, so it is not consumed by this translation.
1407 ///
1408 /// It may be desirable for some application to not reuse consumed modifiers
1409 /// for further processing, e.g. for hotkeys or keyboard shortcuts. To
1410 /// understand why, consider some requirements from a standard shortcut
1411 /// mechanism, and how they are implemented:
1412 ///
1413 /// 1. The shortcut's modifiers must match exactly to the state. For example,
1414 /// it is possible to bind separate actions to \<Alt\>\<Tab\> and to
1415 /// \<Alt\>\<Shift\>\<Tab\>. Further, if only \<Alt\>\<Tab\> is bound to
1416 /// an action, pressing \<Alt\>\<Shift\>\<Tab\> should not trigger the
1417 /// shortcut.
1418 /// Effectively, this means that the modifiers are compared using the
1419 /// equality operator (==).
1420 /// 2. Only relevant modifiers are considered for the matching. For example,
1421 /// Caps Lock and Num Lock should not generally affect the matching, e.g.
1422 /// when matching \<Alt\>\<Tab\> against the state, it does not matter
1423 /// whether Num Lock is active or not. These relevant, or significant,
1424 /// modifiers usually include Alt, Control, Shift, Super and similar.
1425 /// Effectively, this means that non-significant modifiers are masked out,
1426 /// before doing the comparison as described above.
1427 /// 3. The matching must be independent of the layout/keymap. For example,
1428 /// the \<Plus\> (+) symbol is found on the first level on some layouts,
1429 /// and requires holding Shift on others. If you simply bind the action
1430 /// to the \<Plus\> keysym, it would work for the unshifted kind, but
1431 /// not for the others, because the match against Shift would fail. If
1432 /// you bind the action to \<Shift\>\<Plus\>, only the shifted kind would
1433 /// work. So what is needed is to recognize that Shift is used up in the
1434 /// translation of the keysym itself, and therefore should not be included
1435 /// in the matching.
1436 /// Effectively, this means that consumed modifiers (Shift in this example)
1437 /// are masked out as well, before doing the comparison.
1438 ///
1439 /// `state_modifiers` are the modifiers reported by
1440 /// `xkb::State::mod_index_is_active()` and similar functions.
1441 /// `consumed_modifiers` are the modifiers reported by
1442 /// `xkb::State::mod_index_is_consumed()`.
1443 /// `significant_modifiers` are decided upon by the application/toolkit/user;
1444 /// it is up to them to decide whether these are configurable or hard-coded.
1445 #[must_use]
1446 pub fn mod_index_is_consumed(&self, key: Keycode, idx: ModIndex) -> bool {
1447 unsafe { xkb_state_mod_index_is_consumed(self.ptr, key.into(), idx) == 1 }
1448 }
1449
1450 /// Remove consumed modifiers from a modifier mask for a key.
1451 ///
1452 /// Takes the given modifier mask, and removes all modifiers which are
1453 /// consumed for that particular key (as in `xkb_state_mod_index_is_consumed()`).
1454 #[must_use]
1455 pub fn mod_mask_remove_consumed(&self, key: Keycode, mask: ModMask) -> ModMask {
1456 unsafe { xkb_state_mod_mask_remove_consumed(self.ptr, key.into(), mask) }
1457 }
1458
1459 /// Get the mask of modifiers consumed by translating a given key.
1460 ///
1461 /// Returns a mask of the consumed modifiers.
1462 #[must_use]
1463 pub fn key_get_consumed_mods(&self, key: Keycode) -> ModMask {
1464 unsafe { xkb_state_key_get_consumed_mods(self.ptr, key.into()) }
1465 }
1466
1467 /// Test whether a layout is active in a given keyboard state by name.
1468 ///
1469 /// If multiple layouts in the keymap have this name, the one with the lowest
1470 /// index is tested.
1471 #[allow(clippy::missing_panics_doc)]
1472 pub fn layout_name_is_active<S: Borrow<str> + ?Sized>(
1473 &self,
1474 name: &S,
1475 type_: StateComponent,
1476 ) -> bool {
1477 unsafe {
1478 let cname = CString::new(name.borrow().as_bytes()).unwrap();
1479 xkb_state_layout_name_is_active(self.ptr, cname.as_ptr(), type_) != 0
1480 }
1481 }
1482
1483 /// Test whether a layout is active in a given keyboard state by index.
1484 #[must_use]
1485 pub fn layout_index_is_active(&self, idx: LayoutIndex, type_: StateComponent) -> bool {
1486 unsafe { xkb_state_layout_index_is_active(self.ptr, idx, type_) != 0 }
1487 }
1488
1489 /// Test whether a LED is active in a given keyboard state by name.
1490 #[allow(clippy::missing_panics_doc)]
1491 pub fn led_name_is_active<S: Borrow<str> + ?Sized>(&self, name: &S) -> bool {
1492 unsafe {
1493 let cname = CString::new(name.borrow().as_bytes()).unwrap();
1494 xkb_state_led_name_is_active(self.ptr, cname.as_ptr()) != 0
1495 }
1496 }
1497
1498 /// Test whether a LED is active in a given keyboard state by index.
1499 #[must_use]
1500 pub fn led_index_is_active(&self, idx: LedIndex) -> bool {
1501 unsafe { xkb_state_led_index_is_active(self.ptr, idx) != 0 }
1502 }
1503}
1504
1505impl Clone for State {
1506 fn clone(&self) -> State {
1507 unsafe {
1508 State {
1509 ptr: xkb_state_ref(self.ptr),
1510 }
1511 }
1512 }
1513}
1514
1515impl Drop for State {
1516 fn drop(&mut self) {
1517 unsafe {
1518 xkb_state_unref(self.ptr);
1519 }
1520 }
1521}
1522