#![warn(clippy::all)]
#![allow(
clippy::similar_names,
clippy::wildcard_imports,
clippy::cast_sign_loss,
clippy::too_many_arguments
)]
pub mod compose;
pub mod ffi;
pub mod keysyms;
#[cfg(feature = "x11")]
pub mod x11;
pub use self::compose::*;
use crate::xkb::ffi::*;
pub use crate::xkb::keysyms::*;
#[cfg(feature = "wayland")]
use memmap2::MmapOptions;
#[cfg(feature = "wayland")]
use std::os::unix::io::{FromRawFd, RawFd};
use libc::{self, c_char, c_int, c_uint};
use std::borrow::Borrow;
use std::ffi::{CStr, CString};
use std::fs;
use std::io::Read;
use std::iter::Iterator;
use std::mem;
use std::os::raw;
use std::path::Path;
use std::ptr::{null, null_mut};
use std::slice;
use std::str;
pub type Keycode = u32;
pub type Keysym = u32;
pub type LayoutIndex = u32;
pub type LayoutMask = u32;
pub type LevelIndex = u32;
pub type ModIndex = u32;
pub type ModMask = u32;
pub type LedIndex = u32;
pub type LedMask = u32;
pub const KEYCODE_INVALID: u32 = 0xffff_ffff;
pub const LAYOUT_INVALID: u32 = 0xffff_ffff;
pub const LEVEL_INVALID: u32 = 0xffff_ffff;
pub const MOD_INVALID: u32 = 0xffff_ffff;
pub const LED_INVALID: u32 = 0xffff_ffff;
pub const KEYCODE_MAX: u32 = 0xffff_fffe;
pub type KeysymFlags = u32;
pub const KEYSYM_NO_FLAGS: u32 = 0;
pub const KEYSYM_CASE_INSENSITIVE: u32 = 1 << 0;
pub type ContextFlags = u32;
pub const CONTEXT_NO_FLAGS: u32 = 0;
pub const CONTEXT_NO_DEFAULT_INCLUDES: u32 = 1 << 0;
pub const CONTEXT_NO_ENVIRONMENT_NAMES: u32 = 1 << 1;
#[repr(C)]
pub enum LogLevel {
Critical = 10,
Error = 20,
Warning = 30,
Info = 40,
Debug = 50,
}
pub type KeymapCompileFlags = u32;
pub const KEYMAP_COMPILE_NO_FLAGS: u32 = 0;
pub type KeymapFormat = u32;
pub const KEYMAP_FORMAT_TEXT_V1: u32 = 1;
pub const KEYMAP_FORMAT_USE_ORIGINAL: u32 = 0xffff_ffff;
#[repr(C)]
pub enum KeyDirection {
Up,
Down,
}
pub type StateComponent = u32;
pub const STATE_MODS_DEPRESSED: u32 = 1 << 0;
pub const STATE_MODS_LATCHED: u32 = 1 << 1;
pub const STATE_MODS_LOCKED: u32 = 1 << 2;
pub const STATE_MODS_EFFECTIVE: u32 = 1 << 3;
pub const STATE_LAYOUT_DEPRESSED: u32 = 1 << 4;
pub const STATE_LAYOUT_LATCHED: u32 = 1 << 5;
pub const STATE_LAYOUT_LOCKED: u32 = 1 << 6;
pub const STATE_LAYOUT_EFFECTIVE: u32 = 1 << 7;
pub const STATE_LEDS: u32 = 1 << 8;
pub type StateMatch = u32;
pub const STATE_MATCH_ANY: u32 = 1 << 0;
pub const STATE_MATCH_ALL: u32 = 1 << 1;
pub const STATE_MATCH_NON_EXCLUSIVE: u32 = 1 << 16;
pub const MOD_NAME_SHIFT: &str = "Shift";
pub const MOD_NAME_CAPS: &str = "Lock";
pub const MOD_NAME_CTRL: &str = "Control";
pub const MOD_NAME_ALT: &str = "Mod1";
pub const MOD_NAME_NUM: &str = "Mod2";
pub const MOD_NAME_LOGO: &str = "Mod4";
pub const LED_NAME_CAPS: &str = "Caps Lock";
pub const LED_NAME_NUM: &str = "Num Lock";
pub const LED_NAME_SCROLL: &str = "Scroll Lock";
#[must_use]
pub fn keycode_is_legal_ext(key: u32) -> bool {
key <= KEYCODE_MAX
}
#[must_use]
pub fn keycode_is_legal_x11(key: u32) -> bool {
(8..=255).contains(&key)
}
#[must_use]
pub fn keysym_get_name(keysym: Keysym) -> String {
unsafe {
let buf: &mut [c_char] = &mut [0; 64];
let ptr = &mut buf[0] as *mut c_char;
let len = xkb_keysym_get_name(keysym, ptr, 64);
let slice: &[u8] = slice::from_raw_parts(ptr as *const _, len as usize);
String::from_utf8_unchecked(slice.to_owned())
}
}
#[allow(clippy::missing_panics_doc)]
#[must_use]
pub fn keysym_from_name(name: &str, flags: KeysymFlags) -> Keysym {
unsafe {
let cname = CString::new(name.as_bytes().to_owned()).unwrap();
xkb_keysym_from_name(cname.as_ptr(), flags)
}
}
#[must_use]
pub fn keysym_to_utf8(keysym: Keysym) -> String {
unsafe {
let buf: &mut [c_char] = &mut [0; 8];
let ptr = &mut buf[0] as *mut c_char;
let len = xkb_keysym_to_utf8(keysym, ptr, 8);
let slice: &[u8] = slice::from_raw_parts(ptr as *const _, len as usize);
String::from_utf8_unchecked(slice.to_owned())
}
}
#[must_use]
pub fn keysym_to_utf32(keysym: Keysym) -> u32 {
unsafe { xkb_keysym_to_utf32(keysym) }
}
pub struct Context {
ptr: *mut xkb_context,
}
impl Context {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn from_raw_ptr(ptr: *mut xkb_context) -> Context {
Context { ptr }
}
#[must_use]
pub fn get_raw_ptr(&self) -> *mut xkb_context {
self.ptr
}
#[must_use]
pub fn new(flags: ContextFlags) -> Context {
unsafe {
Context {
ptr: xkb_context_new(flags),
}
}
}
pub fn include_path_append(&mut self, path: &Path) -> bool {
path.to_str().map_or(false, |s| unsafe {
let cstr = CString::from_vec_unchecked(s.as_bytes().to_owned());
xkb_context_include_path_append(self.ptr, cstr.as_ptr()) == 1
})
}
pub fn include_path_append_default(&mut self) -> bool {
unsafe { xkb_context_include_path_append_default(self.ptr) == 1 }
}
pub fn include_path_reset_defaults(&mut self) -> bool {
unsafe { xkb_context_include_path_reset_defaults(self.ptr) == 1 }
}
pub fn include_path_clear(&mut self) {
unsafe {
xkb_context_include_path_clear(self.ptr);
}
}
#[must_use]
pub fn include_paths(&self) -> ContextIncludePaths {
unsafe {
ContextIncludePaths {
context: self,
ind: 0,
len: xkb_context_num_include_paths(self.ptr),
}
}
}
pub fn set_log_level(&mut self, level: LogLevel) {
unsafe {
xkb_context_set_log_level(self.ptr, mem::transmute(level));
}
}
#[must_use]
pub fn get_log_level(&self) -> LogLevel {
unsafe { mem::transmute(xkb_context_get_log_level(self.ptr)) }
}
pub fn set_log_verbosity(&mut self, verbosity: i32) {
unsafe {
xkb_context_set_log_verbosity(self.ptr, verbosity as c_int);
}
}
#[must_use]
pub fn get_log_verbosity(&self) -> i32 {
unsafe { xkb_context_get_log_verbosity(self.ptr) as i32 }
}
}
impl Clone for Context {
fn clone(&self) -> Context {
unsafe {
Context {
ptr: xkb_context_ref(self.ptr),
}
}
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
xkb_context_unref(self.ptr);
}
}
}
pub struct ContextIncludePaths<'a> {
context: &'a Context,
ind: c_uint,
len: c_uint,
}
impl<'a> Iterator for ContextIncludePaths<'a> {
type Item = &'a Path;
fn next(&mut self) -> Option<&'a Path> {
if self.ind == self.len {
None
} else {
unsafe {
let ptr = xkb_context_include_path_get(self.context.ptr, self.ind);
self.ind += 1;
let cstr = CStr::from_ptr(ptr);
Some(Path::new(str::from_utf8_unchecked(cstr.to_bytes())))
}
}
}
}
#[test]
fn check_include_paths() {
let mut c = Context::new(CONTEXT_NO_DEFAULT_INCLUDES);
let test_path = Path::new("/");
assert_eq!(true, c.include_path_append(&test_path));
assert_eq!(test_path, c.include_paths().nth(0).unwrap());
}
pub struct Keymap {
ptr: *mut xkb_keymap,
}
impl Keymap {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn from_raw_ptr(ptr: *mut xkb_keymap) -> Keymap {
Keymap { ptr }
}
#[must_use]
pub fn get_raw_ptr(&self) -> *mut xkb_keymap {
self.ptr
}
#[allow(clippy::missing_panics_doc)]
pub fn new_from_names<S: Borrow<str> + ?Sized>(
context: &Context,
rules: &S,
model: &S,
layout: &S,
variant: &S,
mut options: Option<String>,
flags: KeymapCompileFlags,
) -> Option<Keymap> {
let crules = CString::new(rules.borrow().as_bytes()).unwrap();
let cmodel = CString::new(model.borrow().as_bytes()).unwrap();
let clayout = CString::new(layout.borrow().as_bytes()).unwrap();
let cvariant = CString::new(variant.borrow().as_bytes()).unwrap();
let poptions = match &mut options {
None => null(),
Some(s) => {
s.push('\0');
s.as_ptr().cast()
}
};
let rule_names = xkb_rule_names {
rules: crules.as_ptr(),
model: cmodel.as_ptr(),
layout: clayout.as_ptr(),
variant: cvariant.as_ptr(),
options: poptions,
};
unsafe {
let pkeymap = xkb_keymap_new_from_names(context.ptr, &rule_names, flags);
if pkeymap.is_null() {
None
} else {
Some(Keymap { ptr: pkeymap })
}
}
}
pub fn new_from_file(
context: &Context,
file: &mut fs::File,
format: KeymapFormat,
flags: KeymapCompileFlags,
) -> Option<Keymap> {
let mut string = String::new();
file.read_to_string(&mut string)
.ok()
.and_then(|_| Keymap::new_from_string(context, string, format, flags))
}
#[allow(clippy::missing_panics_doc)]
#[must_use]
pub fn new_from_string(
context: &Context,
string: String,
format: KeymapFormat,
flags: KeymapCompileFlags,
) -> Option<Keymap> {
unsafe {
let cstr = CString::new(string.into_bytes()).unwrap();
let ptr = xkb_keymap_new_from_string(context.ptr, cstr.as_ptr(), format, flags);
if ptr.is_null() {
None
} else {
Some(Keymap { ptr })
}
}
}
#[cfg(feature = "wayland")]
#[allow(clippy::missing_panics_doc)]
pub unsafe fn new_from_fd(
context: &Context,
fd: RawFd,
size: usize,
format: KeymapFormat,
flags: KeymapCompileFlags,
) -> std::io::Result<Option<Keymap>> {
let map = MmapOptions::new()
.len(size as usize)
.map_copy_read_only(&fs::File::from_raw_fd(fd))?;
let ptr =
xkb_keymap_new_from_buffer(context.ptr, map.as_ptr().cast(), size - 1, format, flags);
if ptr.is_null() {
Ok(None)
} else {
Ok(Some(Keymap { ptr }))
}
}
#[must_use]
pub fn get_as_string(&self, format: KeymapFormat) -> String {
unsafe {
let ffistr = xkb_keymap_get_as_string(self.ptr, format);
let cstr = CStr::from_ptr(ffistr);
let res = String::from_utf8_unchecked(cstr.to_bytes().to_owned());
libc::free(ffistr.cast());
res
}
}
#[must_use]
pub fn min_keycode(&self) -> Keycode {
unsafe { xkb_keymap_min_keycode(self.ptr) }
}
#[must_use]
pub fn max_keycode(&self) -> Keycode {
unsafe { xkb_keymap_max_keycode(self.ptr) }
}
#[allow(unused_variables)]
unsafe extern "C" fn callback<F>(
pkeymap: *mut ffi::xkb_keymap,
key: ffi::xkb_keycode_t,
data: *mut raw::c_void,
) where
F: FnMut(&Keymap, Keycode),
{
let mut data_box: Box<(&Keymap, F)> = mem::transmute(Box::from_raw(data));
{
let (keymap, ref mut closure) = *data_box;
closure(keymap, key as Keycode);
}
let _ = Box::into_raw(data_box);
}
pub fn key_for_each<F>(&self, closure: F)
where
F: FnMut(&Keymap, Keycode),
{
let data_box = Box::new((self, closure));
let data_ptr = Box::into_raw(data_box).cast();
unsafe {
ffi::xkb_keymap_key_for_each(self.get_raw_ptr(), Self::callback::<F>, data_ptr);
mem::drop(Box::from_raw(data_ptr.cast::<(&Keymap, F)>()));
}
}
#[must_use]
pub fn mods(&self) -> KeymapMods {
unsafe {
KeymapMods {
keymap: self,
ind: 0,
len: xkb_keymap_num_mods(self.ptr),
}
}
}
#[must_use]
pub fn num_mods(&self) -> ModIndex {
unsafe { xkb_keymap_num_mods(self.ptr) }
}
#[must_use]
pub fn mod_get_name(&self, idx: ModIndex) -> &str {
unsafe {
let ptr = xkb_keymap_mod_get_name(self.ptr, idx);
if ptr.is_null() {
""
} else {
let cstr = CStr::from_ptr(ptr);
str::from_utf8_unchecked(cstr.to_bytes())
}
}
}
#[allow(clippy::missing_panics_doc)]
pub fn mod_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> ModIndex {
unsafe {
let cstr = CString::new(name.borrow().as_bytes()).unwrap();
xkb_keymap_mod_get_index(self.ptr, cstr.as_ptr())
}
}
#[must_use]
pub fn layouts(&self) -> KeymapLayouts {
unsafe {
KeymapLayouts {
keymap: self,
ind: 0,
len: xkb_keymap_num_layouts(self.ptr),
}
}
}
#[must_use]
pub fn num_layouts(&self) -> LayoutIndex {
unsafe { xkb_keymap_num_layouts(self.ptr) }
}
#[must_use]
pub fn layout_get_name(&self, idx: LayoutIndex) -> &str {
unsafe {
let ptr = xkb_keymap_layout_get_name(self.ptr, idx);
if ptr.is_null() {
""
} else {
let cstr = CStr::from_ptr(ptr);
str::from_utf8_unchecked(cstr.to_bytes())
}
}
}
pub fn key_get_name(&self, key: Keycode) -> Option<&str> {
unsafe {
let ptr = xkb_keymap_key_get_name(self.ptr, key);
if ptr.is_null() {
None
} else {
let cstr = CStr::from_ptr(ptr);
Some(str::from_utf8_unchecked(cstr.to_bytes()))
}
}
}
pub fn key_by_name<S: Borrow<str> + ?Sized>(&self, name: &S) -> Option<Keycode> {
unsafe {
let cstr = CString::new(name.borrow().as_bytes()).unwrap();
let code = xkb_keymap_key_by_name(self.ptr, cstr.as_ptr());
if code == XKB_KEYCODE_INVALID {
None
} else {
Some(code)
}
}
}
#[allow(clippy::missing_panics_doc)]
pub fn layout_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> LayoutIndex {
unsafe {
let cstr = CString::new(name.borrow().as_bytes()).unwrap();
xkb_keymap_layout_get_index(self.ptr, cstr.as_ptr())
}
}
#[must_use]
pub fn leds(&self) -> KeymapLeds {
unsafe {
KeymapLeds {
keymap: self,
ind: 0,
len: xkb_keymap_num_leds(self.ptr),
}
}
}
#[must_use]
pub fn num_leds(&self) -> LedIndex {
unsafe { xkb_keymap_num_leds(self.ptr) }
}
#[must_use]
pub fn led_get_name(&self, idx: LedIndex) -> &str {
unsafe {
let ptr = xkb_keymap_led_get_name(self.ptr, idx);
if ptr.is_null() {
""
} else {
let cstr = CStr::from_ptr(ptr);
str::from_utf8_unchecked(cstr.to_bytes())
}
}
}
#[allow(clippy::missing_panics_doc)]
pub fn led_get_index<S: Borrow<str> + ?Sized>(&self, name: &S) -> LedIndex {
unsafe {
let cstr = CString::new(name.borrow().as_bytes()).unwrap();
xkb_keymap_led_get_index(self.ptr, cstr.as_ptr())
}
}
#[must_use]
pub fn num_layouts_for_key(&self, key: Keycode) -> LayoutIndex {
unsafe { xkb_keymap_num_layouts_for_key(self.ptr, key) }
}
#[must_use]
pub fn num_levels_for_key(&self, key: Keycode, layout: LayoutIndex) -> LevelIndex {
unsafe { xkb_keymap_num_levels_for_key(self.ptr, key, layout) }
}
#[must_use]
pub fn key_get_syms_by_level(
&self,
key: Keycode,
layout: LayoutIndex,
level: LevelIndex,
) -> &[Keysym] {
unsafe {
let mut syms_out: *const Keysym = null_mut();
let len = xkb_keymap_key_get_syms_by_level(self.ptr, key, layout, level, &mut syms_out);
if syms_out.is_null() {
&[]
} else {
slice::from_raw_parts(syms_out, len as usize)
}
}
}
#[must_use]
pub fn key_repeats(&self, key: Keycode) -> bool {
unsafe { xkb_keymap_key_repeats(self.ptr, key) != 0 }
}
}
impl Clone for Keymap {
fn clone(&self) -> Keymap {
unsafe {
Keymap {
ptr: xkb_keymap_ref(self.ptr),
}
}
}
}
impl Drop for Keymap {
fn drop(&mut self) {
unsafe {
xkb_keymap_unref(self.ptr);
}
}
}
pub struct KeymapMods<'a> {
keymap: &'a Keymap,
ind: ModIndex,
len: ModIndex,
}
impl<'a> Iterator for KeymapMods<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
if self.ind == self.len {
None
} else {
unsafe {
let ptr = xkb_keymap_mod_get_name(self.keymap.ptr, self.ind);
self.ind += 1;
let cstr = CStr::from_ptr(ptr);
Some(str::from_utf8_unchecked(cstr.to_bytes()))
}
}
}
}
pub struct KeymapLayouts<'a> {
keymap: &'a Keymap,
ind: LayoutIndex,
len: LayoutIndex,
}
impl<'a> Iterator for KeymapLayouts<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
if self.ind == self.len {
None
} else {
unsafe {
let ptr = xkb_keymap_layout_get_name(self.keymap.ptr, self.ind);
self.ind += 1;
let cstr = CStr::from_ptr(ptr);
Some(str::from_utf8_unchecked(cstr.to_bytes()))
}
}
}
}
pub struct KeymapLeds<'a> {
keymap: &'a Keymap,
ind: LedIndex,
len: LedIndex,
}
impl<'a> Iterator for KeymapLeds<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
if self.ind == self.len {
None
} else {
unsafe {
let ptr = xkb_keymap_led_get_name(self.keymap.ptr, self.ind);
self.ind += 1;
let cstr = CStr::from_ptr(ptr);
Some(str::from_utf8_unchecked(cstr.to_bytes()))
}
}
}
}
pub struct State {
ptr: *mut xkb_state,
}
impl State {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn from_raw_ptr(ptr: *mut xkb_state) -> State {
State { ptr }
}
#[must_use]
pub fn get_raw_ptr(&self) -> *mut xkb_state {
self.ptr
}
#[must_use]
pub fn new(keymap: &Keymap) -> State {
unsafe {
State {
ptr: xkb_state_new(keymap.ptr),
}
}
}
#[must_use]
pub fn get_keymap(&self) -> Keymap {
unsafe {
let keymap = xkb_state_get_keymap(self.ptr);
xkb_keymap_ref(keymap);
Keymap::from_raw_ptr(keymap)
}
}
pub fn update_key(&mut self, key: Keycode, direction: KeyDirection) -> StateComponent {
unsafe { xkb_state_update_key(self.ptr, key, mem::transmute(direction)) }
}
pub fn update_mask(
&mut self,
depressed_mods: ModMask,
latched_mods: ModMask,
locked_mods: ModMask,
depressed_layout: LayoutIndex,
latched_layout: LayoutIndex,
locked_layout: LayoutIndex,
) -> StateComponent {
unsafe {
xkb_state_update_mask(
self.ptr,
depressed_mods,
latched_mods,
locked_mods,
depressed_layout,
latched_layout,
locked_layout,
)
}
}
#[must_use]
pub fn key_get_syms(&self, key: Keycode) -> &[Keysym] {
unsafe {
let mut syms_out: *const Keysym = null_mut();
let len = xkb_state_key_get_syms(self.ptr, key, &mut syms_out);
if syms_out.is_null() {
&[]
} else {
slice::from_raw_parts(syms_out, len as usize)
}
}
}
#[must_use]
pub fn key_get_utf8(&self, key: Keycode) -> String {
unsafe {
let buf: &mut [c_char] = &mut [0; 64];
let ptr = &mut buf[0] as *mut c_char;
let len = xkb_state_key_get_utf8(self.ptr, key, ptr, 64);
let slice: &[u8] = slice::from_raw_parts(ptr as *const _, len as usize);
String::from_utf8_unchecked(slice.to_owned())
}
}
#[must_use]
pub fn key_get_utf32(&self, key: Keycode) -> u32 {
unsafe { xkb_state_key_get_utf32(self.ptr, key) }
}
#[must_use]
pub fn key_get_one_sym(&self, key: Keycode) -> Keysym {
unsafe { xkb_state_key_get_one_sym(self.ptr, key) }
}
#[must_use]
pub fn key_get_layout(&self, key: Keycode) -> LayoutIndex {
unsafe { xkb_state_key_get_layout(self.ptr, key) }
}
#[must_use]
pub fn key_get_level(&self, key: Keycode, layout: LayoutIndex) -> LevelIndex {
unsafe { xkb_state_key_get_level(self.ptr, key, layout) }
}
#[must_use]
pub fn serialize_mods(&self, components: StateComponent) -> ModMask {
unsafe { xkb_state_serialize_mods(self.ptr, components) }
}
#[must_use]
pub fn serialize_layout(&self, components: StateComponent) -> LayoutIndex {
unsafe { xkb_state_serialize_layout(self.ptr, components) }
}
#[allow(clippy::missing_panics_doc)]
pub fn mod_name_is_active<S: Borrow<str> + ?Sized>(
&self,
name: &S,
type_: StateComponent,
) -> bool {
unsafe {
let cname = CString::new(name.borrow().as_bytes()).unwrap();
xkb_state_mod_name_is_active(self.ptr, cname.as_ptr(), type_) == 1
}
}
#[must_use]
pub fn mod_index_is_active(&self, idx: ModIndex, type_: StateComponent) -> bool {
unsafe { xkb_state_mod_index_is_active(self.ptr, idx, type_) == 1 }
}
#[must_use]
pub fn mod_index_is_consumed(&self, key: Keycode, idx: ModIndex) -> bool {
unsafe { xkb_state_mod_index_is_consumed(self.ptr, key, idx) == 1 }
}
#[must_use]
pub fn mod_mask_remove_consumed(&self, key: Keycode, mask: ModMask) -> ModMask {
unsafe { xkb_state_mod_mask_remove_consumed(self.ptr, key, mask) }
}
#[must_use]
pub fn key_get_consumed_mods(&self, key: Keycode) -> ModMask {
unsafe { xkb_state_key_get_consumed_mods(self.ptr, key) }
}
#[allow(clippy::missing_panics_doc)]
pub fn layout_name_is_active<S: Borrow<str> + ?Sized>(
&self,
name: &S,
type_: StateComponent,
) -> bool {
unsafe {
let cname = CString::new(name.borrow().as_bytes()).unwrap();
xkb_state_layout_name_is_active(self.ptr, cname.as_ptr(), type_) != 0
}
}
#[must_use]
pub fn layout_index_is_active(&self, idx: LayoutIndex, type_: StateComponent) -> bool {
unsafe { xkb_state_layout_index_is_active(self.ptr, idx, type_) != 0 }
}
#[allow(clippy::missing_panics_doc)]
pub fn led_name_is_active<S: Borrow<str> + ?Sized>(&self, name: &S) -> bool {
unsafe {
let cname = CString::new(name.borrow().as_bytes()).unwrap();
xkb_state_led_name_is_active(self.ptr, cname.as_ptr()) != 0
}
}
#[must_use]
pub fn led_index_is_active(&self, idx: LedIndex) -> bool {
unsafe { xkb_state_led_index_is_active(self.ptr, idx) != 0 }
}
}
impl Clone for State {
fn clone(&self) -> State {
unsafe {
State {
ptr: xkb_state_ref(self.ptr),
}
}
}
}
impl Drop for State {
fn drop(&mut self) {
unsafe {
xkb_state_unref(self.ptr);
}
}
}