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
13pub use x11::keysym;
15pub type FunctionCall = fn() -> ();
17
18const IGNORED_MOD_MASK: c_uint = xlib::LockMask | xlib::Mod2Mask | xlib::Mod3Mask;
19
20#[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#[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
64impl 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 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 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 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
173unsafe 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}