keyfn 0.2.1

call function on keypress/release
Documentation
extern crate x11;
extern crate fnv;

use x11::xlib;
use x11::xlib::{Display, Window, KeySym, XEvent};

use std::ptr;
use std::thread;
use std::os::raw::{c_int, c_uint};

use fnv::FnvHashMap;

/// X11 keysyms used as keycode for KeyBind
pub use x11::keysym;
/// Functoin to execute on KeyBind
pub type FunctionCall = fn() -> ();

const IGNORED_MOD_MASK: c_uint = xlib::LockMask | xlib::Mod2Mask | xlib::Mod3Mask;

/// readable modifier values instead of X11 representation
#[repr(u32)]
#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq, Clone, Copy)]
pub enum Mod{
    Alt =           xlib::Mod1Mask,
    NumLock =       xlib::Mod2Mask,
    ScrollLock =    xlib::Mod3Mask,
    Windows =       xlib::Mod4Mask,
    Mod5 =          xlib::Mod5Mask,
    Control =       xlib::ControlMask,
    Shift =         xlib::ShiftMask,
    CapsLock =      xlib::LockMask,
}

/// Enum for trigger event of function call
#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub enum Trigger{
    Pressed,
    Released,
}

#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
struct KeyBindMask{
    keycode:    KeySym,
    mod_mask:    c_uint,
}


#[derive(Debug)]
pub struct KeyBind{
    pub keycode:    KeySym,
    pub mods:       Vec<Mod>, 
    pub trigger:    Trigger,
    pub function:   FunctionCall,   
}

#[derive(Debug)]
pub struct KeyStorage{
    pressed:    FnvHashMap<KeyBindMask, FunctionCall>,
    released:   FnvHashMap<KeyBindMask, FunctionCall>,
    display:    *mut Display,
    root:       Window,
}

/*
*   Implementation
*/
impl KeyBind{
    pub fn new(
        keycode: u32,
        mut mods: Vec<Mod>,
        trigger: Trigger,
        function: FunctionCall,
    ) -> Self{

        mods.dedup();
        mods.sort();

        KeyBind{
            keycode: keycode as xlib::KeySym,
            mods: mods,
            trigger: trigger,
            function: function,
        }
    }
}

impl KeyBindMask{
    fn new(
        keycode: KeySym,
        mod_mask: c_uint,
    ) -> Self{
        KeyBindMask{
            keycode: keycode,
            mod_mask: mod_mask,
        }
    }
}

impl KeyStorage{
    /// create empty KeyStorage
    pub fn new() -> Self{
        unsafe{
            let display = get_display();
            let root = get_root(display);

            KeyStorage{
                pressed: FnvHashMap::default(),
                released: FnvHashMap::default(),
                display: display,
                root: root,
            }
        }
    }

    /// add new KeyBind to storage
    pub fn add(
        &mut self,
        keybind: KeyBind
    ){
        unsafe{
            grab_key(self.display, self.root, &keybind);
        }

        if keybind.trigger == Trigger::Pressed {
            for mask in create_bind_mask(&keybind){
                self.pressed.insert(mask, keybind.function);
            }
        }   else{
            for mask in create_bind_mask(&keybind){
                self.released.insert(mask, keybind.function);
            }
        }
    }

    fn action(
        &mut self,
        event: &mut XEvent
    ){
        let key = get_keysym_from_keycode(event.as_mut());    
        let xkeyevent = unsafe { event.key };

        if xkeyevent.type_ == xlib::KeyPress {
            
            if let Some(call) = self.pressed.get(&KeyBindMask::new(key, xkeyevent.state)){
                let call = call.to_owned();
                thread::spawn(move || {
                    call();
                });
            }
        } else if xkeyevent.type_ == xlib::KeyRelease {

            if let Some(call) = self.released.get(&KeyBindMask::new(key, xkeyevent.state)){
                let call = call.to_owned();
                thread::spawn(move || {
                    call();
                });
            }
        }
    }

    /// start grabbing and executing functions in new thread
    pub fn start(&mut self) {
        let mut event = xlib::XEvent { pad: [0; 24] };
        loop {
            unsafe {
                xlib::XNextEvent(self.display, &mut event);
            }
            self.action(&mut event);
        }
    }
}

/*
*   Utility
*/
unsafe fn grab_key(
    display: *mut Display,
    root: Window,
    key: &KeyBind
){
    let keycode = xlib::XKeysymToKeycode(display, key.keycode) as c_int;

    for mask in create_mod_mask(&key.mods) {
        xlib::XGrabKey(display,
                       keycode as c_int,
                       mask,
                       root,
                       true as c_int,
                       xlib::GrabModeAsync,
                       xlib::GrabModeAsync);
    }
}

fn get_keysym_from_keycode(press: &mut xlib::XKeyEvent) -> xlib::KeySym {
    unsafe {
        xlib::XLookupKeysym(press as *mut _, 0) 
    }
}

fn create_mod_mask(mods: &Vec<Mod>) -> Vec<c_uint> {
    let mut mod_mask;

    if mods.is_empty(){
        mod_mask = xlib::AnyModifier;
    } else {
        mod_mask = 0;

        for mask in mods {
            mod_mask |= *mask as u32;
        }
    }

    let mut ignored_mask = 0;
    let mut out = Vec::new();

    while ignored_mask <= IGNORED_MOD_MASK {
        if (ignored_mask & !IGNORED_MOD_MASK) > 0 {
            ignored_mask += 1;
            continue;
        }

        out.push(mod_mask | ignored_mask);
        ignored_mask += 1;
    }

    return out;
}

fn create_bind_mask(keybind: &KeyBind) -> Vec<KeyBindMask> {
    let mut out = Vec::new();

    for mask in create_mod_mask(&keybind.mods){
        out.push(KeyBindMask::new(keybind.keycode, mask));
    }

    return out;
}

unsafe fn get_display() -> *mut xlib::Display {
    xlib::XOpenDisplay(ptr::null())
}

unsafe fn get_root(display: *mut xlib::Display) -> xlib::Window {
    xlib::XDefaultRootWindow(display)
}