├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── examples ├── event_based_print_keys.rs ├── event_based_print_mouse.rs ├── print_keys.rs └── print_mouse.rs └── src ├── device_events ├── callback │ ├── callback_guard.rs │ ├── keyboard_callback.rs │ ├── mod.rs │ └── mouse_callback.rs ├── event_loop.rs ├── mod.rs └── utils.rs ├── device_query.rs ├── device_state ├── linux │ ├── kernel_key.rs │ └── mod.rs ├── macos │ └── mod.rs ├── mod.rs └── windows │ └── mod.rs ├── keymap.rs ├── lib.rs └── mouse_state.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEs auto-generated files 2 | .idea 3 | 4 | # Cargo files 5 | /target/ 6 | **/*.rs.bk 7 | Cargo.lock 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | cache: cargo 3 | matrix: 4 | include: 5 | - os: linux 6 | rust: stable 7 | env: TARGET=x86_64_unknown_linux_gnu 8 | - os: linux 9 | rust: nightly 10 | env: TARGET=x86_64_unknown_linux_gnu 11 | 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "device_query" 3 | version = "3.0.1" 4 | authors = ["ostrosco "] 5 | build = "build.rs" 6 | description = "A basic library for querying keyboard and mouse state on-demand without a window." 7 | homepage = "https://github.com/ostrosco/device_query" 8 | repository = "https://github.com/ostrosco/device_query" 9 | readme = "README.md" 10 | keywords = ["input", "mouse", "keyboard"] 11 | license = "MIT" 12 | 13 | [badges] 14 | travis-ci = { repository = "ostrosco/device_query" } 15 | 16 | [build-dependencies] 17 | pkg-config = "0.3.26" 18 | 19 | [dependencies] 20 | 21 | [target.'cfg(target_os = "linux")'.dependencies] 22 | x11 = {version = "2.21.0", features = ["xlib"] } 23 | 24 | [target.'cfg(target_os = "windows")'.dependencies] 25 | windows = {version = "0.48.0", features = ["Win32_UI_Input_KeyboardAndMouse", "Win32_UI_WindowsAndMessaging", "Win32_Foundation", "Win32_Foundation"]} 26 | 27 | [target.'cfg(target_os = "macos")'.dependencies] 28 | readkey = "0.2.2" 29 | readmouse = "0.2.1" 30 | macos-accessibility-client = "0.0.1" 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ostrosco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # device_query 2 | 3 | [![Build Status](https://travis-ci.org/ostrosco/device_query.svg?branch=master)](https://travis-ci.org/ostrosco/device_query) 4 | 5 | A simple library to query mouse and keyboard inputs on demand without a window. 6 | Will work in Windows, Linux on X11, and macOS. 7 | 8 | ```Rust 9 | use device_query::{DeviceQuery, DeviceState, MouseState, Keycode}; 10 | 11 | let device_state = DeviceState::new(); 12 | let mouse: MouseState = device_state.get_mouse(); 13 | println!("Current Mouse Coordinates: {:?}", mouse.coords); 14 | let keys: Vec = device_state.get_keys(); 15 | println!("Is A pressed? {}", keys.contains(Keycode::A)); 16 | ``` 17 | 18 | # Dependencies 19 | 20 | Windows shouldn't require any special software to be installed for `device_query` to work properly. 21 | On Linux, the X11 development libraries are required for `device_query` to query state from the OS. 22 | 23 | On Ubuntu/Debian: 24 | ``` 25 | sudo apt install libx11-dev 26 | ``` 27 | 28 | On Fedora/RHEL/CentOS: 29 | ``` 30 | sudo dnf install xorg-x11-server-devel 31 | ``` 32 | 33 | On newer versions of MacOS, you may run into issues where you only see meta keys such as shift, 34 | backspace, et cetera. This is due to a permission issue. To work around this: 35 | 36 | * open the MacOS system preferences 37 | * go to Security -> Privacy 38 | * scroll down to Accessibility and unlock it 39 | * add the app that is using `device_query` (such as your terminal) to the list 40 | 41 | # Device Callbacks 42 | 43 | `device_query` allows you to register callbacks for various device events such as key presses and mouse movements. 44 | 45 | ## Example 46 | 47 | Here's a simple example demonstrating how to use the callback system: 48 | 49 | ```rust 50 | extern crate device_query; 51 | use device_query::{DeviceEvents, DeviceEventsHandler, Keycode, MouseButton, MousePosition}; 52 | use std::thread; 53 | use std::time::Duration; 54 | 55 | fn main() { 56 | // Initialize the event handler with a sleep duration of 10 milliseconds 57 | let event_handler = DeviceEventsHandler::new(Duration::from_millis(10)) 58 | .expect("Could not initialize event loop"); 59 | 60 | // Register callbacks for various events 61 | // The callbacks will be automatically deregistered when they go out of scope 62 | let _mouse_move_guard = event_handler.on_mouse_move(|position: &MousePosition| { 63 | println!("Mouse moved to position: {:?}", position); 64 | }); 65 | 66 | // Keep the main thread alive to continue receiving events 67 | loop { 68 | thread::sleep(Duration::from_secs(1000)); 69 | } 70 | } 71 | ``` -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate pkg_config; 2 | 3 | #[cfg(target_os = "windows")] 4 | fn main() {} 5 | 6 | #[cfg(target_os = "macos")] 7 | fn main() {} 8 | 9 | #[cfg(target_os = "linux")] 10 | use std::env; 11 | #[cfg(target_os = "linux")] 12 | use std::fs::File; 13 | #[cfg(target_os = "linux")] 14 | use std::io::Write; 15 | #[cfg(target_os = "linux")] 16 | use std::path::Path; 17 | 18 | #[cfg(target_os = "linux")] 19 | fn main() { 20 | let mut config = String::new(); 21 | let libdir = match pkg_config::get_variable("x11", "libdir") { 22 | Ok(libdir) => format!("Some(\"{}\")", libdir), 23 | Err(_) => "None".to_string(), 24 | }; 25 | config.push_str(&format!( 26 | "pub const {}: Option<&'static str> = {};\n", 27 | "x11", libdir 28 | )); 29 | 30 | let config = format!("pub mod config {{ pub mod libdir {{\n{}}}\n}}", config); 31 | let out_dir = env::var("OUT_DIR").unwrap(); 32 | let dest_path = Path::new(&out_dir).join("config.rs"); 33 | let mut f = File::create(dest_path).unwrap(); 34 | f.write_all(&config.into_bytes()).unwrap(); 35 | 36 | let target = env::var("TARGET").unwrap(); 37 | if target.contains("linux") { 38 | println!("cargo:rustc-link-lib=dl"); 39 | } else if target.contains("freebsd") || target.contains("dragonfly") { 40 | println!("cargo:rustc-link-lib=c"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/event_based_print_keys.rs: -------------------------------------------------------------------------------- 1 | extern crate device_query; 2 | 3 | use device_query::{DeviceEvents, DeviceEventsHandler}; 4 | use std::thread; 5 | use std::time::Duration; 6 | 7 | fn main() { 8 | let event_handler = DeviceEventsHandler::new(Duration::from_millis(10)) 9 | .expect("Could not initialize event loop"); 10 | let _guard = event_handler.on_key_down(|key| { 11 | println!("Down: {:#?}", key); 12 | }); 13 | let _guard = event_handler.on_key_up(|key| { 14 | println!("Up: {:#?}", key); 15 | }); 16 | 17 | loop { 18 | thread::sleep(Duration::from_secs(1000)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/event_based_print_mouse.rs: -------------------------------------------------------------------------------- 1 | extern crate device_query; 2 | 3 | use device_query::{DeviceEvents, DeviceEventsHandler}; 4 | use std::thread; 5 | use std::time::Duration; 6 | 7 | fn main() { 8 | let event_handler = DeviceEventsHandler::new(std::time::Duration::from_millis(10)) 9 | .expect("Could not initialize event loop"); 10 | let _guard = event_handler.on_mouse_move(|position| { 11 | println!("Position: {:#?}", position); 12 | }); 13 | let _guard = event_handler.on_mouse_down(|button| { 14 | println!("Down: {:#?}", button); 15 | }); 16 | let _guard = event_handler.on_mouse_up(|button| { 17 | println!("Up: {:#?}", button); 18 | }); 19 | 20 | loop { 21 | thread::sleep(Duration::from_secs(1000)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/print_keys.rs: -------------------------------------------------------------------------------- 1 | extern crate device_query; 2 | 3 | use device_query::{DeviceQuery, DeviceState}; 4 | 5 | fn main() { 6 | let device_state = DeviceState::new(); 7 | let mut prev_keys = vec![]; 8 | loop { 9 | let keys = device_state.get_keys(); 10 | if keys != prev_keys { 11 | println!("{:?}", keys); 12 | } 13 | prev_keys = keys; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/print_mouse.rs: -------------------------------------------------------------------------------- 1 | extern crate device_query; 2 | 3 | use device_query::{DeviceQuery, DeviceState, MouseState}; 4 | 5 | fn main() { 6 | let device_state = DeviceState::new(); 7 | let mut prev_mouse = MouseState::default(); 8 | loop { 9 | let mouse = device_state.get_mouse(); 10 | if mouse != prev_mouse { 11 | println!("{:?}", mouse); 12 | } 13 | prev_mouse = mouse; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/device_events/callback/callback_guard.rs: -------------------------------------------------------------------------------- 1 | //! Callback guard. 2 | 3 | use std::sync::Arc; 4 | 5 | /// Callback guard returned when adding a callback as an event listener. If the guard is dropped, 6 | /// the event listener is removed. 7 | #[derive(Debug)] 8 | pub struct CallbackGuard { 9 | pub(crate) _callback: Arc, 10 | } 11 | -------------------------------------------------------------------------------- /src/device_events/callback/keyboard_callback.rs: -------------------------------------------------------------------------------- 1 | use crate::device_events::utils; 2 | use std::ops::DerefMut; 3 | use std::sync::{Arc, Mutex, Weak}; 4 | use Keycode; 5 | 6 | /// Keyboard callback. 7 | pub type KeyboardCallback = dyn Fn(&Keycode) + Sync + Send + 'static; 8 | 9 | /// Keyboard callbacks. 10 | #[derive(Default)] 11 | pub(crate) struct KeyboardCallbacks { 12 | key_down: Mutex>>, 13 | key_up: Mutex>>, 14 | } 15 | 16 | impl KeyboardCallbacks { 17 | pub fn push_key_up(&self, callback: Arc) { 18 | if let Ok(mut key_down) = self.key_up.lock() { 19 | let callback = Arc::downgrade(&callback); 20 | key_down.push(callback) 21 | } 22 | } 23 | 24 | pub fn push_key_down(&self, callback: Arc) { 25 | if let Ok(mut key_down) = self.key_down.lock() { 26 | let callback = Arc::downgrade(&callback); 27 | key_down.push(callback) 28 | } 29 | } 30 | 31 | pub fn run_key_up(&self, key: &Keycode) { 32 | if let Ok(mut callbacks) = self.key_up.lock() { 33 | utils::DrainFilter::drain_filter(callbacks.deref_mut(), |callback| { 34 | callback.upgrade().is_none() 35 | }); 36 | for callback in callbacks.iter() { 37 | if let Some(callback) = callback.upgrade() { 38 | callback(key); 39 | } 40 | } 41 | } 42 | } 43 | 44 | pub fn run_key_down(&self, key: &Keycode) { 45 | if let Ok(mut callbacks) = self.key_down.lock() { 46 | utils::DrainFilter::drain_filter(callbacks.deref_mut(), |callback| { 47 | callback.upgrade().is_none() 48 | }); 49 | for callback in callbacks.iter() { 50 | if let Some(callback) = callback.upgrade() { 51 | callback(key); 52 | } 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/device_events/callback/mod.rs: -------------------------------------------------------------------------------- 1 | mod callback_guard; 2 | mod keyboard_callback; 3 | mod mouse_callback; 4 | 5 | pub use self::callback_guard::*; 6 | pub use self::keyboard_callback::*; 7 | pub use self::mouse_callback::*; 8 | -------------------------------------------------------------------------------- /src/device_events/callback/mouse_callback.rs: -------------------------------------------------------------------------------- 1 | //! Mouse callback. 2 | 3 | use crate::device_events::utils; 4 | use std::ops::DerefMut; 5 | use std::sync::{Arc, Mutex, Weak}; 6 | use MouseButton; 7 | use MousePosition; 8 | 9 | /// Mouse move callback. 10 | pub type MouseMoveCallback = dyn Fn(&MousePosition) + Sync + Send + 'static; 11 | 12 | /// Mouse button callback. 13 | pub type MouseButtonCallback = dyn Fn(&MouseButton) + Sync + Send + 'static; 14 | 15 | /// Mouse callbacks. 16 | #[derive(Default)] 17 | pub(crate) struct MouseCallbacks { 18 | pub mouse_move: Mutex>>, 19 | pub mouse_up: Mutex>>, 20 | pub mouse_down: Mutex>>, 21 | } 22 | 23 | impl MouseCallbacks { 24 | pub fn push_mouse_move(&self, callback: Arc) { 25 | if let Ok(mut callbacks) = self.mouse_move.lock() { 26 | let callback = Arc::downgrade(&callback); 27 | callbacks.push(callback) 28 | } 29 | } 30 | 31 | pub fn push_mouse_down(&self, callback: Arc) { 32 | if let Ok(mut callbacks) = self.mouse_down.lock() { 33 | let callback = Arc::downgrade(&callback); 34 | callbacks.push(callback) 35 | } 36 | } 37 | 38 | pub fn push_mouse_up(&self, callback: Arc) { 39 | if let Ok(mut callbacks) = self.mouse_up.lock() { 40 | let callback = Arc::downgrade(&callback); 41 | callbacks.push(callback) 42 | } 43 | } 44 | 45 | pub fn run_mouse_move(&self, position: &MousePosition) { 46 | if let Ok(mut callbacks) = self.mouse_move.lock() { 47 | utils::DrainFilter::drain_filter(callbacks.deref_mut(), |callback| { 48 | callback.upgrade().is_none() 49 | }); 50 | for callback in callbacks.iter() { 51 | if let Some(callback) = callback.upgrade() { 52 | callback(position); 53 | } 54 | } 55 | } 56 | } 57 | 58 | pub fn run_mouse_down(&self, button: &MouseButton) { 59 | if let Ok(mut callbacks) = self.mouse_down.lock() { 60 | utils::DrainFilter::drain_filter(callbacks.deref_mut(), |callback| { 61 | callback.upgrade().is_none() 62 | }); 63 | for callback in callbacks.iter() { 64 | if let Some(callback) = callback.upgrade() { 65 | callback(button); 66 | } 67 | } 68 | } 69 | } 70 | 71 | pub fn run_mouse_up(&self, button: &MouseButton) { 72 | if let Ok(mut callbacks) = self.mouse_up.lock() { 73 | utils::DrainFilter::drain_filter(callbacks.deref_mut(), |callback| { 74 | callback.upgrade().is_none() 75 | }); 76 | for callback in callbacks.iter() { 77 | if let Some(callback) = callback.upgrade() { 78 | callback(button); 79 | } 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/device_events/event_loop.rs: -------------------------------------------------------------------------------- 1 | use super::{CallbackGuard, KeyboardCallbacks}; 2 | use std::sync::{Arc, LazyLock, Mutex, Weak}; 3 | use std::thread::{sleep, spawn, JoinHandle}; 4 | use std::time::Duration; 5 | use MouseState; 6 | use {DeviceQuery, MouseCallbacks}; 7 | use {DeviceState, Keycode}; 8 | use {MouseButton, MousePosition}; 9 | 10 | pub(crate) struct EventLoop { 11 | keyboard_callbacks: Arc, 12 | mouse_callbacks: Arc, 13 | _keyboard_thread: JoinHandle<()>, 14 | _mouse_thread: JoinHandle<()>, 15 | } 16 | 17 | fn keyboard_thread(callbacks: Weak, sleep_dur: Duration) -> JoinHandle<()> { 18 | spawn(move || { 19 | let device_state = DeviceState::new(); 20 | let mut prev_keys = vec![]; 21 | while let Some(callbacks) = callbacks.upgrade() { 22 | let keys = device_state.get_keys(); 23 | for key_state in &keys { 24 | if !prev_keys.contains(key_state) { 25 | callbacks.run_key_down(key_state); 26 | } 27 | } 28 | for key_state in &prev_keys { 29 | if !keys.contains(key_state) { 30 | callbacks.run_key_up(key_state); 31 | } 32 | } 33 | prev_keys = keys; 34 | sleep(sleep_dur); 35 | } 36 | }) 37 | } 38 | 39 | fn mouse_thread(callbacks: Weak, sleep_dur: Duration) -> JoinHandle<()> { 40 | spawn(move || { 41 | let device_state = DeviceState::new(); 42 | let mut previous_mouse_state = MouseState::default(); 43 | while let Some(callbacks) = callbacks.upgrade() { 44 | let mouse_state = device_state.get_mouse(); 45 | for (index, (previous_state, current_state)) in previous_mouse_state 46 | .button_pressed 47 | .iter() 48 | .zip(mouse_state.button_pressed.iter()) 49 | .enumerate() 50 | { 51 | if !(*previous_state) && *current_state { 52 | callbacks.run_mouse_down(&index); 53 | } else if *previous_state && !(*current_state) { 54 | callbacks.run_mouse_up(&index); 55 | } 56 | } 57 | if mouse_state.coords != previous_mouse_state.coords { 58 | callbacks.run_mouse_move(&mouse_state.coords); 59 | } 60 | previous_mouse_state = mouse_state; 61 | sleep(sleep_dur); 62 | } 63 | }) 64 | } 65 | 66 | impl Default for EventLoop { 67 | fn default() -> Self { 68 | Self::new(Duration::from_micros(100)) 69 | } 70 | } 71 | 72 | impl EventLoop { 73 | fn new(sleep_dur: Duration) -> Self { 74 | let keyboard_callbacks = Arc::new(KeyboardCallbacks::default()); 75 | let mouse_callbacks = Arc::new(MouseCallbacks::default()); 76 | let _keyboard_thread = keyboard_thread(Arc::downgrade(&keyboard_callbacks), sleep_dur); 77 | let _mouse_thread = mouse_thread(Arc::downgrade(&mouse_callbacks), sleep_dur); 78 | Self { 79 | keyboard_callbacks, 80 | mouse_callbacks, 81 | _keyboard_thread, 82 | _mouse_thread, 83 | } 84 | } 85 | 86 | pub fn on_key_down( 87 | &mut self, 88 | callback: Callback, 89 | ) -> CallbackGuard { 90 | let _callback = Arc::new(callback); 91 | self.keyboard_callbacks.push_key_down(_callback.clone()); 92 | CallbackGuard { _callback } 93 | } 94 | 95 | pub fn on_key_up( 96 | &mut self, 97 | callback: Callback, 98 | ) -> CallbackGuard { 99 | let _callback = Arc::new(callback); 100 | self.keyboard_callbacks.push_key_up(_callback.clone()); 101 | CallbackGuard { _callback } 102 | } 103 | 104 | pub fn on_mouse_move( 105 | &mut self, 106 | callback: Callback, 107 | ) -> CallbackGuard { 108 | let _callback = Arc::new(callback); 109 | self.mouse_callbacks.push_mouse_move(_callback.clone()); 110 | CallbackGuard { _callback } 111 | } 112 | 113 | pub fn on_mouse_up( 114 | &mut self, 115 | callback: Callback, 116 | ) -> CallbackGuard { 117 | let _callback = Arc::new(callback); 118 | self.mouse_callbacks.push_mouse_up(_callback.clone()); 119 | CallbackGuard { _callback } 120 | } 121 | 122 | pub fn on_mouse_down( 123 | &mut self, 124 | callback: Callback, 125 | ) -> CallbackGuard { 126 | let _callback = Arc::new(callback); 127 | self.mouse_callbacks.push_mouse_down(_callback.clone()); 128 | CallbackGuard { _callback } 129 | } 130 | } 131 | 132 | pub(crate) static EVENT_LOOP: LazyLock>> = LazyLock::new(|| Default::default()); 133 | 134 | pub(crate) fn init_event_loop(sleep_dur: Duration) -> bool { 135 | let Ok(mut lock) = EVENT_LOOP.lock() else { 136 | return false; 137 | }; 138 | if lock.is_some() { 139 | return false; 140 | } 141 | *lock = Some(EventLoop::new(sleep_dur)); 142 | true 143 | } -------------------------------------------------------------------------------- /src/device_events/mod.rs: -------------------------------------------------------------------------------- 1 | //! Devices events listeners. 2 | //! 3 | //! This module contains the implementation of the DeviceEventsHandler struct. 4 | //! This allows to register callbacks for device events. 5 | //! for the current state of the device, see the [`DeviceState`](crate::device_state::DeviceState) struct. 6 | //! 7 | //! # Example 8 | //! 9 | //! ```no_run 10 | //! use device_query::{DeviceEvents, DeviceEventsHandler, Keycode, MouseButton}; 11 | //! use std::time::Duration; 12 | //! 13 | //! fn main() { 14 | //! let device_events = DeviceEventsHandler::new(Duration::from_millis(10)).unwrap(); 15 | //! // Register a key down event callback 16 | //! // The guard is used to keep the callback alive 17 | //! let _guard = device_events.on_key_down(|key| { 18 | //! println!("Key down: {:?}", key); 19 | //! }); 20 | //! // Keep the main thread alive 21 | //! loop {} 22 | //! } 23 | //! 24 | //! ``` 25 | //! 26 | 27 | mod callback; 28 | mod event_loop; 29 | mod utils; 30 | 31 | use std::time::Duration; 32 | 33 | use crate::MousePosition; 34 | 35 | pub use self::callback::*; 36 | use self::event_loop::*; 37 | 38 | use Keycode; 39 | use MouseButton; 40 | 41 | /// All the supported devices events. 42 | pub trait DeviceEvents { 43 | /// Register an on key down event callback. 44 | fn on_key_down( 45 | &self, 46 | callback: Callback, 47 | ) -> CallbackGuard; 48 | /// Register an on key up event callback. 49 | fn on_key_up( 50 | &self, 51 | callback: Callback, 52 | ) -> CallbackGuard; 53 | 54 | /// Register an on mouse move event callback. 55 | fn on_mouse_move( 56 | &self, 57 | callback: Callback, 58 | ) -> CallbackGuard; 59 | /// Register an on mouse button down event callback. 60 | fn on_mouse_down( 61 | &self, 62 | callback: Callback, 63 | ) -> CallbackGuard; 64 | /// Register an on mouse button up event callback. 65 | fn on_mouse_up( 66 | &self, 67 | callback: Callback, 68 | ) -> CallbackGuard; 69 | } 70 | 71 | pub struct DeviceEventsHandler; 72 | 73 | impl DeviceEventsHandler { 74 | /// Attempts to start event loop with the given sleep duration. 75 | /// Returns None if the event loop is already running. 76 | pub fn new(sleep_dur: Duration) -> Option { 77 | event_loop::init_event_loop(sleep_dur).then_some(DeviceEventsHandler) 78 | } 79 | } 80 | 81 | /// Returns the event loop. 82 | /// 83 | /// This is a workaround to avoid using unsafe code, 84 | /// the existence of a [`DeviceEventsHandler`] means that the event loop is already initialized. 85 | macro_rules! get_event_loop { 86 | () => { 87 | EVENT_LOOP 88 | .lock() 89 | .expect("Couldn't lock EVENT_LOOP") 90 | .as_mut() 91 | .unwrap() 92 | }; 93 | } 94 | 95 | impl DeviceEvents for DeviceEventsHandler { 96 | fn on_key_down( 97 | &self, 98 | callback: Callback, 99 | ) -> CallbackGuard { 100 | get_event_loop!().on_key_down(callback) 101 | } 102 | 103 | fn on_key_up( 104 | &self, 105 | callback: Callback, 106 | ) -> CallbackGuard { 107 | get_event_loop!().on_key_up(callback) 108 | } 109 | 110 | fn on_mouse_move( 111 | &self, 112 | callback: Callback, 113 | ) -> CallbackGuard { 114 | get_event_loop!().on_mouse_move(callback) 115 | } 116 | 117 | fn on_mouse_down( 118 | &self, 119 | callback: Callback, 120 | ) -> CallbackGuard { 121 | get_event_loop!().on_mouse_down(callback) 122 | } 123 | 124 | fn on_mouse_up( 125 | &self, 126 | callback: Callback, 127 | ) -> CallbackGuard { 128 | get_event_loop!().on_mouse_up(callback) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/device_events/utils.rs: -------------------------------------------------------------------------------- 1 | //! Utils. 2 | 3 | /// This is a placeholder for the unstable feature. 4 | pub trait DrainFilter { 5 | fn drain_filter(&mut self, filter: F) 6 | where 7 | F: FnMut(&mut T) -> bool; 8 | } 9 | 10 | impl DrainFilter for Vec { 11 | fn drain_filter(&mut self, filter: F) 12 | where 13 | F: FnMut(&mut T) -> bool, 14 | { 15 | let mut filter = filter; 16 | if self.len() == 0 { 17 | return; 18 | } 19 | let mut i = self.len() - 1; 20 | while i > 0 { 21 | if filter(&mut self[i]) { 22 | self.remove(i); 23 | } else { 24 | i -= 1; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/device_query.rs: -------------------------------------------------------------------------------- 1 | //! Query functions. 2 | 3 | use DeviceState; 4 | use {Keycode, MouseState}; 5 | 6 | /// Trait to get the state of the supported devices. 7 | pub trait DeviceQuery { 8 | /// Get MouseState. 9 | fn get_mouse(&self) -> MouseState; 10 | 11 | /// Get Keyboard state. 12 | fn get_keys(&self) -> Vec; 13 | } 14 | 15 | impl DeviceQuery for DeviceState { 16 | /// Query for the current mouse position and mouse button device_state. 17 | fn get_mouse(&self) -> MouseState { 18 | self.query_pointer() 19 | } 20 | 21 | /// Query for all keys that are currently pressed down. 22 | fn get_keys(&self) -> Vec { 23 | self.query_keymap() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/device_state/linux/kernel_key.rs: -------------------------------------------------------------------------------- 1 | /// A non-exhaustive list of keycodes from Linux. Only the ones that this library currently supports 2 | /// is currently listed in this file; other keycodes will need to be added later as needed. 3 | /// Reference: https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h 4 | 5 | pub const KEY_ESC: u16 = 1; 6 | pub const KEY_1: u16 = 2; 7 | pub const KEY_2: u16 = 3; 8 | pub const KEY_3: u16 = 4; 9 | pub const KEY_4: u16 = 5; 10 | pub const KEY_5: u16 = 6; 11 | pub const KEY_6: u16 = 7; 12 | pub const KEY_7: u16 = 8; 13 | pub const KEY_8: u16 = 9; 14 | pub const KEY_9: u16 = 10; 15 | pub const KEY_0: u16 = 11; 16 | pub const KEY_MINUS: u16 = 12; 17 | pub const KEY_EQUAL: u16 = 13; 18 | pub const KEY_BACKSPACE: u16 = 14; 19 | pub const KEY_TAB: u16 = 15; 20 | pub const KEY_Q: u16 = 16; 21 | pub const KEY_W: u16 = 17; 22 | pub const KEY_E: u16 = 18; 23 | pub const KEY_R: u16 = 19; 24 | pub const KEY_T: u16 = 20; 25 | pub const KEY_Y: u16 = 21; 26 | pub const KEY_U: u16 = 22; 27 | pub const KEY_I: u16 = 23; 28 | pub const KEY_O: u16 = 24; 29 | pub const KEY_P: u16 = 25; 30 | pub const KEY_LEFTBRACE: u16 = 26; 31 | pub const KEY_RIGHTBRACE: u16 = 27; 32 | pub const KEY_ENTER: u16 = 28; 33 | pub const KEY_LEFTCTRL: u16 = 29; 34 | pub const KEY_A: u16 = 30; 35 | pub const KEY_S: u16 = 31; 36 | pub const KEY_D: u16 = 32; 37 | pub const KEY_F: u16 = 33; 38 | pub const KEY_G: u16 = 34; 39 | pub const KEY_H: u16 = 35; 40 | pub const KEY_J: u16 = 36; 41 | pub const KEY_K: u16 = 37; 42 | pub const KEY_L: u16 = 38; 43 | pub const KEY_SEMICOLON: u16 = 39; 44 | pub const KEY_APOSTROPHE: u16 = 40; 45 | pub const KEY_GRAVE: u16 = 41; 46 | pub const KEY_LEFTSHIFT: u16 = 42; 47 | pub const KEY_BACKSLASH: u16 = 43; 48 | pub const KEY_Z: u16 = 44; 49 | pub const KEY_X: u16 = 45; 50 | pub const KEY_C: u16 = 46; 51 | pub const KEY_V: u16 = 47; 52 | pub const KEY_B: u16 = 48; 53 | pub const KEY_N: u16 = 49; 54 | pub const KEY_M: u16 = 50; 55 | pub const KEY_COMMA: u16 = 51; 56 | pub const KEY_DOT: u16 = 52; 57 | pub const KEY_SLASH: u16 = 53; 58 | pub const KEY_RIGHTSHIFT: u16 = 54; 59 | pub const KEY_KPASTERISK: u16 = 55; 60 | pub const KEY_LEFTALT: u16 = 56; 61 | pub const KEY_SPACE: u16 = 57; 62 | pub const KEY_CAPSLOCK: u16 = 58; 63 | pub const KEY_F1: u16 = 59; 64 | pub const KEY_F2: u16 = 60; 65 | pub const KEY_F3: u16 = 61; 66 | pub const KEY_F4: u16 = 62; 67 | pub const KEY_F5: u16 = 63; 68 | pub const KEY_F6: u16 = 64; 69 | pub const KEY_F7: u16 = 65; 70 | pub const KEY_F8: u16 = 66; 71 | pub const KEY_F9: u16 = 67; 72 | pub const KEY_F10: u16 = 68; 73 | pub const KEY_KP7: u16 = 71; 74 | pub const KEY_KP8: u16 = 72; 75 | pub const KEY_KP9: u16 = 73; 76 | pub const KEY_KPMINUS: u16 = 74; 77 | pub const KEY_KP4: u16 = 75; 78 | pub const KEY_KP5: u16 = 76; 79 | pub const KEY_KP6: u16 = 77; 80 | pub const KEY_KPPLUS: u16 = 78; 81 | pub const KEY_KP1: u16 = 79; 82 | pub const KEY_KP2: u16 = 80; 83 | pub const KEY_KP3: u16 = 81; 84 | pub const KEY_KP0: u16 = 82; 85 | pub const KEY_KPDOT: u16 = 83; 86 | pub const KEY_F11: u16 = 87; 87 | pub const KEY_F12: u16 = 88; 88 | pub const KEY_F13: u16 = 183; 89 | pub const KEY_F14: u16 = 184; 90 | pub const KEY_F15: u16 = 185; 91 | pub const KEY_F16: u16 = 186; 92 | pub const KEY_F17: u16 = 187; 93 | pub const KEY_F18: u16 = 188; 94 | pub const KEY_F19: u16 = 189; 95 | pub const KEY_F20: u16 = 190; 96 | pub const KEY_KPENTER: u16 = 96; 97 | pub const KEY_RIGHTCTRL: u16 = 97; 98 | pub const KEY_KPSLASH: u16 = 98; 99 | pub const KEY_RIGHTALT: u16 = 100; 100 | pub const KEY_HOME: u16 = 102; 101 | pub const KEY_UP: u16 = 103; 102 | pub const KEY_PAGEUP: u16 = 104; 103 | pub const KEY_LEFT: u16 = 105; 104 | pub const KEY_RIGHT: u16 = 106; 105 | pub const KEY_END: u16 = 107; 106 | pub const KEY_DOWN: u16 = 108; 107 | pub const KEY_PAGEDOWN: u16 = 109; 108 | pub const KEY_INSERT: u16 = 110; 109 | pub const KEY_DELETE: u16 = 111; 110 | pub const KEY_KPEQUAL: u16 = 117; 111 | pub const KEY_LEFTMETA: u16 = 125; 112 | pub const KEY_RIGHTMETA: u16 = 126; 113 | -------------------------------------------------------------------------------- /src/device_state/linux/mod.rs: -------------------------------------------------------------------------------- 1 | extern crate x11; 2 | 3 | use self::x11::xlib; 4 | use keymap::Keycode; 5 | use mouse_state::MouseState; 6 | use std::os::raw::c_char; 7 | use std::ptr; 8 | use std::rc::Rc; 9 | use std::slice; 10 | 11 | mod kernel_key; 12 | 13 | #[derive(Debug, Clone)] 14 | /// Device state descriptor. 15 | pub struct DeviceState { 16 | xc: Rc, 17 | } 18 | 19 | #[derive(Debug)] 20 | struct X11Connection { 21 | display: *mut xlib::Display, 22 | } 23 | 24 | impl Drop for X11Connection { 25 | fn drop(&mut self) { 26 | unsafe { 27 | xlib::XCloseDisplay(self.display); 28 | } 29 | } 30 | } 31 | 32 | impl DeviceState { 33 | /// Creates a new DeviceState. 34 | pub fn new() -> DeviceState { 35 | unsafe { 36 | let display = xlib::XOpenDisplay(ptr::null()); 37 | if display.as_ref().is_none() { 38 | panic!("Could not connect to a X display"); 39 | } 40 | DeviceState { 41 | xc: Rc::new(X11Connection { display }), 42 | } 43 | } 44 | } 45 | 46 | /// Create a new DeviceState. In case of failure, doesn't panic. 47 | pub fn checked_new() -> Option { 48 | unsafe { 49 | let display = xlib::XOpenDisplay(ptr::null()); 50 | if display.as_ref().is_none() { 51 | eprintln!("Could not connect to a X display"); 52 | return None; 53 | } 54 | Some(DeviceState { 55 | xc: Rc::new(X11Connection { display }), 56 | }) 57 | } 58 | } 59 | 60 | /// Query the `MouseState`. 61 | pub fn query_pointer(&self) -> MouseState { 62 | let root; 63 | let mut root_x = 0; 64 | let mut root_y = 0; 65 | let mut win_x = 0; 66 | let mut win_y = 0; 67 | let mut root_return = 0; 68 | let mut child_return = 0; 69 | let mut mask_return = 0; 70 | unsafe { 71 | root = xlib::XDefaultRootWindow(self.xc.display); 72 | xlib::XQueryPointer( 73 | self.xc.display, 74 | root, 75 | &mut root_return, 76 | &mut child_return, 77 | &mut root_x, 78 | &mut root_y, 79 | &mut win_x, 80 | &mut win_y, 81 | &mut mask_return, 82 | ); 83 | } 84 | let button1pressed = mask_return & xlib::Button1Mask > 0; 85 | let button2pressed = mask_return & xlib::Button2Mask > 0; 86 | let button3pressed = mask_return & xlib::Button3Mask > 0; 87 | let button4pressed = mask_return & xlib::Button4Mask > 0; 88 | let button5pressed = mask_return & xlib::Button5Mask > 0; 89 | 90 | // Use 1-based indexing here so people can just query the button 91 | // number they're interested in directly. 92 | let button_pressed = vec![ 93 | false, 94 | button1pressed, 95 | button2pressed, 96 | button3pressed, 97 | button4pressed, 98 | button5pressed, 99 | ]; 100 | MouseState { 101 | coords: (win_x, win_y), 102 | button_pressed, 103 | } 104 | } 105 | 106 | /// Query the Keyboard state. 107 | pub fn query_keymap(&self) -> Vec { 108 | let mut keycodes = vec![]; 109 | unsafe { 110 | let keymap: *mut c_char = [0; 32].as_mut_ptr(); 111 | xlib::XQueryKeymap(self.xc.display, keymap); 112 | for (ix, byte) in slice::from_raw_parts(keymap, 32).iter().enumerate() { 113 | for bit in 0_u8..8_u8 { 114 | let bitmask = 1 << bit; 115 | if byte & bitmask != 0 { 116 | //x11 keycode uses kernel keycode with an offset of 8. 117 | let x11_key = ix as u8 * 8 + bit; 118 | let kernel_key = x11_key - 8; 119 | if let Some(k) = self.kernel_key_to_keycode(kernel_key) { 120 | keycodes.push(k) 121 | } 122 | } 123 | } 124 | } 125 | } 126 | keycodes 127 | } 128 | 129 | fn kernel_key_to_keycode(&self, kernel_code: u8) -> Option { 130 | match kernel_code as u16 { 131 | kernel_key::KEY_0 => Some(Keycode::Key0), 132 | kernel_key::KEY_1 => Some(Keycode::Key1), 133 | kernel_key::KEY_2 => Some(Keycode::Key2), 134 | kernel_key::KEY_3 => Some(Keycode::Key3), 135 | kernel_key::KEY_4 => Some(Keycode::Key4), 136 | kernel_key::KEY_5 => Some(Keycode::Key5), 137 | kernel_key::KEY_6 => Some(Keycode::Key6), 138 | kernel_key::KEY_7 => Some(Keycode::Key7), 139 | kernel_key::KEY_8 => Some(Keycode::Key8), 140 | kernel_key::KEY_9 => Some(Keycode::Key9), 141 | kernel_key::KEY_A => Some(Keycode::A), 142 | kernel_key::KEY_B => Some(Keycode::B), 143 | kernel_key::KEY_C => Some(Keycode::C), 144 | kernel_key::KEY_D => Some(Keycode::D), 145 | kernel_key::KEY_E => Some(Keycode::E), 146 | kernel_key::KEY_F => Some(Keycode::F), 147 | kernel_key::KEY_G => Some(Keycode::G), 148 | kernel_key::KEY_H => Some(Keycode::H), 149 | kernel_key::KEY_I => Some(Keycode::I), 150 | kernel_key::KEY_J => Some(Keycode::J), 151 | kernel_key::KEY_K => Some(Keycode::K), 152 | kernel_key::KEY_L => Some(Keycode::L), 153 | kernel_key::KEY_M => Some(Keycode::M), 154 | kernel_key::KEY_N => Some(Keycode::N), 155 | kernel_key::KEY_O => Some(Keycode::O), 156 | kernel_key::KEY_P => Some(Keycode::P), 157 | kernel_key::KEY_Q => Some(Keycode::Q), 158 | kernel_key::KEY_R => Some(Keycode::R), 159 | kernel_key::KEY_S => Some(Keycode::S), 160 | kernel_key::KEY_T => Some(Keycode::T), 161 | kernel_key::KEY_U => Some(Keycode::U), 162 | kernel_key::KEY_V => Some(Keycode::V), 163 | kernel_key::KEY_W => Some(Keycode::W), 164 | kernel_key::KEY_X => Some(Keycode::X), 165 | kernel_key::KEY_Y => Some(Keycode::Y), 166 | kernel_key::KEY_Z => Some(Keycode::Z), 167 | kernel_key::KEY_F1 => Some(Keycode::F1), 168 | kernel_key::KEY_F2 => Some(Keycode::F2), 169 | kernel_key::KEY_F3 => Some(Keycode::F3), 170 | kernel_key::KEY_F4 => Some(Keycode::F4), 171 | kernel_key::KEY_F5 => Some(Keycode::F5), 172 | kernel_key::KEY_F6 => Some(Keycode::F6), 173 | kernel_key::KEY_F7 => Some(Keycode::F7), 174 | kernel_key::KEY_F8 => Some(Keycode::F8), 175 | kernel_key::KEY_F9 => Some(Keycode::F9), 176 | kernel_key::KEY_F10 => Some(Keycode::F10), 177 | kernel_key::KEY_F11 => Some(Keycode::F11), 178 | kernel_key::KEY_F12 => Some(Keycode::F12), 179 | kernel_key::KEY_F13 => Some(Keycode::F13), 180 | kernel_key::KEY_F14 => Some(Keycode::F14), 181 | kernel_key::KEY_F15 => Some(Keycode::F15), 182 | kernel_key::KEY_F16 => Some(Keycode::F16), 183 | kernel_key::KEY_F17 => Some(Keycode::F17), 184 | kernel_key::KEY_F18 => Some(Keycode::F18), 185 | kernel_key::KEY_F19 => Some(Keycode::F19), 186 | kernel_key::KEY_F20 => Some(Keycode::F20), 187 | kernel_key::KEY_KP0 => Some(Keycode::Numpad0), 188 | kernel_key::KEY_KP1 => Some(Keycode::Numpad1), 189 | kernel_key::KEY_KP2 => Some(Keycode::Numpad2), 190 | kernel_key::KEY_KP3 => Some(Keycode::Numpad3), 191 | kernel_key::KEY_KP4 => Some(Keycode::Numpad4), 192 | kernel_key::KEY_KP5 => Some(Keycode::Numpad5), 193 | kernel_key::KEY_KP6 => Some(Keycode::Numpad6), 194 | kernel_key::KEY_KP7 => Some(Keycode::Numpad7), 195 | kernel_key::KEY_KP8 => Some(Keycode::Numpad8), 196 | kernel_key::KEY_KP9 => Some(Keycode::Numpad9), 197 | kernel_key::KEY_KPENTER => Some(Keycode::NumpadEnter), 198 | kernel_key::KEY_KPMINUS => Some(Keycode::NumpadSubtract), 199 | kernel_key::KEY_KPPLUS => Some(Keycode::NumpadAdd), 200 | kernel_key::KEY_KPSLASH => Some(Keycode::NumpadDivide), 201 | kernel_key::KEY_KPASTERISK => Some(Keycode::NumpadMultiply), 202 | kernel_key::KEY_KPEQUAL => Some(Keycode::NumpadEquals), 203 | kernel_key::KEY_KPDOT => Some(Keycode::NumpadDecimal), 204 | kernel_key::KEY_ESC => Some(Keycode::Escape), 205 | kernel_key::KEY_SPACE => Some(Keycode::Space), 206 | kernel_key::KEY_LEFTCTRL => Some(Keycode::LControl), 207 | kernel_key::KEY_RIGHTCTRL => Some(Keycode::RControl), 208 | kernel_key::KEY_LEFTSHIFT => Some(Keycode::LShift), 209 | kernel_key::KEY_RIGHTSHIFT => Some(Keycode::RShift), 210 | kernel_key::KEY_LEFTALT => Some(Keycode::LAlt), 211 | kernel_key::KEY_RIGHTALT => Some(Keycode::RAlt), 212 | kernel_key::KEY_LEFTMETA => Some(Keycode::LMeta), 213 | kernel_key::KEY_RIGHTMETA => Some(Keycode::RMeta), 214 | kernel_key::KEY_ENTER => Some(Keycode::Enter), 215 | kernel_key::KEY_UP => Some(Keycode::Up), 216 | kernel_key::KEY_DOWN => Some(Keycode::Down), 217 | kernel_key::KEY_LEFT => Some(Keycode::Left), 218 | kernel_key::KEY_RIGHT => Some(Keycode::Right), 219 | kernel_key::KEY_BACKSPACE => Some(Keycode::Backspace), 220 | kernel_key::KEY_CAPSLOCK => Some(Keycode::CapsLock), 221 | kernel_key::KEY_TAB => Some(Keycode::Tab), 222 | kernel_key::KEY_HOME => Some(Keycode::Home), 223 | kernel_key::KEY_END => Some(Keycode::End), 224 | kernel_key::KEY_PAGEUP => Some(Keycode::PageUp), 225 | kernel_key::KEY_PAGEDOWN => Some(Keycode::PageDown), 226 | kernel_key::KEY_INSERT => Some(Keycode::Insert), 227 | kernel_key::KEY_DELETE => Some(Keycode::Delete), 228 | kernel_key::KEY_GRAVE => Some(Keycode::Grave), 229 | kernel_key::KEY_MINUS => Some(Keycode::Minus), 230 | kernel_key::KEY_EQUAL => Some(Keycode::Equal), 231 | kernel_key::KEY_LEFTBRACE => Some(Keycode::LeftBracket), 232 | kernel_key::KEY_RIGHTBRACE => Some(Keycode::RightBracket), 233 | kernel_key::KEY_BACKSLASH => Some(Keycode::BackSlash), 234 | kernel_key::KEY_SEMICOLON => Some(Keycode::Semicolon), 235 | kernel_key::KEY_APOSTROPHE => Some(Keycode::Apostrophe), 236 | kernel_key::KEY_COMMA => Some(Keycode::Comma), 237 | kernel_key::KEY_DOT => Some(Keycode::Dot), 238 | kernel_key::KEY_SLASH => Some(Keycode::Slash), 239 | _ => None, 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/device_state/macos/mod.rs: -------------------------------------------------------------------------------- 1 | extern crate macos_accessibility_client; 2 | 3 | use keymap::Keycode; 4 | use mouse_state::MouseState; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct DeviceState; 8 | const MAPPING: &[(readkey::Keycode, Keycode)] = &[ 9 | (readkey::Keycode::_0, Keycode::Key0), 10 | (readkey::Keycode::_1, Keycode::Key1), 11 | (readkey::Keycode::_2, Keycode::Key2), 12 | (readkey::Keycode::_3, Keycode::Key3), 13 | (readkey::Keycode::_4, Keycode::Key4), 14 | (readkey::Keycode::_5, Keycode::Key5), 15 | (readkey::Keycode::_6, Keycode::Key6), 16 | (readkey::Keycode::_7, Keycode::Key7), 17 | (readkey::Keycode::_8, Keycode::Key8), 18 | (readkey::Keycode::_9, Keycode::Key9), 19 | (readkey::Keycode::A, Keycode::A), 20 | (readkey::Keycode::B, Keycode::B), 21 | (readkey::Keycode::C, Keycode::C), 22 | (readkey::Keycode::D, Keycode::D), 23 | (readkey::Keycode::E, Keycode::E), 24 | (readkey::Keycode::F, Keycode::F), 25 | (readkey::Keycode::G, Keycode::G), 26 | (readkey::Keycode::H, Keycode::H), 27 | (readkey::Keycode::I, Keycode::I), 28 | (readkey::Keycode::J, Keycode::J), 29 | (readkey::Keycode::K, Keycode::K), 30 | (readkey::Keycode::L, Keycode::L), 31 | (readkey::Keycode::M, Keycode::M), 32 | (readkey::Keycode::N, Keycode::N), 33 | (readkey::Keycode::O, Keycode::O), 34 | (readkey::Keycode::P, Keycode::P), 35 | (readkey::Keycode::Q, Keycode::Q), 36 | (readkey::Keycode::R, Keycode::R), 37 | (readkey::Keycode::S, Keycode::S), 38 | (readkey::Keycode::T, Keycode::T), 39 | (readkey::Keycode::U, Keycode::U), 40 | (readkey::Keycode::V, Keycode::V), 41 | (readkey::Keycode::W, Keycode::W), 42 | (readkey::Keycode::X, Keycode::X), 43 | (readkey::Keycode::Y, Keycode::Y), 44 | (readkey::Keycode::Z, Keycode::Z), 45 | (readkey::Keycode::F1, Keycode::F1), 46 | (readkey::Keycode::F2, Keycode::F2), 47 | (readkey::Keycode::F3, Keycode::F3), 48 | (readkey::Keycode::F4, Keycode::F4), 49 | (readkey::Keycode::F5, Keycode::F5), 50 | (readkey::Keycode::F6, Keycode::F6), 51 | (readkey::Keycode::F7, Keycode::F7), 52 | (readkey::Keycode::F8, Keycode::F8), 53 | (readkey::Keycode::F9, Keycode::F9), 54 | (readkey::Keycode::F10, Keycode::F10), 55 | (readkey::Keycode::F11, Keycode::F11), 56 | (readkey::Keycode::F12, Keycode::F12), 57 | (readkey::Keycode::F13, Keycode::F13), 58 | (readkey::Keycode::F14, Keycode::F14), 59 | (readkey::Keycode::F15, Keycode::F15), 60 | (readkey::Keycode::F16, Keycode::F16), 61 | (readkey::Keycode::F17, Keycode::F17), 62 | (readkey::Keycode::F18, Keycode::F18), 63 | (readkey::Keycode::F19, Keycode::F19), 64 | (readkey::Keycode::F20, Keycode::F20), 65 | (readkey::Keycode::Keypad0, Keycode::Numpad0), 66 | (readkey::Keycode::Keypad1, Keycode::Numpad1), 67 | (readkey::Keycode::Keypad2, Keycode::Numpad2), 68 | (readkey::Keycode::Keypad3, Keycode::Numpad3), 69 | (readkey::Keycode::Keypad4, Keycode::Numpad4), 70 | (readkey::Keycode::Keypad5, Keycode::Numpad5), 71 | (readkey::Keycode::Keypad6, Keycode::Numpad6), 72 | (readkey::Keycode::Keypad7, Keycode::Numpad7), 73 | (readkey::Keycode::Keypad8, Keycode::Numpad8), 74 | (readkey::Keycode::Keypad9, Keycode::Numpad9), 75 | (readkey::Keycode::KeypadPlus, Keycode::NumpadAdd), 76 | (readkey::Keycode::KeypadMinus, Keycode::NumpadSubtract), 77 | (readkey::Keycode::KeypadDivide, Keycode::NumpadDivide), 78 | (readkey::Keycode::KeypadMultiply, Keycode::NumpadMultiply), 79 | (readkey::Keycode::KeypadEquals, Keycode::NumpadEquals), 80 | (readkey::Keycode::KeypadEnter, Keycode::NumpadEnter), 81 | (readkey::Keycode::KeypadDecimal, Keycode::NumpadDecimal), 82 | (readkey::Keycode::Escape, Keycode::Escape), 83 | (readkey::Keycode::Space, Keycode::Space), 84 | (readkey::Keycode::Control, Keycode::LControl), 85 | (readkey::Keycode::RightControl, Keycode::RControl), 86 | (readkey::Keycode::Shift, Keycode::LShift), 87 | (readkey::Keycode::RightShift, Keycode::RShift), 88 | (readkey::Keycode::Option, Keycode::LOption), 89 | (readkey::Keycode::RightOption, Keycode::ROption), 90 | (readkey::Keycode::Command, Keycode::Command), 91 | (readkey::Keycode::RightCommand, Keycode::RCommand), 92 | (readkey::Keycode::Return, Keycode::Enter), 93 | (readkey::Keycode::Up, Keycode::Up), 94 | (readkey::Keycode::Down, Keycode::Down), 95 | (readkey::Keycode::Left, Keycode::Left), 96 | (readkey::Keycode::Right, Keycode::Right), 97 | (readkey::Keycode::Delete, Keycode::Backspace), 98 | (readkey::Keycode::CapsLock, Keycode::CapsLock), 99 | (readkey::Keycode::Tab, Keycode::Tab), 100 | (readkey::Keycode::Home, Keycode::Home), 101 | (readkey::Keycode::End, Keycode::End), 102 | (readkey::Keycode::PageUp, Keycode::PageUp), 103 | (readkey::Keycode::PageDown, Keycode::PageDown), 104 | (readkey::Keycode::Help, Keycode::Insert), 105 | (readkey::Keycode::ForwardDelete, Keycode::Delete), 106 | (readkey::Keycode::Grave, Keycode::Grave), 107 | (readkey::Keycode::Minus, Keycode::Minus), 108 | (readkey::Keycode::Equal, Keycode::Equal), 109 | (readkey::Keycode::LeftBracket, Keycode::LeftBracket), 110 | (readkey::Keycode::RightBracket, Keycode::RightBracket), 111 | (readkey::Keycode::Backslash, Keycode::BackSlash), 112 | (readkey::Keycode::Semicolon, Keycode::Semicolon), 113 | (readkey::Keycode::Quote, Keycode::Apostrophe), 114 | (readkey::Keycode::Comma, Keycode::Comma), 115 | (readkey::Keycode::Period, Keycode::Dot), 116 | (readkey::Keycode::Slash, Keycode::Slash), 117 | ]; 118 | 119 | impl DeviceState { 120 | pub fn new() -> DeviceState { 121 | // TODO: remove this 122 | assert!( 123 | has_accessibility(), 124 | "This app does not have Accessibility Permissions enabled and will not work" 125 | ); 126 | 127 | DeviceState {} 128 | } 129 | 130 | /// returns `None` if app doesn't accessibility permissions. 131 | pub fn checked_new() -> Option { 132 | if has_accessibility() { 133 | Some(DeviceState {}) 134 | } else { 135 | None 136 | } 137 | } 138 | 139 | pub fn query_pointer(&self) -> MouseState { 140 | let (x, y) = readmouse::Mouse::location(); 141 | let button_pressed = vec![ 142 | false, 143 | readmouse::Mouse::Left.is_pressed(), 144 | readmouse::Mouse::Right.is_pressed(), 145 | readmouse::Mouse::Center.is_pressed(), 146 | false, 147 | ]; 148 | 149 | MouseState { 150 | coords: (x as i32, y as i32), 151 | button_pressed, 152 | } 153 | } 154 | 155 | pub fn query_keymap(&self) -> Vec { 156 | MAPPING 157 | .iter() 158 | .filter(|(from, _)| from.is_pressed()) 159 | .map(|(_, to)| *to) 160 | .collect() 161 | } 162 | } 163 | 164 | /// Returns true if the Accessibility permissions necessary for this library to work are granted 165 | /// to this process 166 | /// 167 | /// If this returns false, the app can request them through the OS APIs, or the user can: 168 | /// 1. open the MacOS system preferences 169 | /// 2. go to Security -> Privacy 170 | /// 3. scroll down to Accessibility and unlock it 171 | /// 4. Add the app that is using device_query (such as your terminal) to the list 172 | /// 173 | fn has_accessibility() -> bool { 174 | use self::macos_accessibility_client::accessibility::*; 175 | // Without prompting: 176 | // application_is_trusted() 177 | 178 | // With prompting: 179 | application_is_trusted_with_prompt() 180 | } 181 | -------------------------------------------------------------------------------- /src/device_state/mod.rs: -------------------------------------------------------------------------------- 1 | //! DeviceState implementation. 2 | //! 3 | //! This module contains the implementation of the DeviceState struct. 4 | //! This only allows to get the current state of the device. 5 | //! for callbacks, see the [`DeviceEventsHandler`](crate::device_events::DeviceEventsHandler) struct. 6 | //! 7 | //! # Example 8 | //! 9 | //! ```no_run 10 | //! use device_query::{DeviceState, DeviceQuery}; 11 | //! 12 | //! fn main() { 13 | //! let device_state = DeviceState::new(); 14 | //! println!("Mouse position: {:?}", device_state.get_mouse()); 15 | //! println!("Key down: {:?}", device_state.get_keys()); 16 | //! } 17 | //! 18 | //! ``` 19 | 20 | #[cfg(target_os = "linux")] 21 | mod linux; 22 | #[cfg(target_os = "linux")] 23 | pub use self::linux::DeviceState; 24 | 25 | #[cfg(target_os = "windows")] 26 | mod windows; 27 | #[cfg(target_os = "windows")] 28 | pub use self::windows::DeviceState; 29 | 30 | #[cfg(target_os = "macos")] 31 | mod macos; 32 | #[cfg(target_os = "macos")] 33 | pub use self::macos::DeviceState; 34 | 35 | impl Default for DeviceState { 36 | fn default() -> Self { 37 | Self::new() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/device_state/windows/mod.rs: -------------------------------------------------------------------------------- 1 | use keymap::Keycode; 2 | use mouse_state::MouseState; 3 | use windows::Win32::Foundation::POINT; 4 | use windows::Win32::UI::Input::KeyboardAndMouse; 5 | use windows::Win32::UI::Input::KeyboardAndMouse::{GetAsyncKeyState, VIRTUAL_KEY}; 6 | use windows::Win32::UI::WindowsAndMessaging::GetCursorPos; 7 | 8 | #[derive(Debug, Clone)] 9 | pub struct DeviceState; 10 | 11 | impl DeviceState { 12 | pub fn new() -> Self { 13 | Self {} 14 | } 15 | 16 | // Adding because Linux and OSX supports this where `new` can panic. 17 | pub fn checked_new() -> Option { 18 | Some(Self::new()) 19 | } 20 | 21 | pub fn query_pointer(&self) -> MouseState { 22 | let point = &mut POINT { x: 0, y: 0 }; 23 | let button1pressed; 24 | let button2pressed; 25 | let button3pressed; 26 | let button4pressed; 27 | let button5pressed; 28 | let coords; 29 | unsafe { 30 | coords = if GetCursorPos(point).into() { 31 | (point.x, point.y) 32 | } else { 33 | (0, 0) 34 | }; 35 | button1pressed = 36 | GetAsyncKeyState(KeyboardAndMouse::VK_LBUTTON.0 as i32) as u32 & 0x8000 != 0; 37 | button2pressed = 38 | GetAsyncKeyState(KeyboardAndMouse::VK_RBUTTON.0 as i32) as u32 & 0x8000 != 0; 39 | button3pressed = 40 | GetAsyncKeyState(KeyboardAndMouse::VK_MBUTTON.0 as i32) as u32 & 0x8000 != 0; 41 | button4pressed = 42 | GetAsyncKeyState(KeyboardAndMouse::VK_XBUTTON1.0 as i32) as u32 & 0x8000 != 0; 43 | button5pressed = 44 | GetAsyncKeyState(KeyboardAndMouse::VK_XBUTTON2.0 as i32) as u32 & 0x8000 != 0; 45 | } 46 | MouseState { 47 | coords, 48 | button_pressed: vec![ 49 | false, 50 | button1pressed, 51 | button2pressed, 52 | button3pressed, 53 | button4pressed, 54 | button5pressed, 55 | ], 56 | } 57 | } 58 | 59 | pub fn query_keymap(&self) -> Vec { 60 | let mut keycodes = vec![]; 61 | let mut keymap = vec![]; 62 | unsafe { 63 | for key in 0..256 { 64 | keymap.push(GetAsyncKeyState(key)); 65 | } 66 | } 67 | for (ix, byte) in keymap.iter().enumerate() { 68 | if *byte as u32 & 0x8000 != 0 { 69 | if let Some(k) = self.win_key_to_keycode(ix as u16) { 70 | keycodes.push(k) 71 | } 72 | } 73 | } 74 | keycodes 75 | } 76 | 77 | fn win_key_to_keycode(&self, win_key: u16) -> Option { 78 | let mut keycode = match VIRTUAL_KEY(win_key) { 79 | KeyboardAndMouse::VK_F1 => Some(Keycode::F1), 80 | KeyboardAndMouse::VK_F2 => Some(Keycode::F2), 81 | KeyboardAndMouse::VK_F3 => Some(Keycode::F3), 82 | KeyboardAndMouse::VK_F4 => Some(Keycode::F4), 83 | KeyboardAndMouse::VK_F5 => Some(Keycode::F5), 84 | KeyboardAndMouse::VK_F6 => Some(Keycode::F6), 85 | KeyboardAndMouse::VK_F7 => Some(Keycode::F7), 86 | KeyboardAndMouse::VK_F8 => Some(Keycode::F8), 87 | KeyboardAndMouse::VK_F9 => Some(Keycode::F9), 88 | KeyboardAndMouse::VK_F10 => Some(Keycode::F10), 89 | KeyboardAndMouse::VK_F11 => Some(Keycode::F11), 90 | KeyboardAndMouse::VK_F12 => Some(Keycode::F12), 91 | KeyboardAndMouse::VK_F13 => Some(Keycode::F13), 92 | KeyboardAndMouse::VK_F14 => Some(Keycode::F14), 93 | KeyboardAndMouse::VK_F15 => Some(Keycode::F15), 94 | KeyboardAndMouse::VK_F16 => Some(Keycode::F16), 95 | KeyboardAndMouse::VK_F17 => Some(Keycode::F17), 96 | KeyboardAndMouse::VK_F18 => Some(Keycode::F18), 97 | KeyboardAndMouse::VK_F19 => Some(Keycode::F19), 98 | KeyboardAndMouse::VK_F20 => Some(Keycode::F20), 99 | KeyboardAndMouse::VK_NUMPAD0 => Some(Keycode::Numpad0), 100 | KeyboardAndMouse::VK_NUMPAD1 => Some(Keycode::Numpad1), 101 | KeyboardAndMouse::VK_NUMPAD2 => Some(Keycode::Numpad2), 102 | KeyboardAndMouse::VK_NUMPAD3 => Some(Keycode::Numpad3), 103 | KeyboardAndMouse::VK_NUMPAD4 => Some(Keycode::Numpad4), 104 | KeyboardAndMouse::VK_NUMPAD5 => Some(Keycode::Numpad5), 105 | KeyboardAndMouse::VK_NUMPAD6 => Some(Keycode::Numpad6), 106 | KeyboardAndMouse::VK_NUMPAD7 => Some(Keycode::Numpad7), 107 | KeyboardAndMouse::VK_NUMPAD8 => Some(Keycode::Numpad8), 108 | KeyboardAndMouse::VK_NUMPAD9 => Some(Keycode::Numpad9), 109 | KeyboardAndMouse::VK_ADD => Some(Keycode::NumpadAdd), 110 | KeyboardAndMouse::VK_SUBTRACT => Some(Keycode::NumpadSubtract), 111 | KeyboardAndMouse::VK_DIVIDE => Some(Keycode::NumpadDivide), 112 | KeyboardAndMouse::VK_MULTIPLY => Some(Keycode::NumpadMultiply), 113 | KeyboardAndMouse::VK_OEM_NEC_EQUAL => Some(Keycode::NumpadEquals), 114 | KeyboardAndMouse::VK_DECIMAL => Some(Keycode::NumpadDecimal), 115 | KeyboardAndMouse::VK_SPACE => Some(Keycode::Space), 116 | KeyboardAndMouse::VK_LCONTROL => Some(Keycode::LControl), 117 | KeyboardAndMouse::VK_RCONTROL => Some(Keycode::RControl), 118 | KeyboardAndMouse::VK_LSHIFT => Some(Keycode::LShift), 119 | KeyboardAndMouse::VK_RSHIFT => Some(Keycode::RShift), 120 | KeyboardAndMouse::VK_LMENU => Some(Keycode::LAlt), 121 | KeyboardAndMouse::VK_RMENU => Some(Keycode::RAlt), 122 | KeyboardAndMouse::VK_LWIN => Some(Keycode::LMeta), 123 | KeyboardAndMouse::VK_RWIN => Some(Keycode::RMeta), 124 | KeyboardAndMouse::VK_RETURN => Some(Keycode::Enter), 125 | KeyboardAndMouse::VK_ESCAPE => Some(Keycode::Escape), 126 | KeyboardAndMouse::VK_UP => Some(Keycode::Up), 127 | KeyboardAndMouse::VK_DOWN => Some(Keycode::Down), 128 | KeyboardAndMouse::VK_LEFT => Some(Keycode::Left), 129 | KeyboardAndMouse::VK_RIGHT => Some(Keycode::Right), 130 | KeyboardAndMouse::VK_BACK => Some(Keycode::Backspace), 131 | KeyboardAndMouse::VK_CAPITAL => Some(Keycode::CapsLock), 132 | KeyboardAndMouse::VK_TAB => Some(Keycode::Tab), 133 | KeyboardAndMouse::VK_HOME => Some(Keycode::Home), 134 | KeyboardAndMouse::VK_END => Some(Keycode::End), 135 | KeyboardAndMouse::VK_PRIOR => Some(Keycode::PageUp), 136 | KeyboardAndMouse::VK_NEXT => Some(Keycode::PageDown), 137 | KeyboardAndMouse::VK_INSERT => Some(Keycode::Insert), 138 | KeyboardAndMouse::VK_DELETE => Some(Keycode::Delete), 139 | KeyboardAndMouse::VK_OEM_3 => Some(Keycode::Grave), 140 | KeyboardAndMouse::VK_OEM_MINUS => Some(Keycode::Minus), 141 | KeyboardAndMouse::VK_OEM_PLUS => Some(Keycode::Equal), 142 | KeyboardAndMouse::VK_OEM_4 => Some(Keycode::LeftBracket), 143 | KeyboardAndMouse::VK_OEM_6 => Some(Keycode::RightBracket), 144 | KeyboardAndMouse::VK_OEM_5 => Some(Keycode::BackSlash), 145 | KeyboardAndMouse::VK_OEM_1 => Some(Keycode::Semicolon), 146 | KeyboardAndMouse::VK_OEM_7 => Some(Keycode::Apostrophe), 147 | KeyboardAndMouse::VK_OEM_COMMA => Some(Keycode::Comma), 148 | KeyboardAndMouse::VK_OEM_PERIOD => Some(Keycode::Dot), 149 | KeyboardAndMouse::VK_OEM_2 => Some(Keycode::Slash), 150 | 151 | _ => None, 152 | }; 153 | 154 | if keycode.is_none() { 155 | let win_key = win_key as u8; 156 | keycode = match win_key as char { 157 | '0' => Some(Keycode::Key0), 158 | '1' => Some(Keycode::Key1), 159 | '2' => Some(Keycode::Key2), 160 | '3' => Some(Keycode::Key3), 161 | '4' => Some(Keycode::Key4), 162 | '5' => Some(Keycode::Key5), 163 | '6' => Some(Keycode::Key6), 164 | '7' => Some(Keycode::Key7), 165 | '8' => Some(Keycode::Key8), 166 | '9' => Some(Keycode::Key9), 167 | 'A' => Some(Keycode::A), 168 | 'B' => Some(Keycode::B), 169 | 'C' => Some(Keycode::C), 170 | 'D' => Some(Keycode::D), 171 | 'E' => Some(Keycode::E), 172 | 'F' => Some(Keycode::F), 173 | 'G' => Some(Keycode::G), 174 | 'H' => Some(Keycode::H), 175 | 'I' => Some(Keycode::I), 176 | 'J' => Some(Keycode::J), 177 | 'K' => Some(Keycode::K), 178 | 'L' => Some(Keycode::L), 179 | 'M' => Some(Keycode::M), 180 | 'N' => Some(Keycode::N), 181 | 'O' => Some(Keycode::O), 182 | 'P' => Some(Keycode::P), 183 | 'Q' => Some(Keycode::Q), 184 | 'R' => Some(Keycode::R), 185 | 'S' => Some(Keycode::S), 186 | 'T' => Some(Keycode::T), 187 | 'U' => Some(Keycode::U), 188 | 'V' => Some(Keycode::V), 189 | 'W' => Some(Keycode::W), 190 | 'X' => Some(Keycode::X), 191 | 'Y' => Some(Keycode::Y), 192 | 'Z' => Some(Keycode::Z), 193 | _ => None, 194 | } 195 | } 196 | keycode 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/keymap.rs: -------------------------------------------------------------------------------- 1 | //! List of keycodes. 2 | 3 | use std::fmt; 4 | use std::str::FromStr; 5 | 6 | /// A list of supported keys that we can query from the OS. Outside of mod. 7 | #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] 8 | #[allow(missing_docs)] 9 | pub enum Keycode { 10 | Key0, 11 | Key1, 12 | Key2, 13 | Key3, 14 | Key4, 15 | Key5, 16 | Key6, 17 | Key7, 18 | Key8, 19 | Key9, 20 | A, 21 | B, 22 | C, 23 | D, 24 | E, 25 | F, 26 | G, 27 | H, 28 | I, 29 | J, 30 | K, 31 | L, 32 | M, 33 | N, 34 | O, 35 | P, 36 | Q, 37 | R, 38 | S, 39 | T, 40 | U, 41 | V, 42 | W, 43 | X, 44 | Y, 45 | Z, 46 | F1, 47 | F2, 48 | F3, 49 | F4, 50 | F5, 51 | F6, 52 | F7, 53 | F8, 54 | F9, 55 | F10, 56 | F11, 57 | F12, 58 | F13, 59 | F14, 60 | F15, 61 | F16, 62 | F17, 63 | F18, 64 | F19, 65 | F20, 66 | Escape, 67 | Space, 68 | LControl, 69 | RControl, 70 | LShift, 71 | RShift, 72 | LAlt, 73 | RAlt, 74 | // TODO rename `Command` into `RCommand` at new major release 75 | Command, 76 | RCommand, 77 | LOption, 78 | ROption, 79 | LMeta, 80 | RMeta, 81 | Enter, 82 | Up, 83 | Down, 84 | Left, 85 | Right, 86 | Backspace, 87 | CapsLock, 88 | Tab, 89 | Home, 90 | End, 91 | PageUp, 92 | PageDown, 93 | Insert, 94 | Delete, 95 | 96 | // Numpad keys which have not been implemented: NumpadSeparator NumLock 97 | Numpad0, 98 | Numpad1, 99 | Numpad2, 100 | Numpad3, 101 | Numpad4, 102 | Numpad5, 103 | Numpad6, 104 | Numpad7, 105 | Numpad8, 106 | Numpad9, 107 | NumpadSubtract, 108 | NumpadAdd, 109 | NumpadDivide, 110 | NumpadMultiply, 111 | NumpadEquals, 112 | NumpadEnter, 113 | NumpadDecimal, 114 | 115 | // The following keys names represent the position of the key in a US keyboard, 116 | // not the sign value. In a different keyboards and OS, the position can vary. 117 | Grave, 118 | Minus, 119 | Equal, 120 | LeftBracket, 121 | RightBracket, 122 | BackSlash, 123 | Semicolon, 124 | Apostrophe, 125 | Comma, 126 | Dot, 127 | Slash, 128 | } 129 | 130 | impl FromStr for Keycode { 131 | type Err = String; 132 | fn from_str(s: &str) -> Result { 133 | match s { 134 | "Key0" => Ok(Self::Key0), 135 | "Key1" => Ok(Self::Key1), 136 | "Key2" => Ok(Self::Key2), 137 | "Key3" => Ok(Self::Key3), 138 | "Key4" => Ok(Self::Key4), 139 | "Key5" => Ok(Self::Key5), 140 | "Key6" => Ok(Self::Key6), 141 | "Key7" => Ok(Self::Key7), 142 | "Key8" => Ok(Self::Key8), 143 | "Key9" => Ok(Self::Key9), 144 | "A" => Ok(Self::A), 145 | "B" => Ok(Self::B), 146 | "C" => Ok(Self::C), 147 | "D" => Ok(Self::D), 148 | "E" => Ok(Self::E), 149 | "F" => Ok(Self::F), 150 | "G" => Ok(Self::G), 151 | "H" => Ok(Self::H), 152 | "I" => Ok(Self::I), 153 | "J" => Ok(Self::J), 154 | "K" => Ok(Self::K), 155 | "L" => Ok(Self::L), 156 | "M" => Ok(Self::M), 157 | "N" => Ok(Self::N), 158 | "O" => Ok(Self::O), 159 | "P" => Ok(Self::P), 160 | "Q" => Ok(Self::Q), 161 | "R" => Ok(Self::R), 162 | "S" => Ok(Self::S), 163 | "T" => Ok(Self::T), 164 | "U" => Ok(Self::U), 165 | "V" => Ok(Self::V), 166 | "W" => Ok(Self::W), 167 | "X" => Ok(Self::X), 168 | "Y" => Ok(Self::Y), 169 | "Z" => Ok(Self::Z), 170 | "F1" => Ok(Self::F1), 171 | "F2" => Ok(Self::F2), 172 | "F3" => Ok(Self::F3), 173 | "F4" => Ok(Self::F4), 174 | "F5" => Ok(Self::F5), 175 | "F6" => Ok(Self::F6), 176 | "F7" => Ok(Self::F7), 177 | "F8" => Ok(Self::F8), 178 | "F9" => Ok(Self::F9), 179 | "F10" => Ok(Self::F10), 180 | "F11" => Ok(Self::F11), 181 | "F12" => Ok(Self::F12), 182 | "F13" => Ok(Self::F13), 183 | "F14" => Ok(Self::F14), 184 | "F15" => Ok(Self::F15), 185 | "F16" => Ok(Self::F16), 186 | "F17" => Ok(Self::F17), 187 | "F18" => Ok(Self::F18), 188 | "F19" => Ok(Self::F19), 189 | "F20" => Ok(Self::F20), 190 | "Escape" => Ok(Self::Escape), 191 | "Space" => Ok(Self::Space), 192 | "LControl" => Ok(Self::LControl), 193 | "RControl" => Ok(Self::RControl), 194 | "LShift" => Ok(Self::LShift), 195 | "RShift" => Ok(Self::RShift), 196 | "LAlt" => Ok(Self::LAlt), 197 | "RAlt" => Ok(Self::RAlt), 198 | // TODO rename `Command` into `RCommand` at new major release 199 | "Command" => Ok(Self::Command), 200 | "RCommand" => Ok(Self::RCommand), 201 | "LOption" => Ok(Self::LOption), 202 | "ROption" => Ok(Self::ROption), 203 | "LMeta" => Ok(Self::LMeta), 204 | "RMeta" => Ok(Self::RMeta), 205 | "Enter" => Ok(Self::Enter), 206 | "Up" => Ok(Self::Up), 207 | "Down" => Ok(Self::Down), 208 | "Left" => Ok(Self::Left), 209 | "Right" => Ok(Self::Right), 210 | "Backspace" => Ok(Self::Backspace), 211 | "CapsLock" => Ok(Self::CapsLock), 212 | "Tab" => Ok(Self::Tab), 213 | "Home" => Ok(Self::Home), 214 | "End" => Ok(Self::End), 215 | "PageUp" => Ok(Self::PageUp), 216 | "PageDown" => Ok(Self::PageDown), 217 | "Insert" => Ok(Self::Insert), 218 | "Delete" => Ok(Self::Delete), 219 | "Numpad0" => Ok(Self::Numpad0), 220 | "Numpad1" => Ok(Self::Numpad1), 221 | "Numpad2" => Ok(Self::Numpad2), 222 | "Numpad3" => Ok(Self::Numpad3), 223 | "Numpad4" => Ok(Self::Numpad4), 224 | "Numpad5" => Ok(Self::Numpad5), 225 | "Numpad6" => Ok(Self::Numpad6), 226 | "Numpad7" => Ok(Self::Numpad7), 227 | "Numpad8" => Ok(Self::Numpad8), 228 | "Numpad9" => Ok(Self::Numpad9), 229 | "NumpadSubtract" => Ok(Self::NumpadSubtract), 230 | "NumpadAdd" => Ok(Self::NumpadAdd), 231 | "NumpadDivide" => Ok(Self::NumpadDivide), 232 | "NumpadMultiply" => Ok(Self::NumpadMultiply), 233 | "NumpadEquals" => Ok(Self::NumpadEquals), 234 | "NumpadEnter" => Ok(Self::NumpadEnter), 235 | "NumpadDecimal" => Ok(Self::NumpadDecimal), 236 | "Grave" => Ok(Self::Grave), 237 | "Minus" => Ok(Self::Minus), 238 | "Equal" => Ok(Self::Equal), 239 | "LeftBracket" => Ok(Self::LeftBracket), 240 | "RightBracket" => Ok(Self::RightBracket), 241 | "BackSlash" => Ok(Self::BackSlash), 242 | "Semicolon" => Ok(Self::Semicolon), 243 | "Apostrophe" => Ok(Self::Apostrophe), 244 | "Comma" => Ok(Self::Comma), 245 | "Dot" => Ok(Self::Dot), 246 | "Slash" => Ok(Self::Slash), 247 | _ => Err(String::from("failed to parse keycode")), 248 | } 249 | } 250 | } 251 | 252 | impl fmt::Display for Keycode { 253 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 254 | write!(f, "{:?}", self) 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A simple library for querying mouse and keyboard state without requiring 2 | //! an active window. Currently works in Windows, Linux, and macOS. 3 | //! 4 | //! ```no_run 5 | //! use device_query::{DeviceQuery, DeviceState, MouseState, Keycode}; 6 | //! 7 | //! let device_state = DeviceState::new(); 8 | //! 9 | //! let mouse: MouseState = device_state.get_mouse(); 10 | //! println!("Current Mouse Coordinates: {:?}", mouse.coords); 11 | //! 12 | //! let keys: Vec = device_state.get_keys(); 13 | //! println!("Is A pressed? {}", keys.contains(&Keycode::A)); 14 | //! ``` 15 | //! 16 | //! It's also possible to listen for events. 17 | //! ```no_run 18 | //! use device_query::{DeviceEvents, DeviceEventsHandler}; 19 | //! use std::time::Duration; 20 | //! 21 | //! let device_state = DeviceEventsHandler::new(Duration::from_millis(10)) 22 | //! .expect("Failed to start event loop"); 23 | //! 24 | //! // Register a key down event callback 25 | //! // The guard is used to keep the callback alive 26 | //! let _guard = device_state.on_mouse_move(|position| { 27 | //! println!("Mouse position: {:#?}", position); 28 | //! }); 29 | //! 30 | //! // Keep the main thread alive 31 | //! loop {} 32 | //! ``` 33 | 34 | #[cfg(target_os = "windows")] 35 | extern crate windows; 36 | 37 | pub mod device_events; 38 | pub mod device_query; 39 | pub mod device_state; 40 | pub mod keymap; 41 | pub mod mouse_state; 42 | 43 | pub use device_events::*; 44 | pub use device_query::*; 45 | pub use device_state::*; 46 | pub use keymap::*; 47 | pub use mouse_state::*; 48 | -------------------------------------------------------------------------------- /src/mouse_state.rs: -------------------------------------------------------------------------------- 1 | //! Description of mouse coordinates and state of buttons. 2 | 3 | /// Mouse position. 4 | pub type MousePosition = (i32, i32); 5 | 6 | /// MouseButton. 7 | pub type MouseButton = usize; 8 | 9 | #[derive(Debug, PartialEq, Default, Clone)] 10 | /// A simple structure containing the current mouse coordinates and the 11 | /// state of each mouse button that we can query. Currently, Windows and 12 | /// Linux provide nice ways to query five mouse buttons. Since button 13 | /// numbers are 1-based, `button_pressed[0]` is assumed to be false and 14 | /// have no meaning. 15 | pub struct MouseState { 16 | /// Coordinates in pixel. 17 | pub coords: MousePosition, 18 | /// State of each mouse button. 19 | pub button_pressed: Vec, 20 | } 21 | --------------------------------------------------------------------------------