1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::collections::HashMap;
use std::mem;
use std::os::raw::c_ulong;
use std::ptr;
use x11_dl::xlib;

pub mod modifiers {
    use x11_dl::xlib;
    pub const ALT: u32 = xlib::Mod1Mask;
    pub const CONTROL: u32 = xlib::ControlMask;
    pub const SHIFT: u32 = xlib::ShiftMask;
    pub const SUPER: u32 = xlib::Mod4Mask;
}

pub type ListenerID = (i32, u32);

pub struct Listener {
    display: *mut xlib::Display,
    root: c_ulong,
    xlib: xlib::Xlib,
    handlers: HashMap<ListenerID, Box<dyn Fn()>>,
}

impl Listener {
    pub fn new() -> Listener {
        let xlib = xlib::Xlib::open().unwrap();
        unsafe {
            let display = (xlib.XOpenDisplay)(ptr::null());

            // Only trigger key release at end of repeated keys
            let mut supported_rtrn: i32 = mem::MaybeUninit::uninit().assume_init();
            (xlib.XkbSetDetectableAutoRepeat)(display, 1, &mut supported_rtrn);

            Listener {
                display: display,
                root: (xlib.XDefaultRootWindow)(display),
                xlib,
                handlers: HashMap::new(),
            }
        }
    }

    pub fn register_hotkey<CB: 'static + Fn()>(
        &mut self,
        modifiers: u32,
        key: u32,
        handler: CB,
    ) -> Result<ListenerID, String> {
        unsafe {
            let keycode = (self.xlib.XKeysymToKeycode)(self.display, key as u64) as i32;
            let result = (self.xlib.XGrabKey)(
                self.display,
                keycode,
                modifiers,
                self.root,
                0,
                xlib::GrabModeAsync,
                xlib::GrabModeAsync,
            );

            if result == 0 {
                return Err("Failed to register hotkey".to_string());
            }

            let id = (keycode, modifiers);
            self.handlers.insert(id, Box::new(handler));
            Ok(id)
        }
    }

    pub fn listen(self) {
        unsafe {
            (self.xlib.XSelectInput)(self.display, self.root, xlib::KeyReleaseMask);
            let mut event: xlib::XEvent = mem::MaybeUninit::uninit().assume_init();
            loop {
                (self.xlib.XNextEvent)(self.display, &mut event);
                match event.get_type() {
                    xlib::KeyRelease => {
                        if let Some(handler) = self
                            .handlers
                            .get(&(event.key.keycode as i32, event.key.state))
                        {
                            handler();
                        }
                    }
                    _ => (),
                }
            }
        }
    }
}