pub mod ffi;
#[cfg(feature = "x11")]
pub mod x11;
pub mod keysyms;
pub use xkb::keysyms::*;
use xkb::ffi::*;
use libc::{self, c_int, c_uint, c_char, c_void};
use std::ffi::{CStr, CString};
use std::ptr::{null, null_mut};
use std::str;
use std::slice;
use std::mem;
use std::fs;
use std::io::Read;
use std::iter::Iterator;
use std::path::{Path};
use std::borrow::Borrow;
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 = 0xffffffff;
pub const LAYOUT_INVALID :u32 = 0xffffffff;
pub const LEVEL_INVALID :u32 = 0xffffffff;
pub const MOD_INVALID :u32 = 0xffffffff;
pub const LED_INVALID :u32 = 0xffffffff;
pub const KEYCODE_MAX :u32 = 0xfffffffe;
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 = 0xffffffff;
#[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: &'static str = "Shift";
pub const MOD_NAME_CAPS: &'static str = "Lock";
pub const MOD_NAME_CTRL: &'static str = "Control";
pub const MOD_NAME_ALT: &'static str = "Mod1";
pub const MOD_NAME_NUM: &'static str = "Mod2";
pub const MOD_NAME_LOGO: &'static str = "Mod4";
pub const LED_NAME_CAPS: &'static str = "Caps Lock";
pub const LED_NAME_NUM: &'static str = "Num Lock";
pub const LED_NAME_SCROLL: &'static str = "Scroll Lock";
pub fn keycode_is_legal_ext(key: u32) -> bool {
key <= KEYCODE_MAX
}
pub fn keycode_is_legal_x11(key: u32) -> bool {
key >= 8 && key <= 255
}
pub fn keysym_get_name(keysym: Keysym) -> String {
unsafe {
let mut 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(
mem::transmute(ptr), len as usize);
String::from_utf8_unchecked(slice.to_owned())
}
}
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)
}
}
pub fn keysym_to_utf8(keysym: Keysym) -> String {
unsafe {
let mut 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(
mem::transmute(ptr), len as usize);
String::from_utf8_unchecked(slice.to_owned())
}
}
pub fn keysym_to_utf32(keysym: Keysym) -> u32 {
unsafe { xkb_keysym_to_utf32(keysym) }
}
pub struct Context {
ptr: *mut xkb_context
}
impl Context {
pub unsafe fn from_raw_ptr(ptr: *mut xkb_context) -> Context {
Context {
ptr: ptr
}
}
pub fn get_raw_ptr(&self) -> *mut xkb_context {
self.ptr
}
pub fn new(flags: ContextFlags) -> Context {
unsafe {
Context {
ptr: xkb_context_new(flags)
}
}
}
pub fn include_path_append(&mut self, path: &Path) -> bool {
if let Some(s) = path.to_str() {
unsafe {
let cstr = CString::from_vec_unchecked(
s.as_bytes().to_owned()
);
if xkb_context_include_path_append(
self.ptr, cstr.as_ptr()) == 1 {
true
}
else {
false
}
}
}
else {
false
}
}
pub fn include_path_append_default(&mut self) -> bool {
unsafe {
if xkb_context_include_path_append_default(self.ptr) == 1 {
true
}
else {
false
}
}
}
pub fn include_path_reset_defaults(&mut self) -> bool {
unsafe {
if xkb_context_include_path_reset_defaults(self.ptr) == 1 {
true
}
else {
false
}
}
}
pub fn include_path_clear(&mut self) {
unsafe {
xkb_context_include_path_clear(self.ptr);
}
}
pub fn include_paths<'a>(&'a self) -> ContextIncludePaths<'a> {
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));
}
}
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);
}
}
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 {
pub unsafe fn from_raw_ptr(ptr: *mut xkb_keymap) -> Keymap {
Keymap {
ptr: ptr
}
}
pub fn get_raw_ptr(&self) -> *mut xkb_keymap {
self.ptr
}
pub fn new_from_names<S: Borrow<str>>(context: &Context,
rules: &S,
model: &S,
layout: &S,
variant: &S,
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 options {
None => (CString::new(Vec::new()).unwrap(), null()),
Some(s) => {
let coptions = CString::new(s.into_bytes()).unwrap();
let poptions = coptions.as_ptr();
(coptions, poptions)
}
};
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();
if let Ok(_) = file.read_to_string(&mut string) {
Keymap::new_from_string(&context, string, format, flags)
}
else {
None
}
}
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: ptr} )
}
}
}
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 as *mut c_void);
res
}
}
pub fn min_keycode(&self) -> Keycode {
unsafe {
xkb_keymap_min_keycode(self.ptr)
}
}
pub fn max_keycode(&self) -> Keycode {
unsafe {
xkb_keymap_max_keycode(self.ptr)
}
}
pub fn mods<'a>(&'a self) -> KeymapMods<'a> {
unsafe {
KeymapMods {
keymap: &self, ind: 0,
len: xkb_keymap_num_mods(self.ptr)
}
}
}
pub fn num_mods(&self) -> ModIndex {
unsafe {
xkb_keymap_num_mods(self.ptr)
}
}
pub fn mod_get_name<'a>(&'a self, idx: ModIndex) -> &'a str {
unsafe {
let ptr = xkb_keymap_mod_get_name(self.ptr, idx);
if !ptr.is_null() {
let cstr = CStr::from_ptr(ptr);
str::from_utf8_unchecked(cstr.to_bytes())
} else {
""
}
}
}
pub fn mod_get_index<S: Borrow<str>>(&self, name: &S) -> ModIndex {
unsafe {
let cstr = CString::new(name.borrow().as_bytes()).unwrap();
xkb_keymap_mod_get_index(self.ptr, cstr.as_ptr())
}
}
pub fn layouts<'a>(&'a self) -> KeymapLayouts<'a> {
unsafe {
KeymapLayouts {
keymap: &self, ind: 0,
len: xkb_keymap_num_layouts(self.ptr)
}
}
}
pub fn num_layouts(&self) -> LayoutIndex {
unsafe {
xkb_keymap_num_layouts(self.ptr)
}
}
pub fn layout_get_name<'a>(&'a self, idx: LayoutIndex) -> &'a str {
unsafe {
let ptr = xkb_keymap_layout_get_name(self.ptr, idx);
if !ptr.is_null() {
let cstr = CStr::from_ptr(ptr);
str::from_utf8_unchecked(cstr.to_bytes())
} else {
""
}
}
}
pub fn layout_get_index<S: Borrow<str>>(&self, name: &S) -> LayoutIndex {
unsafe {
let cstr = CString::new(name.borrow().as_bytes()).unwrap();
xkb_keymap_layout_get_index(self.ptr, cstr.as_ptr())
}
}
pub fn leds<'a>(&'a self) -> KeymapLeds<'a> {
unsafe {
KeymapLeds {
keymap: &self, ind: 0,
len: xkb_keymap_num_leds(self.ptr)
}
}
}
pub fn num_leds(&self) -> LedIndex {
unsafe {
xkb_keymap_num_leds(self.ptr)
}
}
pub fn led_get_name<'a>(&'a self, idx: LedIndex) -> &'a str {
unsafe {
let ptr = xkb_keymap_led_get_name(self.ptr, idx);
if !ptr.is_null() {
let cstr = CStr::from_ptr(ptr);
str::from_utf8_unchecked(cstr.to_bytes())
} else {
""
}
}
}
pub fn led_get_index<S: Borrow<str>>(&self, name: &S) -> LedIndex {
unsafe {
let cstr = CString::new(name.borrow().as_bytes()).unwrap();
xkb_keymap_led_get_index(self.ptr, cstr.as_ptr())
}
}
pub fn num_layouts_for_key(&self, key: Keycode) -> LayoutIndex {
unsafe {
xkb_keymap_num_layouts_for_key(self.ptr, key)
}
}
pub fn num_levels_for_key(&self, key: Keycode) -> LevelIndex {
unsafe {
xkb_keymap_num_levels_for_key(self.ptr, key)
}
}
pub fn key_get_syms_by_level<'a>(&'a self, key: Keycode,
layout: LayoutIndex,
level: LevelIndex)
-> &'a [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)
}
}
}
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 {
pub unsafe fn from_raw_ptr(ptr: *mut xkb_state) -> State {
State {
ptr: ptr
}
}
pub fn get_raw_ptr(&self) -> *mut xkb_state {
self.ptr
}
pub fn new(keymap: &Keymap) -> State {
unsafe {
State {
ptr: xkb_state_new(keymap.ptr)
}
}
}
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)
}
}
pub fn key_get_syms<'a>(&'a self, key: Keycode)
-> &'a [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)
}
}
}
pub fn key_get_utf8(&self, key: Keycode) -> String {
unsafe {
let mut 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(
mem::transmute(ptr), len as usize);
String::from_utf8_unchecked(slice.to_owned())
}
}
pub fn key_get_utf32(&self, key: Keycode) -> u32 {
unsafe {
xkb_state_key_get_utf32(self.ptr, key)
}
}
pub fn key_get_one_sym(&self, key: Keycode) -> Keysym {
unsafe {
xkb_state_key_get_one_sym(self.ptr, key)
}
}
pub fn key_get_layout(&self, key: Keycode) -> LayoutIndex {
unsafe {
xkb_state_key_get_layout(self.ptr, key)
}
}
pub fn key_get_level(&self, key: Keycode, layout: LayoutIndex)
-> LevelIndex {
unsafe {
xkb_state_key_get_level(self.ptr, key, layout)
}
}
pub fn serialize_mods(&self, components: StateComponent) -> ModMask {
unsafe {
xkb_state_serialize_mods(self.ptr, components)
}
}
pub fn serialize_layout(&self, components: StateComponent) -> LayoutIndex {
unsafe {
xkb_state_serialize_layout(self.ptr, components)
}
}
pub fn mod_name_is_active<S: Borrow<str>>(&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
}
}
pub fn mod_index_is_active(&self, idx: ModIndex, type_: StateComponent)
-> bool {
unsafe {
xkb_state_mod_index_is_active(self.ptr, idx, type_) == 1
}
}
pub fn mod_index_is_consumed(&self, key: Keycode, idx: ModIndex)
-> bool {
unsafe {
xkb_state_mod_index_is_consumed(self.ptr, key, idx) == 1
}
}
pub fn mod_mask_remove_consumed(&self, key: Keycode, mask: ModMask)
-> ModMask {
unsafe {
xkb_state_mod_mask_remove_consumed(self.ptr, key, mask)
}
}
pub fn key_get_consumed_mods(&self, key: Keycode)
-> ModMask {
unsafe {
xkb_state_key_get_consumed_mods(self.ptr, key)
}
}
pub fn layout_name_is_active<S: Borrow<str>>(&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
}
}
pub fn layout_index_is_active(&self, idx: LayoutIndex,
type_: StateComponent)
-> bool {
unsafe {
xkb_state_layout_index_is_active(self.ptr, idx, type_) != 0
}
}
pub fn led_name_is_active<S: Borrow<str>>(&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
}
}
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);
}
}
}