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
92
93
94
95
96
97
98
#![warn(
    clippy::complexity,
    clippy::correctness,
    clippy::perf,
    clippy::style,
    missing_docs,
    rust_2018_idioms
)]
#![cfg_attr(not(feature = "std"), no_std)]

//! `livesplit-hotkey` is a crate that allows listening to hotkeys even when the
//! application is not in focus. The crate currently supports Windows, macOS,
//! Linux and the web via wasm-bindgen. On unsupported platforms the crate still
//! compiles but uses a stubbed out implementation instead that never receives
//! any hotkeys.

extern crate alloc;

cfg_if::cfg_if! {
    if #[cfg(not(feature = "std"))] {
        mod other;
        use self::other as platform;
    } else if #[cfg(windows)] {
        mod windows;
        use self::windows as platform;
    } else if #[cfg(target_os = "linux")] {
        mod linux;
        use self::linux as platform;
    } else if #[cfg(target_os = "macos")] {
        #[macro_use]
        extern crate objc;
        mod macos;
        use self::macos as platform;
    } else if #[cfg(all(target_arch = "wasm32", target_os = "unknown", feature = "wasm-web"))] {
        mod wasm_web;
        use self::wasm_web as platform;
    } else {
        mod other;
        use self::other as platform;
    }
}

mod hotkey;
mod key_code;
mod modifiers;
pub use self::{hotkey::*, key_code::*, modifiers::*, platform::*};

#[cfg(test)]
mod tests {
    use std::{thread, time::Duration};

    use super::*;

    #[test]
    fn test() {
        let hook = Hook::new().unwrap();

        hook.register(KeyCode::Numpad1.with_modifiers(Modifiers::SHIFT), || {
            println!("A")
        })
        .unwrap();
        println!("Press Shift + Numpad1");
        thread::sleep(Duration::from_secs(5));
        hook.unregister(KeyCode::Numpad1.with_modifiers(Modifiers::SHIFT))
            .unwrap();

        hook.register(KeyCode::KeyN.into(), || println!("B"))
            .unwrap();
        println!("Press KeyN");
        thread::sleep(Duration::from_secs(5));
        hook.unregister(KeyCode::KeyN.into()).unwrap();

        hook.register(KeyCode::Numpad1.into(), || println!("C"))
            .unwrap();
        println!("Press Numpad1");
        thread::sleep(Duration::from_secs(5));
        hook.unregister(KeyCode::Numpad1.into()).unwrap();
    }

    #[test]
    fn resolve() {
        let hook = Hook::new().unwrap();

        // Based on German keyboard layout.
        println!("ß: {}", KeyCode::Minus.resolve(&hook));
        println!("ü: {}", KeyCode::BracketLeft.resolve(&hook));
        println!("#: {}", KeyCode::Backslash.resolve(&hook));
        println!("+: {}", KeyCode::BracketRight.resolve(&hook));
        println!("z: {}", KeyCode::KeyY.resolve(&hook));
        println!("^: {}", KeyCode::Backquote.resolve(&hook));
        println!("<: {}", KeyCode::IntlBackslash.resolve(&hook));
        println!("Yen: {}", KeyCode::IntlYen.resolve(&hook));
        println!("Enter: {}", KeyCode::Enter.resolve(&hook));
        println!("Space: {}", KeyCode::Space.resolve(&hook));
        println!("Tab: {}", KeyCode::Tab.resolve(&hook));
        println!("Numpad0: {}", KeyCode::Numpad0.resolve(&hook));
    }
}