这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
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
8 changes: 2 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ version = "0.1.0"
authors = ["Nicolas Patry <patry.nicolas@protonmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.20"
core-graphics = {version = "0.19.0", features = ["highsierra"]}
Expand All @@ -19,6 +13,8 @@ core-graphics = {version = "0.19.0", features = ["highsierra"]}
libc = "0.2"
x11 = {version = "2.18", features = ["xlib", "xrecord"]}

[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winuser", "errhandlingapi"] }

[dev-dependencies]
tokio = {version = "0.2", features=["process", "rt-core", "io-util", "macros"]}
4 changes: 2 additions & 2 deletions examples/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ fn send(event_type: &EventType) {
}

fn main() {
send(&EventType::KeyPress { code: 39 });
send(&EventType::KeyRelease { code: 39 });
send(&EventType::KeyPress { code: 83 });
send(&EventType::KeyRelease { code: 83 });

send(&EventType::MouseMove { x: 0.0, y: 0.0 });
send(&EventType::MouseMove { x: 400.0, y: 400.0 });
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ mod linux;

#[cfg(target_os = "linux")]
pub use crate::linux::{listen, simulate};

#[cfg(target_os = "windows")]
mod win;

#[cfg(target_os = "windows")]
pub use crate::win::{listen, simulate};
4 changes: 1 addition & 3 deletions src/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extern crate libc;
extern crate x11;

use crate::rdev::{Event, EventType, SimulateError};
use crate::rdev::{Event, EventType, SimulateError, Callback};
use std::ffi::CString;
use std::os::raw::c_int;
use std::ptr::{null, null_mut};
Expand All @@ -12,8 +12,6 @@ use x11::xtest;

static mut EVENT_COUNT: u32 = 0;

type Callback = fn(event: Event);

fn default_callback(event: Event) {
println!("Default : Event {:?}", event);
}
Expand Down
3 changes: 3 additions & 0 deletions src/rdev.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::time::SystemTime;

/// Callback type to send to listen function.
pub type Callback = fn(event: Event);

/// Marking an error when we tried to simulate and event
#[derive(Debug)]
pub struct SimulateError;
Expand Down
241 changes: 241 additions & 0 deletions src/win/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
extern crate winapi;

use crate::rdev::{Callback, Event, EventType, SimulateError};
use std::mem::{size_of, transmute, transmute_copy};
use std::ptr::null_mut;
use std::time::SystemTime;
use winapi::ctypes::c_int;
use winapi::shared::windef::{HHOOK};
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winuser::{
CallNextHookEx, GetMessageA, GetSystemMetrics, SendInput, SetWindowsHookExA, HC_ACTION, INPUT,
INPUT_KEYBOARD, INPUT_MOUSE, KBDLLHOOKSTRUCT, KEYBDINPUT, KEYEVENTF_KEYUP, LPINPUT,
MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP,
MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN,
MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT,
MSLLHOOKSTRUCT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, 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_XBUTTONDOWN,
WM_XBUTTONUP,
};

static KEYEVENTF_KEYDOWN: u32 = 0; // Not defined in win32 but define here for clarity

fn default_callback(event: Event) {
println!("Default : Event {:?}", event);
}

static mut GLOBAL_CALLBACK: Callback = default_callback;
static mut HOOK: HHOOK = null_mut();

unsafe fn get_code(lpdata: isize) -> u8 {
let kb = *(lpdata as *const KBDLLHOOKSTRUCT);
kb.vkCode as u8
}
unsafe fn get_point(lpdata: isize) -> (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)
unsafe fn get_delta(lpdata: isize) -> i32 {
let mouse = *(lpdata as *const MSLLHOOKSTRUCT);
(mouse.mouseData as i32 >> 16) as i32
}
unsafe fn get_button_code(lpdata: isize) -> i32 {
let mouse = *(lpdata as *const MSLLHOOKSTRUCT);
(mouse.mouseData as i32 >> 16) as i32
}

unsafe extern "system" fn raw_callback(code: i32, param: usize, lpdata: isize) -> isize {
if code == HC_ACTION {
let opt = match param {
x if x == WM_KEYDOWN as usize => {
let code = get_code(lpdata);
Some(EventType::KeyPress { code })
}
x if x == WM_KEYUP as usize => {
let code = get_code(lpdata);
Some(EventType::KeyRelease { code })
}
x if x == WM_LBUTTONDOWN as usize => Some(EventType::ButtonPress { code: 1 }),
x if x == WM_LBUTTONUP as usize => Some(EventType::ButtonRelease { code: 1 }),
x if x == WM_MBUTTONDOWN as usize => Some(EventType::ButtonPress { code: 2 }),
x if x == WM_MBUTTONUP as usize => Some(EventType::ButtonRelease { code: 2 }),
x if x == WM_RBUTTONDOWN as usize => Some(EventType::ButtonPress { code: 3 }),
x if x == WM_RBUTTONUP as usize => Some(EventType::ButtonRelease { code: 3 }),
x if x == WM_XBUTTONDOWN as usize => {
let code = get_button_code(lpdata) as u8 + 3;
Some(EventType::ButtonPress { code })
}
x if x == WM_XBUTTONUP as usize => {
let code = get_button_code(lpdata) as u8 + 3;

Some(EventType::ButtonRelease { code })
}

x if x == WM_MOUSEMOVE as usize => {
let (x, y) = get_point(lpdata);
Some(EventType::MouseMove {
x: x as f64,
y: y as f64,
})
}
x if x == WM_MOUSEWHEEL as usize => {
let delta = get_delta(lpdata);
Some(EventType::Wheel {
delta_x: 0,
delta_y: (delta as i64) / WHEEL_DELTA as i64,
})
}
x if x == WM_MOUSEHWHEEL as usize => {
let delta = get_delta(lpdata);

Some(EventType::Wheel {
delta_x: (delta as i64) / WHEEL_DELTA as i64,
delta_y: 0,
})
}
_ => None,
};

if let Some(event_type) = opt {
let event = Event {
event_type,
time: SystemTime::now(),
name: None,
};
GLOBAL_CALLBACK(event);
}
}
CallNextHookEx(HOOK, code, param, lpdata)
}

unsafe fn set_key_hook() {
let hook = SetWindowsHookExA(WH_KEYBOARD_LL, Some(raw_callback), null_mut(), 0);
if hook == null_mut() {
let error = GetLastError();
panic!("Can't set system hook! {:?}", error)
}
HOOK = hook;
}
unsafe fn set_mouse_hook() {
let hook = SetWindowsHookExA(WH_MOUSE_LL, Some(raw_callback), null_mut(), 0);
if hook == null_mut() {
let error = GetLastError();
panic!("Can't set system hook! {:?}", error)
}
HOOK = hook;
}

pub fn listen(callback: Callback) {
unsafe {
GLOBAL_CALLBACK = callback;
set_key_hook();
set_mouse_hook();

GetMessageA(null_mut(), null_mut(), 0, 0);
}
}

fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> Result<(), SimulateError> {
let mut input = INPUT {
type_: INPUT_MOUSE,
u: unsafe {
transmute(MOUSEINPUT {
dx,
dy,
mouseData: data,
dwFlags: flags,
time: 0,
dwExtraInfo: 0,
})
},
};
let value = unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
if value!= 1{
Err(SimulateError)
}else{
Ok(())
}
}

fn keyboard_event(flags: u32, vk: u16, scan: u16) -> Result<(), SimulateError> {
let mut input = INPUT {
type_: INPUT_KEYBOARD,
u: unsafe {
transmute_copy(&KEYBDINPUT {
wVk: vk,
wScan: scan,
dwFlags: flags,
time: 0,
dwExtraInfo: 0,
})
},
};
let value = unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
if value != 1{
Err(SimulateError)
}else{
Ok(())
}
}

pub fn simulate(event_type: &EventType) -> Result<(), SimulateError> {
match event_type {
EventType::KeyPress { code } => keyboard_event(KEYEVENTF_KEYDOWN, *code as u16, 0),
EventType::KeyRelease { code } => keyboard_event(KEYEVENTF_KEYUP, *code as u16, 0),
EventType::ButtonPress { code } => match code {
1 => mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0),
2 => mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0),
3 => mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0),
_ => mouse_event(MOUSEEVENTF_XDOWN, 0, 0, (code - 3) as i32),
},
EventType::ButtonRelease { code } => match code {
1 => mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0),
2 => mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0),
3 => mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0),
_ => mouse_event(MOUSEEVENTF_XUP, 0, 0, (code - 3) as i32),
},
EventType::Wheel { delta_x, delta_y } => {
let result_x = if *delta_x != 0 {
mouse_event(
MOUSEEVENTF_HWHEEL,
0,
(delta_x * WHEEL_DELTA as i64) as i32,
0,
)
} else {
Ok(())
};

let result_y = if *delta_y != 0 {
mouse_event(
MOUSEEVENTF_WHEEL,
0,
0,
(delta_y * WHEEL_DELTA as i64) as i32,
)
} else {
Ok(())
};

if result_x.is_ok() && result_y.is_ok() {
Ok(())
} else {
Err(SimulateError)
}
}
EventType::MouseMove { x, y } => {
let width = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) };
let height = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) };


mouse_event(
MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
0,
(*x * 65335.0) as i32 / width,
(*y * 65335.0) as i32 / height,
)
}
}
}
Loading