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