From b6510099497d03356250b0238feb6ad040ec7f4c Mon Sep 17 00:00:00 2001 From: Gabriel <68819302+obsidianical@users.noreply.github.com> Date: Wed, 15 Jun 2022 14:06:27 +0200 Subject: [PATCH] formatted with cargo, cleaned up imports and dependencies. --- Cargo.toml | 2 +- README.md | 6 +- src/bin/easymacroplay.rs | 49 ++++++------ src/bin/easymacrorec.rs | 6 +- src/x11_safe_wrapper.rs | 158 +++++++++++++++++++++------------------ 5 files changed, 117 insertions(+), 104 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d7f0a13..d517ec4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "easymacros" version = "0.1.0" +author = "obsidianical" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] x11 = { version = "2.19.1", features = ["xlib", "xtest"] } -x11-keysymdef = "0.2.0" clap = { version = "3.2.4", features = ["derive"] } \ No newline at end of file diff --git a/README.md b/README.md index e5f955f..24418a4 100644 --- a/README.md +++ b/README.md @@ -44,4 +44,8 @@ I may or may not do these, but they sound fun to implement to me! - [x] Linux x11 (only tested on i3wm) - [ ] Linux Wayland (makes heavy use of X apis, I will only do this if I myself switch to Wayland. I'm open to suggestions how to do it though!) - [ ] MacOS (Might work because of XQuartz?) -- [ ] Windows (Yeah, I'm not doing that myself. Unless I have to use Windows for anything.) \ No newline at end of file +- [ ] Windows (Yeah, I'm not doing that myself. Unless I have to use Windows for anything.) + +## Installation + +Currently only manually possible via `cargo build --release` and then moving the result into your $PATH. \ No newline at end of file diff --git a/src/bin/easymacroplay.rs b/src/bin/easymacroplay.rs index fa2669c..5a73383 100644 --- a/src/bin/easymacroplay.rs +++ b/src/bin/easymacroplay.rs @@ -1,26 +1,18 @@ -use std::ffi::{CStr, CString}; -use std::os::raw::{c_char, c_int, c_uint}; -use std::process::exit; -use std::slice::from_raw_parts; -use std::{fs, thread}; -use std::time::Duration; -use x11::xlib::{Display, XCloseDisplay, XDisplayString, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync}; use clap::Parser; -use x11::keysym::{XK_d, XK_Super_L}; -use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension}; -use x11_keysymdef::lookup_by_name; use easymacros::x11_safe_wrapper::{Keysym, XDisplay}; +use std::ffi::CString; +use std::process::exit; +use std::time::Duration; +use std::{fs, thread}; - - -/// Macro program inspired by xmacro. +/// Macro player module for easymacros. It's partially compatible with xmacro macros, with aim for full compatibility. #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { - /// Input file + /// The file that contains the macro to run. #[clap(value_parser, value_name = "input_file", value_hint = clap::ValueHint::FilePath)] input_file: std::path::PathBuf, - /// Display + /// Display to run the macro on. This uses the $DISPLAY environment variable by default. #[clap(short, long)] display: Option, // xmacro compatibility, currently the only supported input format anyway @@ -28,11 +20,12 @@ struct Args { // xmacro: bool, } -fn main () { +fn main() { let args = Args::parse(); // let xmacro_mode = args.xmacro; - let input_file_contents = fs::read_to_string(args.input_file).expect("couldn't read macro file"); + let input_file_contents = + fs::read_to_string(args.input_file).expect("couldn't read macro file"); let display = get_remote(args.display); for instruction in input_file_contents.lines() { @@ -43,23 +36,29 @@ fn main () { "Delay" => thread::sleep(Duration::from_millis(command[1].parse().unwrap())), "ButtonPress" => display.send_fake_buttonpress(command[1].parse().unwrap()), "ButtonRelease" => display.send_fake_buttonrelease(command[1].parse().unwrap()), - "MotionNotify" => display.send_fake_motion_event(command[1].parse().unwrap(), command[2].parse().unwrap()), + "MotionNotify" => display + .send_fake_motion_event(command[1].parse().unwrap(), command[2].parse().unwrap()), "KeyCodePress" => display.send_fake_keypress_from_code(command[1].parse().unwrap()), "KeyCodeRelease" => display.send_fake_keyrelease_from_code(command[1].parse().unwrap()), "KeySymPress" => display.send_fake_keypress_from_keysym(command[1].parse().unwrap()), - "KeySymRelease" => display.send_fake_keyrelease_from_keysym(command[1].parse().unwrap()), + "KeySymRelease" => { + display.send_fake_keyrelease_from_keysym(command[1].parse().unwrap()) + } "KeySym" => { let key: Keysym = command[1].parse().unwrap(); display.send_fake_keypress_from_keysym(key); display.send_fake_keyrelease_from_keysym(key); - }, - "KeyStrPress" => display.send_fake_keypress_from_string(CString::new(command[1]).unwrap().as_bytes()), - "KeyStrRelease" => display.send_fake_keyrelease_from_string(CString::new(command[1]).unwrap().as_bytes()), + } + "KeyStrPress" => { + display.send_fake_keypress_from_string(CString::new(command[1]).unwrap().as_bytes()) + } + "KeyStrRelease" => display + .send_fake_keyrelease_from_string(CString::new(command[1]).unwrap().as_bytes()), "KeyStr" => { let keystring = CString::new(command[1]).unwrap(); display.send_fake_keypress_from_string(keystring.as_bytes()); display.send_fake_keyrelease_from_string(keystring.as_bytes()); - }, + } "String" => { println!("Strings are currently not supported."); // for c in instruction[7..].chars() { @@ -67,7 +66,9 @@ fn main () { // display.send_fake_keyrelease_from_string(CString::new(c.to_string()).unwrap().as_bytes()); // } } - c => {panic!("Unknown command {}", c)} + c => { + panic!("Unknown command {}", c) + } } } diff --git a/src/bin/easymacrorec.rs b/src/bin/easymacrorec.rs index 08df7b8..c89b901 100644 --- a/src/bin/easymacrorec.rs +++ b/src/bin/easymacrorec.rs @@ -1,5 +1,3 @@ -use easymacros::add; - fn main() { - println!("rec: {}", add(2, 2)); -} \ No newline at end of file + todo!(); +} diff --git a/src/x11_safe_wrapper.rs b/src/x11_safe_wrapper.rs index 3c142ab..b7f119f 100644 --- a/src/x11_safe_wrapper.rs +++ b/src/x11_safe_wrapper.rs @@ -1,11 +1,16 @@ use std::env; -use std::ffi::{CStr, CString}; -use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ulong}; -use x11::xlib::{Display, XCloseDisplay, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync}; -use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension}; +use std::ffi::CString; +use std::os::raw::{c_char, c_int, c_uint, c_ulong}; +use x11::xlib::{ + Display, XCloseDisplay, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync, +}; +use x11::xtest::{ + XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, + XTestQueryExtension, +}; pub struct XDisplay { - ptr: *mut Display, + ptr: *mut Display, } pub type Keysym = c_ulong; @@ -15,93 +20,98 @@ const FALSE_C: c_int = 0; const TRUE_C: c_int = 1; impl XDisplay { - pub fn open(display_name: Option) -> Self { - let name = CString::new(if let Some(name) = display_name { name } else { env::var("DISPLAY").expect("DISPLAY is not set") }).unwrap(); - let name_ptr = name.as_bytes().as_ptr(); - let display_ptr = unsafe { XOpenDisplay(name_ptr as *const i8) }; + pub fn open(display_name: Option) -> Self { + let name = CString::new(if let Some(name) = display_name { + name + } else { + env::var("DISPLAY").expect("DISPLAY is not set") + }) + .unwrap(); + let name_ptr = name.as_bytes().as_ptr(); + let display_ptr = unsafe { XOpenDisplay(name_ptr as *const i8) }; - Self { ptr: display_ptr } - } + Self { ptr: display_ptr } + } - pub fn close(self) { - unsafe { XCloseDisplay(self.ptr) }; - } + pub fn close(self) { + unsafe { XCloseDisplay(self.ptr) }; + } - pub fn sync(&self) { - unsafe { XSync(self.ptr, c_int::from(false)); } - } + pub fn sync(&self) { + unsafe { + XSync(self.ptr, c_int::from(false)); + } + } - pub fn flush(&self) { - unsafe { XFlush(self.ptr); } - } + pub fn flush(&self) { + unsafe { + XFlush(self.ptr); + } + } - pub fn keysym_to_keycode(&self, keysym: c_ulong) -> Keycode { - unsafe { XKeysymToKeycode(self.ptr, keysym) as Keycode } - } + pub fn keysym_to_keycode(&self, keysym: c_ulong) -> Keycode { + unsafe { XKeysymToKeycode(self.ptr, keysym) as Keycode } + } - pub fn string_to_keycode(&self, string: &[u8]) -> Keycode { - self.keysym_to_keycode(string_to_keysym(string)) - } + pub fn string_to_keycode(&self, string: &[u8]) -> Keycode { + self.keysym_to_keycode(string_to_keysym(string)) + } - pub fn has_xtest(&self) -> bool { - let mut vals: (c_int, c_int, c_int, c_int) = (0, 0, 0, 0); - let has_extension = unsafe { - XTestQueryExtension( - self.ptr, - &mut vals.0, - &mut vals.1, - &mut vals.2, - &mut vals.3 - ) - }; - has_extension != 0 - } + pub fn has_xtest(&self) -> bool { + let mut vals: (c_int, c_int, c_int, c_int) = (0, 0, 0, 0); + let has_extension = unsafe { + XTestQueryExtension(self.ptr, &mut vals.0, &mut vals.1, &mut vals.2, &mut vals.3) + }; + has_extension != 0 + } - pub fn send_fake_keypress_from_string(&self, string: &[u8]) { - self.send_fake_keypress_from_keysym(string_to_keysym(string)) - } + pub fn send_fake_keypress_from_string(&self, string: &[u8]) { + self.send_fake_keypress_from_keysym(string_to_keysym(string)) + } - pub fn send_fake_keypress_from_keysym(&self, ks: Keysym) { - self.send_fake_keypress_from_code(self.keysym_to_keycode(ks)) - } + pub fn send_fake_keypress_from_keysym(&self, ks: Keysym) { + self.send_fake_keypress_from_code(self.keysym_to_keycode(ks)) + } - pub fn send_fake_keypress_from_code(&self, code: Keycode) { - unsafe { XTestFakeKeyEvent(self.ptr, code, TRUE_C, 10) }; - self.flush(); - } + pub fn send_fake_keypress_from_code(&self, code: Keycode) { + unsafe { XTestFakeKeyEvent(self.ptr, code, TRUE_C, 10) }; + self.flush(); + } - pub fn send_fake_buttonpress(&self, button: u32) { - unsafe { XTestFakeButtonEvent(self.ptr, button, TRUE_C, 10) }; - } + pub fn send_fake_buttonpress(&self, button: u32) { + unsafe { XTestFakeButtonEvent(self.ptr, button, TRUE_C, 10) }; + } - pub fn send_fake_buttonrelease(&self, button: u32) { - unsafe { XTestFakeButtonEvent(self.ptr, button, FALSE_C, 10) }; - } + pub fn send_fake_buttonrelease(&self, button: u32) { + unsafe { XTestFakeButtonEvent(self.ptr, button, FALSE_C, 10) }; + } - pub fn send_fake_keyrelease_from_string(&self, string: &[u8]) { - self.send_fake_keyrelease_from_keysym(string_to_keysym(string)) - } + pub fn send_fake_keyrelease_from_string(&self, string: &[u8]) { + self.send_fake_keyrelease_from_keysym(string_to_keysym(string)) + } - pub fn send_fake_keyrelease_from_keysym(&self, ks: Keysym) { - self.send_fake_keyrelease_from_code(self.keysym_to_keycode(ks)) - } + pub fn send_fake_keyrelease_from_keysym(&self, ks: Keysym) { + self.send_fake_keyrelease_from_code(self.keysym_to_keycode(ks)) + } - pub fn send_fake_keyrelease_from_code(&self, code: Keycode) { - unsafe { XTestFakeKeyEvent(self.ptr, code, FALSE_C, 10) }; - self.flush(); - } + pub fn send_fake_keyrelease_from_code(&self, code: Keycode) { + unsafe { XTestFakeKeyEvent(self.ptr, code, FALSE_C, 10) }; + self.flush(); + } - pub fn send_fake_motion_event(&self, x: c_int, y: c_int) { - unsafe { XTestFakeMotionEvent(self.ptr, -1, x, y, 10)}; - self.flush(); - } + pub fn send_fake_motion_event(&self, x: c_int, y: c_int) { + unsafe { XTestFakeMotionEvent(self.ptr, -1, x, y, 10) }; + self.flush(); + } - pub fn grab_control(&self) { - unsafe { XTestGrabControl(self.ptr, TRUE_C); } - } + pub fn grab_control(&self) { + unsafe { + XTestGrabControl(self.ptr, TRUE_C); + } + } } /// Wrapper for XStringToKeysym. Remember to give a null terminated string! pub fn string_to_keysym(string: &[u8]) -> Keysym { - unsafe { XStringToKeysym(string.as_ptr() as *const c_char) } -} \ No newline at end of file + unsafe { XStringToKeysym(string.as_ptr() as *const c_char) } +}