diff --git a/.gitignore b/.gitignore index 96ef6c0..1b4fcfd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,13 @@ + +.DS_Store + +# Generated by Cargo +# will have compiled files and executables /target + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock Cargo.lock + +# RustFmt files +**/*.rs.bk diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7404ac1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "editor.autoClosingBrackets": "languageDefined", + "editor.trimAutoWhitespace": true, + "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true, + "files.watcherExclude": { + "**/target": true + } +} diff --git a/Cargo.toml b/Cargo.toml index 41f3198..ae9a65e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,20 @@ [package] name = "robot-rust" -version = "0.1.0" -authors = ["crusader "] +version = "0.0.1" +authors = ["richard park "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde = { version = "1.0.117", optional = true } +serde_derive = { version = "1.0.117", optional = true } + +[features] +with_serde = ["serde", "serde_derive"] + +[target.'cfg(target_os = "windows")'.dependencies] +winapi = { version = "0.3.9", features = ["winuser"] } + +[build-dependencies] +pkg-config = "0.3.19" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..f17100a --- /dev/null +++ b/build.rs @@ -0,0 +1,2 @@ +#[cfg(target_os = "windows")] +fn main() {} diff --git a/src/keyboard/mod.rs b/src/keyboard/mod.rs new file mode 100644 index 0000000..1d4bd7f --- /dev/null +++ b/src/keyboard/mod.rs @@ -0,0 +1,121 @@ +pub enum KeyboardKey { + Escape, + Digit0, + Digit1, + Digit2, + Digit3, + Digit4, + Digit5, + Digit6, + Digit7, + Digit8, + Digit9, + KeyA, + KeyB, + KeyC, + KeyD, + KeyE, + KeyF, + KeyG, + KeyH, + KeyI, + KeyJ, + KeyK, + KeyL, + KeyM, + KeyN, + KeyO, + KeyP, + KeyQ, + KeyR, + KeyS, + KeyT, + KeyU, + KeyV, + KeyW, + KeyX, + KeyY, + KeyZ, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + F21, + F22, + F23, + F24, + Numpad0, + Numpad1, + Numpad2, + Numpad3, + Numpad4, + Numpad5, + Numpad6, + Numpad7, + Numpad8, + Numpad9, + NumpadAdd, + NumpadSubtract, + NumpadMultiply, + NumpadDecimal, + NumpadEqual, + NumpadComma, + NumpadEnter, + NumLock, + Minus, + Equal, + BracketLeft, + BracketRight, + Semicolon, + Quote, + Backquote, + Backslash, + Comma, + Period, + Slash, + Enter, + Backspace, + Tab, + Space, + CapsLock, + ShiftLeft, + ShiftRight, + ControlLeft, + ControlRight, + AltLeft, + AltRight, + Pause, + ScrollLock, + PrintScreen, + ArrowLeft, + ArrowUp, + ArrowRight, + ArrowDown, + PageUp, + PageDown, + Home, + End, + Insert, + Delete, + MetaLeft, + MetaRight, + ContextMenu, +} + +pub struct Keyboard; diff --git a/src/keyboard/windows/key_codes.rs b/src/keyboard/windows/key_codes.rs new file mode 100644 index 0000000..e158cea --- /dev/null +++ b/src/keyboard/windows/key_codes.rs @@ -0,0 +1,153 @@ +// // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731 + +// pub const VK_LBUTTON: u16 = 0x01; // Left mouse button +// pub const VK_RBUTTON: u16 = 0x02; // Right mouse button +// pub const VK_CANCEL: u16 = 0x03; // Control-break processing +// pub const VK_MBUTTON: u16 = 0x04; // Middle mouse button (three-button mouse) +// pub const VK_XBUTTON1: u16 = 0x05; // X1 mouse button +// pub const VK_XBUTTON2: u16 = 0x06; // X2 mouse button +// pub const VK_BACK: u16 = 0x08; // BACKSPACE key +// pub const VK_TAB: u16 = 0x09; // TAB key +// pub const VK_CLEAR: u16 = 0x0C; // CLEAR key +// pub const VK_RETURN: u16 = 0x0D; // ENTER key +// pub const VK_SHIFT: u16 = 0x10; // SHIFT key +// pub const VK_CONTROL: u16 = 0x11; // CTRL key +// pub const VK_MENU: u16 = 0x12; // ALT key +// pub const VK_PAUSE: u16 = 0x13; // PAUSE key +// pub const VK_CAPITAL: u16 = 0x14; // CAPS LOCK key +// pub const VK_KANA: u16 = 0x15; // IME Kana mode +// pub const VK_HANGUEL: u16 = 0x15; // IME Hanguel mode (maintained for compatibility; use VK_HANGUL) +// pub const VK_HANGUL: u16 = 0x15; // IME Hangul mode +// pub const VK_IME_ON: u16 = 0x16; // IME On +// pub const VK_JUNJA: u16 = 0x17; // IME Junja mode +// pub const VK_FINAL: u16 = 0x18; // IME final mode +// pub const VK_HANJA: u16 = 0x19; // IME Hanja mode +// pub const VK_KANJI: u16 = 0x19; // IME Kanji mode +// pub const VK_IME_OFF: u16 = 0x1A; // IME Off +// pub const VK_ESCAPE: u16 = 0x1B; // ESC key +// pub const VK_CONVERT: u16 = 0x1C; // IME convert +// pub const VK_NONCONVERT: u16 = 0x1D; // IME nonconvert +// pub const VK_ACCEPT: u16 = 0x1E; // IME accept +// pub const VK_MODECHANGE: u16 = 0x1F; // IME mode change request +// pub const VK_SPACE: u16 = 0x20; // SPACEBAR +// pub const VK_PRIOR: u16 = 0x21; // PAGE UP key +// pub const VK_NEXT: u16 = 0x22; // PAGE DOWN key +// pub const VK_END: u16 = 0x23; // END key +// pub const VK_HOME: u16 = 0x24; // HOME key +// pub const VK_LEFT: u16 = 0x25; // LEFT ARROW key +// pub const VK_UP: u16 = 0x26; // UP ARROW key +// pub const VK_RIGHT: u16 = 0x27; // RIGHT ARROW key +// pub const VK_DOWN: u16 = 0x28; // DOWN ARROW key +// pub const VK_SELECT: u16 = 0x29; // SELECT key +// pub const VK_PRINT: u16 = 0x2A; // PRINT key +// pub const VK_EXECUTE: u16 = 0x2B; // EXECUTE key +// pub const VK_SNAPSHOT: u16 = 0x2C; // PRINT SCREEN key +// pub const VK_INSERT: u16 = 0x2D; // INS key +// pub const VK_DELETE: u16 = 0x2E; // DEL key +// pub const VK_HELP: u16 = 0x2F; // HELP key +// pub const VK_DIGIT_0: u16 = 0x30; // 0 key +// pub const VK_DIGIT_1: u16 = 0x31; // 1 key +// pub const VK_DIGIT_2: u16 = 0x32; // 2 key +// pub const VK_DIGIT_3: u16 = 0x33; // 3 key +// pub const VK_DIGIT_4: u16 = 0x34; // 4 key +// pub const VK_DIGIT_5: u16 = 0x35; // 5 key +// pub const VK_DIGIT_6: u16 = 0x36; // 6 key +// pub const VK_DIGIT_7: u16 = 0x37; // 7 key +// pub const VK_DIGIT_8: u16 = 0x38; // 8 key +// pub const VK_DIGIT_9: u16 = 0x39; // 9 key +// pub const VK_KEY_A: u16 = 0x41; // A key +// pub const VK_KEY_B: u16 = 0x42; // B key +// pub const VK_KEY_C: u16 = 0x43; // C key +// pub const VK_KEY_D: u16 = 0x44; // D key +// pub const VK_KEY_E: u16 = 0x45; // E key +// pub const VK_KEY_F: u16 = 0x46; // F key +// pub const VK_KEY_G: u16 = 0x47; // G key +// pub const VK_KEY_H: u16 = 0x48; // H key +// pub const VK_KEY_I: u16 = 0x49; // I key +// pub const VK_KEY_J: u16 = 0x4A; // J key +// pub const VK_KEY_K: u16 = 0x4B; // K key +// pub const VK_KEY_L: u16 = 0x4C; // L key +// pub const VK_KEY_M: u16 = 0x4D; // M key +// pub const VK_KEY_N: u16 = 0x4E; // N key +// pub const VK_KEY_O: u16 = 0x4F; // O key +// pub const VK_KEY_P: u16 = 0x50; // P key +// pub const VK_KEY_Q: u16 = 0x51; // Q key +// pub const VK_KEY_R: u16 = 0x52; // R key +// pub const VK_KEY_S: u16 = 0x53; // S key +// pub const VK_KEY_T: u16 = 0x54; // T key +// pub const VK_KEY_U: u16 = 0x55; // U key +// pub const VK_KEY_V: u16 = 0x56; // V key +// pub const VK_KEY_W: u16 = 0x57; // W key +// pub const VK_KEY_X: u16 = 0x58; // X key +// pub const VK_KEY_Y: u16 = 0x59; // Y key +// pub const VK_KEY_Z: u16 = 0x5A; // Z key +// pub const VK_LWIN: u16 = 0x5B; // Left Windows key (Natural keyboard) +// pub const VK_RWIN: u16 = 0x5C; // Right Windows key (Natural keyboard) +// pub const VK_APPS: u16 = 0x5D; // Applications key (Natural keyboard) +// pub const VK_SLEEP: u16 = 0x5F; // Computer Sleep key +// pub const VK_NUMPAD0: u16 = 0x60; // Numeric keypad 0 key +// pub const VK_NUMPAD1: u16 = 0x61; // Numeric keypad 1 key +// pub const VK_NUMPAD2: u16 = 0x62; // Numeric keypad 2 key +// pub const VK_NUMPAD3: u16 = 0x63; // Numeric keypad 3 key +// pub const VK_NUMPAD4: u16 = 0x64; // Numeric keypad 4 key +// pub const VK_NUMPAD5: u16 = 0x65; // Numeric keypad 5 key +// pub const VK_NUMPAD6: u16 = 0x66; // Numeric keypad 6 key +// pub const VK_NUMPAD7: u16 = 0x67; // Numeric keypad 7 key +// pub const VK_NUMPAD8: u16 = 0x68; // Numeric keypad 8 key +// pub const VK_NUMPAD9: u16 = 0x69; // Numeric keypad 9 key +// pub const VK_MULTIPLY: u16 = 0x6A; // Multiply key +// pub const VK_ADD: u16 = 0x6B; // Add key +// pub const VK_SEPARATOR: u16 = 0x6C; // Separator key +// pub const VK_SUBTRACT: u16 = 0x6D; // Subtract key +// pub const VK_DECIMAL: u16 = 0x6E; // Decimal key +// pub const VK_DIVIDE: u16 = 0x6F; // Divide key +// pub const VK_F1: u16 = 0x70; // F1 key +// pub const VK_F2: u16 = 0x71; // F2 key +// pub const VK_F3: u16 = 0x72; // F3 key +// pub const VK_F4: u16 = 0x73; // F4 key +// pub const VK_F5: u16 = 0x74; // F5 key +// pub const VK_F6: u16 = 0x75; // F6 key +// pub const VK_F7: u16 = 0x76; // F7 key +// pub const VK_F8: u16 = 0x77; // F8 key +// pub const VK_F9: u16 = 0x78; // F9 key +// pub const VK_F10: u16 = 0x79; // F10 key +// pub const VK_F11: u16 = 0x7A; // F11 key +// pub const VK_F12: u16 = 0x7B; // F12 key +// pub const VK_F13: u16 = 0x7C; // F13 key +// pub const VK_F14: u16 = 0x7D; // F14 key +// pub const VK_F15: u16 = 0x7E; // F15 key +// pub const VK_F16: u16 = 0x7F; // F16 key +// pub const VK_F17: u16 = 0x80; // F17 key +// pub const VK_F18: u16 = 0x81; // F18 key +// pub const VK_F19: u16 = 0x82; // F19 key +// pub const VK_F20: u16 = 0x83; // F20 key +// pub const VK_F21: u16 = 0x84; // F21 key +// pub const VK_F22: u16 = 0x85; // F22 key +// pub const VK_F23: u16 = 0x86; // F23 key +// pub const VK_F24: u16 = 0x87; // F24 key +// pub const VK_NUMLOCK: u16 = 0x90; // NUM LOCK key +// pub const VK_SCROLL: u16 = 0x91; // SCROLL LOCK key +// pub const VK_LSHIFT: u16 = 0xA0; // Left SHIFT key +// pub const VK_RSHIFT: u16 = 0xA1; // Right SHIFT key +// pub const VK_LCONTROL: u16 = 0xA2; // Left CONTROL key +// pub const VK_RCONTROL: u16 = 0xA3; // Right CONTROL key +// pub const VK_LMENU: u16 = 0xA4; // Left MENU key +// pub const VK_RMENU: u16 = 0xA5; // Right MENU key +// pub const VK_BROWSER_BACK: u16 = 0xA6; // Browser Back key +// pub const VK_BROWSER_FORWARD: u16 = 0xA7; // Browser Forward key +// pub const VK_BROWSER_REFRESH: u16 = 0xA8; // Browser Refresh key +// pub const VK_BROWSER_STOP: u16 = 0xA9; // Browser Stop key +// pub const VK_BROWSER_SEARCH: u16 = 0xAA; // Browser Search key +// pub const VK_BROWSER_FAVORITES: u16 = 0xAB; // Browser Favorites key +// pub const VK_BROWSER_HOME: u16 = 0xAC; // Browser Start and Home key +// pub const VK_VOLUME_MUTE: u16 = 0xAD; // Volume Mute key +// pub const VK_VOLUME_DOWN: u16 = 0xAE; // Volume Down key +// pub const VK_VOLUME_UP: u16 = 0xAF; // Volume Up key +// pub const VK_MEDIA_NEXT_TRACK: u16 = 0xB0; // Next Track key +// pub const VK_MEDIA_PREV_TRACK: u16 = 0xB1; // Previous Track key +// pub const VK_MEDIA_STOP: u16 = 0xB2; // Stop Media key +// pub const VK_MEDIA_PLAY_PAUSE: u16 = 0xB3; // Play/Pause Media key +// pub const VK_LAUNCH_MAIL: u16 = 0xB4; // Start Mail key +// pub const VK_LAUNCH_MEDIA_SELECT: u16 = 0xB5; // Select Media key +// pub const VK_LAUNCH_APP1: u16 = 0xB6; // Start Application 1 key +// pub const VK_LAUNCH_APP2: u16 = 0xB7; // Start Application 2 key diff --git a/src/keyboard/windows/mod.rs b/src/keyboard/windows/mod.rs new file mode 100644 index 0000000..efce1dd --- /dev/null +++ b/src/keyboard/windows/mod.rs @@ -0,0 +1 @@ +impl Keyboard {} diff --git a/src/lib.rs b/src/lib.rs index 31e1bb2..73cdf76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,2 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +pub mod keyboard; +pub mod mouse; diff --git a/src/mouse/mod.rs b/src/mouse/mod.rs new file mode 100644 index 0000000..abe1fa9 --- /dev/null +++ b/src/mouse/mod.rs @@ -0,0 +1,20 @@ +#[cfg(target_os = "windows")] +mod windows; +#[cfg(target_os = "windows")] +pub use crate::mouse::windows::*; + +pub enum Button { + Left, + Middle, + Right, + X1, + X2, + Other(u32), +} + +pub enum ButtonState { + Press, + Release, +} + +pub struct Mouse; diff --git a/src/mouse/windows/mod.rs b/src/mouse/windows/mod.rs new file mode 100644 index 0000000..3344fe1 --- /dev/null +++ b/src/mouse/windows/mod.rs @@ -0,0 +1,123 @@ +use std::mem::{size_of, transmute}; +use winapi::ctypes::c_int; +use winapi::shared::minwindef::DWORD; +use winapi::um::winuser::{ + GetAsyncKeyState, SendInput, INPUT, INPUT_MOUSE, LPINPUT, MOUSEEVENTF_ABSOLUTE, + MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, + MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK, + MOUSEINPUT, VK_LBUTTON, VK_MBUTTON, VK_RBUTTON, VK_XBUTTON1, VK_XBUTTON2, +}; + +use crate::mouse::{Button, ButtonState, Mouse}; + +impl Mouse { + pub fn move_to(absolute: bool, dx: i32, dy: i32) { + let pressed_left = Self::pressed(Button::Left); + let pressed_right = Self::pressed(Button::Right); + let pressed_middle = Self::pressed(Button::Middle); + + let mut dw_flags = MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK; + + if absolute { + dw_flags = dw_flags | MOUSEEVENTF_ABSOLUTE; + } + if pressed_left { + dw_flags = dw_flags | MOUSEEVENTF_LEFTDOWN; + } + if pressed_right { + dw_flags = dw_flags | MOUSEEVENTF_RIGHTDOWN; + } + if pressed_middle { + dw_flags = dw_flags | MOUSEEVENTF_MIDDLEDOWN; + } + + let mut input = INPUT { + type_: INPUT_MOUSE, + u: unsafe { + transmute(MOUSEINPUT { + dx, + dy, + mouseData: 0, + dwFlags: dw_flags, + time: 0, + dwExtraInfo: 0, + }) + }, + }; + unsafe { SendInput(1, &mut input as LPINPUT, size_of::() as c_int) }; + } + + pub fn press(button: Button) { + let btn = Self::button_event(button, ButtonState::Press); + + let dw_flags = btn; + + let mut input = INPUT { + type_: INPUT_MOUSE, + u: unsafe { + transmute(MOUSEINPUT { + dx: 0, + dy: 0, + mouseData: 0, + dwFlags: dw_flags, + time: 0, + dwExtraInfo: 0, + }) + }, + }; + unsafe { SendInput(1, &mut input as LPINPUT, size_of::() as c_int) }; + } + + pub fn release(button: Button) { + let btn = Self::button_event(button, ButtonState::Release); + + let dw_flags = btn; + + let mut input = INPUT { + type_: INPUT_MOUSE, + u: unsafe { + transmute(MOUSEINPUT { + dx: 0, + dy: 0, + mouseData: 0, + dwFlags: dw_flags, + time: 0, + dwExtraInfo: 0, + }) + }, + }; + unsafe { SendInput(1, &mut input as LPINPUT, size_of::() as c_int) }; + } + + pub fn pressed(button: Button) -> bool { + (unsafe { GetAsyncKeyState(Self::button_virtual_key(button)) } >> 15) != 0 + } + + fn button_event(button: Button, state: ButtonState) -> DWORD { + match state { + ButtonState::Press => match button { + Button::Left => MOUSEEVENTF_LEFTDOWN, + Button::Middle => MOUSEEVENTF_MIDDLEDOWN, + Button::Right => MOUSEEVENTF_RIGHTDOWN, + _ => unimplemented!(), + }, + ButtonState::Release => match button { + Button::Left => MOUSEEVENTF_LEFTUP, + Button::Middle => MOUSEEVENTF_MIDDLEUP, + Button::Right => MOUSEEVENTF_RIGHTUP, + _ => unimplemented!(), + }, + } + } + + fn button_virtual_key(button: Button) -> c_int { + match button { + Button::Left => VK_LBUTTON, + Button::Middle => VK_MBUTTON, + Button::Right => VK_RBUTTON, + Button::X1 => VK_XBUTTON1, + Button::X2 => VK_XBUTTON2, + _ => unimplemented!(), + } + } +} diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..8915d42 --- /dev/null +++ b/src/test.rs @@ -0,0 +1,9 @@ +use crate::mouse::Mouse; + +#[cfg(test)] +mod tests { + #[test] + fn mouse_moto_to() { + Mouse::move_to(true, 500, 30); + } +}