这是indexloc提供的服务,不要输入任何密码
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/target
Cargo.lock

/.idea
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

31 changes: 21 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ categories = ["development-tools::testing", "api-bindings", "hardware-support"]
license = "MIT"

[dependencies]
serde = {version = "1.0", features = ["derive"], optional=true}
serde = { version = "1.0", features = ["derive"], optional = true }
lazy_static = "1.4"

[features]
Expand All @@ -23,28 +23,34 @@ unstable_grab = ["evdev-rs", "epoll", "inotify"]

[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.22"
core-graphics = {version = "0.19.0", features = ["highsierra"]}
core-foundation = {version = "0.7"}
core-foundation-sys = {version = "0.7"}
core-graphics = { version = "0.19.0", features = ["highsierra"] }
core-foundation = { version = "0.7" }
core-foundation-sys = { version = "0.7" }


[target.'cfg(target_os = "linux")'.dependencies]
libc = "0.2"
x11 = {version = "2.18", features = ["xlib", "xrecord", "xinput"]}
evdev-rs = {version = "0.4.0", optional=true}
epoll = {version = "4.1.0", optional=true}
inotify = {version = "0.8.2", default-features=false, optional=true}
x11 = { version = "2.18", features = ["xlib", "xrecord", "xinput"] }
evdev-rs = { version = "0.4.0", optional = true }
epoll = { version = "4.1.0", optional = true }
inotify = { version = "0.8.2", default-features = false, optional = true }

[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winuser", "errhandlingapi", "processthreadsapi"] }
windows-sys = { version = "0.45.0", features = [
"Win32_UI_WindowsAndMessaging",
"Win32_Foundation",
"Win32_System_Threading",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_TextServices"
] }

[dev-dependencies]
serde_json = "1.0"
# Some tests interact with the real OS. We can't hit the OS in parallel
# because that leads to unexpected behavior and flaky tests, so we need
# to run thoses tests in sequence instead.
serial_test = "0.4"
tokio = {version = "1.5", features=["sync", "macros", "rt-multi-thread"]}
tokio = { version = "1.5", features = ["sync", "macros", "rt-multi-thread"] }

[[example]]
name = "serialize"
Expand All @@ -62,3 +68,8 @@ required-features = ["unstable_grab"]
name = "grab"
path = "tests/grab.rs"
required-features = ["unstable_grab"]

[profile.release]
lto = true
codegen-units = 1
opt-level = 3
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still no. This is really not the job of the lib.
Or prove that it does matter, if you really think that's the case.

4 changes: 2 additions & 2 deletions examples/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ fn main() {
listen(move |event| {
schan
.send(event)
.unwrap_or_else(|e| println!("Could not send event {:?}", e));
.unwrap_or_else(|e| println!("Could not send event {e:?}"));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove all these changes and put them in a separate PR please.

While being nice, they pollute the PR by adding a lot of meaningless changes.
Changing a dependency is not a simple thing, keeping the changes to a minimum increases the likelihood that the review will be done correctly.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it's a new clippy lint. Let's still move it to another PR.

})
.expect("Could not listen");
});

let mut events = Vec::new();
for event in rchan.iter() {
println!("Received {:?}", event);
println!("Received {event:?}");
events.push(event);
}
}
2 changes: 1 addition & 1 deletion examples/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ use rdev::display_size;
fn main() {
let (w, h) = display_size().unwrap();

println!("Your screen is {:?}x{:?}", w, h);
println!("Your screen is {w:?}x{h:?}");
}
4 changes: 2 additions & 2 deletions examples/keyboard_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ fn main() {
let mut keyboard = Keyboard::new().unwrap();
let char_s = keyboard.add(&EventType::KeyPress(Key::KeyS)).unwrap();
assert_eq!(char_s, "s".to_string());
println!("Pressing S gives: {:?}", char_s);
println!("Pressing S gives: {char_s:?}");
let n = keyboard.add(&EventType::KeyRelease(Key::KeyS));
assert_eq!(n, None);

keyboard.add(&EventType::KeyPress(Key::ShiftLeft));
let char_s = keyboard.add(&EventType::KeyPress(Key::KeyS)).unwrap();
println!("Pressing Shift+S gives: {:?}", char_s);
println!("Pressing Shift+S gives: {char_s:?}");
assert_eq!(char_s, "S".to_string());
let n = keyboard.add(&EventType::KeyRelease(Key::KeyS));
assert_eq!(n, None);
Expand Down
4 changes: 2 additions & 2 deletions examples/listen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use rdev::{listen, Event};
fn main() {
// This will block.
if let Err(error) = listen(callback) {
println!("Error: {:?}", error)
println!("Error: {error:?}")
}
}

fn callback(event: Event) {
println!("My callback {:?}", event);
println!("My callback {event:?}");
}
2 changes: 1 addition & 1 deletion examples/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fn send(event_type: &EventType) {
match simulate(event_type) {
Ok(()) => (),
Err(SimulateError) => {
println!("We could not send {:?}", event_type);
println!("We could not send {event_type:?}");
}
}
// Let ths OS catchup (at least MacOS)
Expand Down
54 changes: 29 additions & 25 deletions src/windows/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ use crate::windows::keycodes::key_from_code;
use lazy_static::lazy_static;
use std::convert::TryInto;
use std::os::raw::{c_int, c_short};
use std::ptr::null_mut;

use std::sync::Mutex;
use winapi::shared::minwindef::{DWORD, HIWORD, LPARAM, LRESULT, WORD, WPARAM};
use winapi::shared::ntdef::LONG;
use winapi::shared::windef::HHOOK;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winuser::{
use windows_sys::Win32::Foundation::GetLastError;
use windows_sys::Win32::Foundation::{LPARAM, LRESULT};
use windows_sys::Win32::UI::WindowsAndMessaging::HHOOK;
use windows_sys::Win32::UI::WindowsAndMessaging::{
SetWindowsHookExA, KBDLLHOOKSTRUCT, MSLLHOOKSTRUCT, WHEEL_DELTA, WH_KEYBOARD_LL, WH_MOUSE_LL,
WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP,
WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SYSKEYDOWN,
Expand All @@ -19,36 +18,41 @@ use winapi::um::winuser::{
pub const TRUE: i32 = 1;
pub const FALSE: i32 = 0;

pub static mut HOOK: HHOOK = null_mut();
#[inline]
pub fn hiword(l: u32) -> u16 {
((l >> 16) & 0xffff) as u16
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

microsoft/windows-rs#2273

This feels broken to me. Classic Microsoft thing.
This single thing gives me doubt in moving dependency altogether.

}

pub static mut HOOK: HHOOK = 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this

lazy_static! {
pub(crate) static ref KEYBOARD: Mutex<Keyboard> = Mutex::new(Keyboard::new().unwrap());
}

pub unsafe fn get_code(lpdata: LPARAM) -> DWORD {
pub unsafe fn get_code(lpdata: LPARAM) -> u32 {
let kb = *(lpdata as *const KBDLLHOOKSTRUCT);
kb.vkCode
}
pub unsafe fn get_scan_code(lpdata: LPARAM) -> DWORD {
pub unsafe fn get_scan_code(lpdata: LPARAM) -> u32 {
let kb = *(lpdata as *const KBDLLHOOKSTRUCT);
kb.scanCode
}
pub unsafe fn get_point(lpdata: LPARAM) -> (LONG, LONG) {
pub unsafe fn get_point(lpdata: LPARAM) -> (i32, i32) {
let mouse = *(lpdata as *const MSLLHOOKSTRUCT);
(mouse.pt.x, mouse.pt.y)
}
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644986(v=vs.85)
/// confusingly, this function returns a WORD (unsigned), but may be
/// confusingly, this function returns a u16 (unsigned), but may be
/// interpreted as either signed or unsigned depending on context
pub unsafe fn get_delta(lpdata: LPARAM) -> WORD {
pub unsafe fn get_delta(lpdata: LPARAM) -> u16 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these conversions are broken we need to revert (and it's ok to maybe alias everything at the beginning of the file).

DWORD is not u16. It might be for the machine, but not for a reader. Semantics are important.

let mouse = *(lpdata as *const MSLLHOOKSTRUCT);
HIWORD(mouse.mouseData)
hiword(mouse.mouseData)
}
pub unsafe fn get_button_code(lpdata: LPARAM) -> WORD {
pub unsafe fn get_button_code(lpdata: LPARAM) -> u16 {
let mouse = *(lpdata as *const MSLLHOOKSTRUCT);
HIWORD(mouse.mouseData)
hiword(mouse.mouseData)
}

pub unsafe fn convert(param: WPARAM, lpdata: LPARAM) -> Option<EventType> {
pub unsafe fn convert(param: usize, lpdata: LPARAM) -> Option<EventType> {
match param.try_into() {
Ok(WM_KEYDOWN) | Ok(WM_SYSKEYDOWN) => {
let code = get_code(lpdata);
Expand Down Expand Up @@ -85,30 +89,30 @@ pub unsafe fn convert(param: WPARAM, lpdata: LPARAM) -> Option<EventType> {
let delta = get_delta(lpdata) as c_short;
Some(EventType::Wheel {
delta_x: 0,
delta_y: (delta / WHEEL_DELTA) as i64,
delta_y: (delta as u32 / WHEEL_DELTA) as i64,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

})
}
Ok(WM_MOUSEHWHEEL) => {
let delta = get_delta(lpdata) as c_short;
Some(EventType::Wheel {
delta_x: (delta / WHEEL_DELTA) as i64,
delta_x: (delta as u32 / WHEEL_DELTA) as i64,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

delta_y: 0,
})
}
_ => None,
}
}

type RawCallback = unsafe extern "system" fn(code: c_int, param: WPARAM, lpdata: LPARAM) -> LRESULT;
type RawCallback = unsafe extern "system" fn(code: c_int, param: usize, lpdata: LPARAM) -> LRESULT;
pub enum HookError {
Mouse(DWORD),
Key(DWORD),
Mouse(u32),
Key(u32),
}

pub unsafe fn set_key_hook(callback: RawCallback) -> Result<(), HookError> {
let hook = SetWindowsHookExA(WH_KEYBOARD_LL, Some(callback), null_mut(), 0);
let hook = SetWindowsHookExA(WH_KEYBOARD_LL, Some(callback), 0, 0);

if hook.is_null() {
if hook == 0 {
let error = GetLastError();
return Err(HookError::Key(error));
}
Expand All @@ -117,8 +121,8 @@ pub unsafe fn set_key_hook(callback: RawCallback) -> Result<(), HookError> {
}

pub unsafe fn set_mouse_hook(callback: RawCallback) -> Result<(), HookError> {
let hook = SetWindowsHookExA(WH_MOUSE_LL, Some(callback), null_mut(), 0);
if hook.is_null() {
let hook = SetWindowsHookExA(WH_MOUSE_LL, Some(callback), 0, 0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if hook == 0 {
let error = GetLastError();
return Err(HookError::Mouse(error));
}
Expand Down
2 changes: 1 addition & 1 deletion src/windows/display.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::rdev::DisplayError;
use std::convert::TryInto;
use winapi::um::winuser::{GetSystemMetrics, SM_CXSCREEN, SM_CYSCREEN};
use windows_sys::Win32::UI::WindowsAndMessaging::{GetSystemMetrics, SM_CXSCREEN, SM_CYSCREEN};

pub fn display_size() -> Result<(u64, u64), DisplayError> {
let w = unsafe {
Expand Down
6 changes: 3 additions & 3 deletions src/windows/grab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use crate::rdev::{Event, EventType, GrabError};
use crate::windows::common::{convert, set_key_hook, set_mouse_hook, HookError, HOOK, KEYBOARD};
use std::ptr::null_mut;
use std::time::SystemTime;
use winapi::um::winuser::{CallNextHookEx, GetMessageA, HC_ACTION};
use windows_sys::Win32::UI::WindowsAndMessaging::{CallNextHookEx, GetMessageA, HC_ACTION};

static mut GLOBAL_CALLBACK: Option<Box<dyn FnMut(Event) -> Option<Event>>> = None;

unsafe extern "system" fn raw_callback(code: i32, param: usize, lpdata: isize) -> isize {
if code == HC_ACTION {
if code == HC_ACTION as i32 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let opt = convert(param, lpdata);
if let Some(event_type) = opt {
let name = match &event_type {
Expand Down Expand Up @@ -53,7 +53,7 @@ where
set_key_hook(raw_callback)?;
set_mouse_hook(raw_callback)?;

GetMessageA(null_mut(), null_mut(), 0, 0);
GetMessageA(null_mut(), 0, 0, 0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
Ok(())
}
30 changes: 16 additions & 14 deletions src/windows/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use crate::rdev::{EventType, Key, KeyboardState};
use crate::windows::common::{get_code, get_scan_code, FALSE, TRUE};
use crate::windows::keycodes::code_from_key;
use std::ptr::null_mut;
use winapi::shared::minwindef::{BYTE, HKL, LPARAM, UINT};
use winapi::um::processthreadsapi::GetCurrentThreadId;
use winapi::um::winuser;
use winapi::um::winuser::{
GetForegroundWindow, GetKeyState, GetKeyboardLayout, GetKeyboardState,
GetWindowThreadProcessId, ToUnicodeEx, VK_CAPITAL, VK_LSHIFT, VK_RSHIFT, VK_SHIFT,
use windows_sys::Win32::Foundation::LPARAM;
use windows_sys::Win32::System::Threading::{AttachThreadInput, GetCurrentThreadId};
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
GetKeyState, GetKeyboardLayout, GetKeyboardState, ToUnicodeEx, VK_CAPITAL, VK_LSHIFT,
VK_RSHIFT, VK_SHIFT,
};
use windows_sys::Win32::UI::TextServices::HKL;

use windows_sys::Win32::UI::WindowsAndMessaging::{GetForegroundWindow, GetWindowThreadProcessId};

const VK_SHIFT_: usize = VK_SHIFT as usize;
const VK_CAPITAL_: usize = VK_CAPITAL as usize;
Expand All @@ -17,9 +19,9 @@ const VK_RSHIFT_: usize = VK_RSHIFT as usize;
const HIGHBIT: u8 = 0x80;

pub struct Keyboard {
last_code: UINT,
last_scan_code: UINT,
last_state: [BYTE; 256],
last_code: u32,
last_scan_code: u32,
last_state: [u8; 256],
last_is_dead: bool,
}

Expand Down Expand Up @@ -47,16 +49,16 @@ impl Keyboard {
let mut state = [0_u8; 256];
let state_ptr = state.as_mut_ptr();

let _shift = GetKeyState(VK_SHIFT);
let _shift = GetKeyState(VK_SHIFT as i32);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let current_window_thread_id = GetWindowThreadProcessId(GetForegroundWindow(), null_mut());
let thread_id = GetCurrentThreadId();
// Attach to active thread so we can get that keyboard state
let status = if winuser::AttachThreadInput(thread_id, current_window_thread_id, TRUE) == 1 {
let status = if AttachThreadInput(thread_id, current_window_thread_id, TRUE) == 1 {
// Current state of the modifiers in keyboard
let status = GetKeyboardState(state_ptr);

// Detach
winuser::AttachThreadInput(thread_id, current_window_thread_id, FALSE);
AttachThreadInput(thread_id, current_window_thread_id, FALSE);
status
} else {
// Could not attach, perhaps it is this process?
Expand All @@ -70,7 +72,7 @@ impl Keyboard {
Some(())
}

pub(crate) unsafe fn get_code_name(&mut self, code: UINT, scan_code: UINT) -> Option<String> {
pub(crate) unsafe fn get_code_name(&mut self, code: u32, scan_code: u32) -> Option<String> {
let current_window_thread_id = GetWindowThreadProcessId(GetForegroundWindow(), null_mut());
let state_ptr = self.last_state.as_mut_ptr();
const BUF_LEN: i32 = 32;
Expand Down Expand Up @@ -113,7 +115,7 @@ impl Keyboard {
result
}

unsafe fn clear_keyboard_buffer(&self, code: UINT, scan_code: UINT, layout: HKL) {
unsafe fn clear_keyboard_buffer(&self, code: u32, scan_code: u32, layout: HKL) {
const BUF_LEN: i32 = 32;
let mut buff = [0_u16; BUF_LEN as usize];
let buff_ptr = buff.as_mut_ptr();
Expand Down
5 changes: 2 additions & 3 deletions src/windows/keycodes.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::rdev::Key;
use std::convert::TryInto;
use winapi::shared::minwindef::WORD;

macro_rules! decl_keycodes {
($($key:ident, $code:literal),*) => {
//TODO: make const when rust lang issue #49146 is fixed
pub fn code_from_key(key: Key) -> Option<WORD> {
pub fn code_from_key(key: Key) -> Option<u16> {
match key {
$(
Key::$key => Some($code),
Expand All @@ -16,7 +15,7 @@ macro_rules! decl_keycodes {
}

//TODO: make const when rust lang issue #49146 is fixed
pub fn key_from_code(code: WORD) -> Key {
pub fn key_from_code(code: u16) -> Key {
match code {
$(
$code => Key::$key,
Expand Down
Loading