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
//! # What this crate provides
//!
//! This Windows-only crate provides safe and correct means to listen for keyboard and mouse events regardless of application focus.
//! The application can be CLI or with a Window.
//!
//! Under the hood the crate leverages the **WI**ndows **L**ow-**L**evel **HOOK**s.
//! You can read more about that topic on [MSDN](https://learn.microsoft.com/en-us/windows/win32/winmsg/about-hooks?redirectedfrom=MSDN).
//!
//! The crate was created for learning-purposes mostly and for my hobby project, but we will see where it goes.
//!
//! The design goals for this crate are to be: correct, misuse-proof and fail-proof.
//! Having that in mind, the implementation follows best effort to avoid any panic.
//! In the worst case, it should just return incomplete input event (e.g. with missing keyboard key code).
//!
//! ### What this crate does NOT provide
//!
//! This crate is intended for "read-only" access to hooks. It does not support injecting input events or altering them.
//! If you are looking for that kind of functionality, you can give [mki](https://crates.io/crates/mki) a try.
//! In comparison, the mki crate supports also Linux, but does not cleanup the low-level hooks (by [unhooking them](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-unhookwindowshookex)) and threads behind them (by [joinging with them](https://doc.rust-lang.org/std/thread/struct.JoinHandle.html#method.join)).
//! This *may* not be an issue for you. The addition of "injecting" and "altering" input events to [willhook] is a possibility, although it is not top priority.
//!
//! # Warning: The current state
//!
//! Currently it supports listening to mouse and keyboard actions, see [event] module for details.
//! There is no fancy logic to interpret the events - with this crate you can just received them and do what you want with that information.
//! In that aspect, I consider it feature complete.
//! There are integration tests that should cover all realistic scenarios.
//! There are also some unit tests covering less realistic cases, when Windows OS would send invalid input.
//! I think the crate is rather well tested, but still, keep in mind that the crate is also "young".
//! Note: the integration tests inject mouse and keyboard events, also they need to be run sequentially (no multi-threading).
//! There are some tests that do not pass on GitHub Actions and are ignored.
//! With that in mind, run the tests with `cargo test --tests -- --test-threads=1 --include-ignored`.
//! *It is highly recommended to at least quickly review the code before using this crate for anything more then hobby projects, at least at the current state.*
//!
//! TODO:
//! - document unsafe code before I forget all the quirks :-)
//! - maybe write more unit tests
//! - maybe improve the crate partitioning to modules (without breaking the API)
//! - maybe rework underlying channels, so that they are dropped with the hook (now they are just drained)
//! - maybe add injecting events
//! - maybe add blocking events, if even possible
//! - maybe add manipulating events, if even possible
//! - maybe add information about time of the event
//!
//! # How it works
//!
//! In short, there are a few handy functions to request a hook: [keyboard_hook], [mouse_hook] and [willhook].
//! When called they:
//! - start background thread(s) for each low-level hook, and in that thread(s):
//! - register a mouse and/or keyboard low-level hook(s)
//! - start Windows message queue and wait for the message to end execution
//! - create, if were not created already, the channels for passing events to "client" thread
//! - return the handle to the underlying low-level hooks as [hook::Hook]
//!
//! When the [hook::Hook] goes out of scope, the underlying resources supporting low-level hooks are dropped:
//! - each of the underlying low-level hooks is unhooked from the Windows Kernel
//! - each of the background threads is properly joined
//! - all pending events are dropped (background channels are drained)
//!
//! When the [hook::Hook] is active (in scope / not dropped).
//! Then one can receive recorded [event::InputEvent]s via [hook::Hook::try_recv].
//! It works similiarly to [std::sync::mpsc::Receiver::try_recv].
//!
//! # Optional features
//!
//! ## Serde support
//!
//! To enable [serde](https://crates.io/crates/serde) support, add willhook with "serde" feature to your cargo.toml:
//!
//! `willhook = { version = "^0.6.2", features = ["serde"]}`
pub use Hook;
pub use HookBuilder;
pub use *;
/// Return the Keyboard Hook handle. For more details see [Hook] and [HookBuilder]
/// Return the Mouse Hook handle. For more details see [Hook] and [HookBuilder]
/// Return the handle for both mouse and keyboard hook. For more details see [Hook] and [HookBuilder]