Skip to main content

keyfn/
lib.rs

1extern crate x11;
2extern crate fnv;
3
4use x11::xlib;
5use x11::xlib::{Display, Window, KeySym, XEvent};
6
7use std::ptr;
8use std::thread;
9use std::os::raw::{c_int, c_uint};
10
11use fnv::FnvHashMap;
12
13/// X11 keysyms used as keycode for KeyBind
14pub use x11::keysym;
15/// Functoin to execute on KeyBind
16pub type FunctionCall = fn() -> ();
17
18const IGNORED_MOD_MASK: c_uint = xlib::LockMask | xlib::Mod2Mask | xlib::Mod3Mask;
19
20/// readable modifier values instead of X11 representation
21#[repr(u32)]
22#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq, Clone, Copy)]
23pub enum Mod{
24    Alt =           xlib::Mod1Mask,
25    NumLock =       xlib::Mod2Mask,
26    ScrollLock =    xlib::Mod3Mask,
27    Windows =       xlib::Mod4Mask,
28    Mod5 =          xlib::Mod5Mask,
29    Control =       xlib::ControlMask,
30    Shift =         xlib::ShiftMask,
31    CapsLock =      xlib::LockMask,
32}
33
34/// Enum for trigger event of function call
35#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
36pub enum Trigger{
37    Pressed,
38    Released,
39}
40
41#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
42struct KeyBindMask{
43    keycode:    KeySym,
44    mod_mask:    c_uint,
45}
46
47
48#[derive(Debug)]
49pub struct KeyBind{
50    pub keycode:    KeySym,
51    pub mods:       Vec<Mod>, 
52    pub trigger:    Trigger,
53    pub function:   FunctionCall,   
54}
55
56#[derive(Debug)]
57pub struct KeyStorage{
58    pressed:    FnvHashMap<KeyBindMask, FunctionCall>,
59    released:   FnvHashMap<KeyBindMask, FunctionCall>,
60    display:    *mut Display,
61    root:       Window,
62}
63
64/*
65*   Implementation
66*/
67impl KeyBind{
68    pub fn new(
69        keycode: u32,
70        mut mods: Vec<Mod>,
71        trigger: Trigger,
72        function: FunctionCall,
73    ) -> Self{
74
75        mods.dedup();
76        mods.sort();
77
78        KeyBind{
79            keycode: keycode as xlib::KeySym,
80            mods: mods,
81            trigger: trigger,
82            function: function,
83        }
84    }
85}
86
87impl KeyBindMask{
88    fn new(
89        keycode: KeySym,
90        mod_mask: c_uint,
91    ) -> Self{
92        KeyBindMask{
93            keycode: keycode,
94            mod_mask: mod_mask,
95        }
96    }
97}
98
99impl KeyStorage{
100    /// create empty KeyStorage
101    pub fn new() -> Self{
102        unsafe{
103            let display = get_display();
104            let root = get_root(display);
105
106            KeyStorage{
107                pressed: FnvHashMap::default(),
108                released: FnvHashMap::default(),
109                display: display,
110                root: root,
111            }
112        }
113    }
114
115    /// add new KeyBind to storage
116    pub fn add(
117        &mut self,
118        keybind: KeyBind
119    ){
120        unsafe{
121            grab_key(self.display, self.root, &keybind);
122        }
123
124        if keybind.trigger == Trigger::Pressed {
125            for mask in create_bind_mask(&keybind){
126                self.pressed.insert(mask, keybind.function);
127            }
128        }   else{
129            for mask in create_bind_mask(&keybind){
130                self.released.insert(mask, keybind.function);
131            }
132        }
133    }
134
135    fn action(
136        &mut self,
137        event: &mut XEvent
138    ){
139        let key = get_keysym_from_keycode(event.as_mut());    
140        let xkeyevent = unsafe { event.key };
141
142        if xkeyevent.type_ == xlib::KeyPress {
143            
144            if let Some(call) = self.pressed.get(&KeyBindMask::new(key, xkeyevent.state)){
145                let call = call.to_owned();
146                thread::spawn(move || {
147                    call();
148                });
149            }
150        } else if xkeyevent.type_ == xlib::KeyRelease {
151
152            if let Some(call) = self.released.get(&KeyBindMask::new(key, xkeyevent.state)){
153                let call = call.to_owned();
154                thread::spawn(move || {
155                    call();
156                });
157            }
158        }
159    }
160
161    /// start grabbing and executing functions in new thread
162    pub fn start(&mut self) {
163        let mut event = xlib::XEvent { pad: [0; 24] };
164        loop {
165            unsafe {
166                xlib::XNextEvent(self.display, &mut event);
167            }
168            self.action(&mut event);
169        }
170    }
171}
172
173/*
174*   Utility
175*/
176unsafe fn grab_key(
177    display: *mut Display,
178    root: Window,
179    key: &KeyBind
180){
181    let keycode = xlib::XKeysymToKeycode(display, key.keycode) as c_int;
182
183    for mask in create_mod_mask(&key.mods) {
184        xlib::XGrabKey(display,
185                       keycode as c_int,
186                       mask,
187                       root,
188                       true as c_int,
189                       xlib::GrabModeAsync,
190                       xlib::GrabModeAsync);
191    }
192}
193
194fn get_keysym_from_keycode(press: &mut xlib::XKeyEvent) -> xlib::KeySym {
195    unsafe {
196        xlib::XLookupKeysym(press as *mut _, 0) 
197    }
198}
199
200fn create_mod_mask(mods: &Vec<Mod>) -> Vec<c_uint> {
201    let mut mod_mask;
202
203    if mods.is_empty(){
204        mod_mask = xlib::AnyModifier;
205    } else {
206        mod_mask = 0;
207
208        for mask in mods {
209            mod_mask |= *mask as u32;
210        }
211    }
212
213    let mut ignored_mask = 0;
214    let mut out = Vec::new();
215
216    while ignored_mask <= IGNORED_MOD_MASK {
217        if (ignored_mask & !IGNORED_MOD_MASK) > 0 {
218            ignored_mask += 1;
219            continue;
220        }
221
222        out.push(mod_mask | ignored_mask);
223        ignored_mask += 1;
224    }
225
226    return out;
227}
228
229fn create_bind_mask(keybind: &KeyBind) -> Vec<KeyBindMask> {
230    let mut out = Vec::new();
231
232    for mask in create_mod_mask(&keybind.mods){
233        out.push(KeyBindMask::new(keybind.keycode, mask));
234    }
235
236    return out;
237}
238
239unsafe fn get_display() -> *mut xlib::Display {
240    xlib::XOpenDisplay(ptr::null())
241}
242
243unsafe fn get_root(display: *mut xlib::Display) -> xlib::Window {
244    xlib::XDefaultRootWindow(display)
245}