From f52e2914d7199ef76d8e0b407f2f57a1813b36ad Mon Sep 17 00:00:00 2001 From: Gabriel <68819302+obsidianical@users.noreply.github.com> Date: Mon, 25 Jul 2022 17:14:00 +0200 Subject: [PATCH] added macro playing delay!!!!!!!!1 --- src/bin/easymacroplay.rs | 219 +++++++++++++++++++-------------------- src/x11_safe_wrapper.rs | 36 +++---- 2 files changed, 125 insertions(+), 130 deletions(-) diff --git a/src/bin/easymacroplay.rs b/src/bin/easymacroplay.rs index ba358d5..ba1960a 100644 --- a/src/bin/easymacroplay.rs +++ b/src/bin/easymacroplay.rs @@ -12,140 +12,135 @@ use easymacros::chartbl::CHARTBL; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { - /// The file that contains the macro to run. - #[clap(value_parser, value_name = "input_file", value_hint = clap::ValueHint::FilePath)] - input_file: Option, - /// Display to run the macro on. This uses the $DISPLAY environment variable by default. - #[clap(short = "D", long)] - display: Option, - // Delay for events to be sent. - // #[clap(short, long)] - // event_delay: Option, + /// The file that contains the macro to run. + #[clap(value_parser, value_name = "input_file", value_hint = clap::ValueHint::FilePath)] + input_file: Option, + /// Display to run the macro on. This uses the $DISPLAY environment variable by default. + #[clap(short = 'D', long)] + display: Option, + /// Delay for events to be sent. + #[clap(short, long)] + delay: Option, } fn main() { - let args = Args::parse(); + let args = Args::parse(); - let display = get_remote(args.display); + let display = get_remote(args.display); + let delay = args.delay.unwrap_or(10); - if let Some(input_file_path) = args.input_file { - let input_file_contents = fs::read_to_string(input_file_path) - .expect("Couldn't read macro file"); + if let Some(input_file_path) = args.input_file { + let input_file_contents = fs::read_to_string(input_file_path).expect("Couldn't read macro file"); - for instruction in input_file_contents.lines() { - run_instruction(instruction, &display); - } - } else { - println!("No input file specified, reading from stdin."); - let stdin = stdin(); + for instruction in input_file_contents.lines() { + run_instruction(instruction, &display, delay); + } + } else { + println!("No input file specified, reading from stdin."); + let stdin = stdin(); - loop { - let mut line = String::new(); - stdin.read_line(&mut line).expect("Couldn't read line from stdin"); - // Without this it crashes because apparently it doesn't properly read the next input line? - println!(); - line = line.trim().to_string(); - run_instruction(&*line, &display); - } - } + loop { + let mut line = String::new(); + stdin.read_line(&mut line).expect("Couldn't read line from stdin"); + // Without this it crashes because apparently it doesn't properly read the next input line? + println!(); + line = line.trim().to_string(); + run_instruction(&*line, &display, delay); + } + } - display.close(); + display.close(); } fn get_remote(display_name: Option) -> XDisplay { - let display = XDisplay::open(display_name); + let display = XDisplay::open(display_name); - if !display.has_xtest() { - eprintln!("XTest not supported!"); - display.close(); - exit(1) - } + if !display.has_xtest() { + eprintln!("XTest not supported!"); + display.close(); + exit(1) + } - display.grab_control(); - display.sync(); + display.grab_control(); + display.sync(); - display + display } -fn run_instruction(instruction: &str, dpy: &XDisplay) { - let instruction_split: Vec<&str> = instruction.split(' ').collect(); +fn run_instruction(instruction: &str, dpy: &XDisplay, delay: u64) { + let instruction_split: Vec<&str> = instruction.split(' ').collect(); - match instruction_split[0] { - "Delay" => thread::sleep(Duration::from_millis(instruction_split[1].parse().unwrap())), - "ButtonPress" => dpy.send_fake_buttonpress(instruction_split[1].parse().unwrap()), - "ButtonRelease" => dpy.send_fake_buttonrelease(instruction_split[1].parse().unwrap()), - "MotionNotify" => dpy - .send_fake_motion_event(instruction_split[1].parse().unwrap(), instruction_split[2].parse().unwrap()), - "KeyCodePress" => dpy.send_fake_keypress_from_code(instruction_split[1].parse().unwrap()), - "KeyCodeRelease" => dpy.send_fake_keyrelease_from_code(instruction_split[1].parse().unwrap()), - "KeySymPress" => dpy.send_fake_keypress_from_keysym(instruction_split[1].parse().unwrap()), - "KeySymRelease" => { - dpy.send_fake_keyrelease_from_keysym(instruction_split[1].parse().unwrap()) - } - "KeySym" => { - let key: Keysym = instruction_split[1].parse().unwrap(); - dpy.send_fake_keypress_from_keysym(key); - dpy.send_fake_keyrelease_from_keysym(key); - } - "KeyStrPress" => { - dpy.send_fake_keypress_from_string(CString::new(instruction_split[1]).unwrap().as_bytes()) - } - "KeyStrRelease" => dpy - .send_fake_keyrelease_from_string(CString::new(instruction_split[1]).unwrap().as_bytes()), - "KeyStr" => { - let keystring = CString::new(instruction_split[1]).unwrap(); - dpy.send_fake_keypress_from_string(keystring.as_bytes()); - dpy.send_fake_keyrelease_from_string(keystring.as_bytes()); - } - "String" => { - for c in instruction["String".len()+1..].chars() { - send_char(dpy, c); - } - } - "ExecBlock" | "ExecNoBlock" => { - let mut command = Command::new(instruction_split[1]); - for arg in &instruction_split[2..] { - command.arg(arg); - } - if instruction_split[0] == "ExecBlock" { - command.status().unwrap(); - } else { - command.spawn().unwrap(); - } - } - c => panic!("Unknown command {:?}", instruction_split), - } + match instruction_split[0] { + "Delay" => thread::sleep(Duration::from_millis(instruction_split[1].parse().unwrap())), + "ButtonPress" => dpy.send_fake_buttonpress(instruction_split[1].parse().unwrap(), delay), + "ButtonRelease" => dpy.send_fake_buttonrelease(instruction_split[1].parse().unwrap(), delay), + "MotionNotify" => dpy.send_fake_motion_event(instruction_split[1].parse().unwrap(), instruction_split[2].parse().unwrap(), delay), + "KeyCodePress" => dpy.send_fake_keypress_from_code(instruction_split[1].parse().unwrap(), delay), + "KeyCodeRelease" => dpy.send_fake_keyrelease_from_code(instruction_split[1].parse().unwrap(), delay), + "KeySymPress" => dpy.send_fake_keypress_from_keysym(instruction_split[1].parse().unwrap(), delay), + "KeySymRelease" => dpy.send_fake_keyrelease_from_keysym(instruction_split[1].parse().unwrap(), delay), + + "KeySym" => { + let key: Keysym = instruction_split[1].parse().unwrap(); + dpy.send_fake_keypress_from_keysym(key, delay); + dpy.send_fake_keyrelease_from_keysym(key, delay); + } + "KeyStrPress" => dpy.send_fake_keypress_from_string(CString::new(instruction_split[1]).unwrap().as_bytes(), delay), + "KeyStrRelease" => dpy.send_fake_keyrelease_from_string(CString::new(instruction_split[1]).unwrap().as_bytes(), delay), + "KeyStr" => { + let keystring = CString::new(instruction_split[1]).unwrap(); + dpy.send_fake_keypress_from_string(keystring.as_bytes(), delay); + dpy.send_fake_keyrelease_from_string(keystring.as_bytes(), delay); + } + "String" => { + for c in instruction["String".len() + 1..].chars() { + send_char(dpy, c, delay); + } + } + "ExecBlock" | "ExecNoBlock" => { + let mut command = Command::new(instruction_split[1]); + for arg in &instruction_split[2..] { + command.arg(arg); + } + if instruction_split[0] == "ExecBlock" { + command.status().unwrap(); + } else { + command.spawn().unwrap(); + } + } + c => panic!("Unknown command {:?}", instruction_split), + } } -fn send_char(dpy: &XDisplay, c: char) { - // get keystring from character and turn it into a keysym - let keysym = string_to_keysym(CHARTBL[c as usize].as_ref()); - let keycode = dpy.keysym_to_keycode(keysym); +fn send_char(dpy: &XDisplay, c: char, delay: u64) { + // get keystring from character and turn it into a keysym + let keysym = string_to_keysym(CHARTBL[c as usize].as_ref()); + let keycode = dpy.keysym_to_keycode(keysym); - if keycode == 0 { - eprintln!("No keycode found for character '{}'", c); - return; - } + if keycode == 0 { + eprintln!("No keycode found for character '{}'", c); + return; + } - let map_ks = dpy.get_keyboard_mapping(keycode, 1); - if map_ks[0] == 0 { - eprintln!("XGetKeyboardMapping failed (keycode: {})", keycode); - return; - } + let map_ks = dpy.get_keyboard_mapping(keycode, 1); + if map_ks[0] == 0 { + eprintln!("XGetKeyboardMapping failed (keycode: {})", keycode); + return; + } - let (ks_lower, ks_upper) = dpy.convert_case(keysym); + let (ks_lower, ks_upper) = dpy.convert_case(keysym); - // check if shift has to be pressed as well - let mut shift_needed = true; - if keysym == map_ks[0] && (keysym == ks_lower && keysym == ks_upper) { - shift_needed = false; - } - if keysym == ks_lower && keysym != ks_upper { - shift_needed = false; - } + // check if shift has to be pressed as well + let mut shift_needed = true; + if keysym == map_ks[0] && (keysym == ks_lower && keysym == ks_upper) { + shift_needed = false; + } + if keysym == ks_lower && keysym != ks_upper { + shift_needed = false; + } - if shift_needed { dpy.send_fake_keypress_from_keysym(XK_Shift_L as Keysym); } - dpy.send_fake_keypress_from_code(keycode); - dpy.send_fake_keyrelease_from_code(keycode); - if shift_needed { dpy.send_fake_keyrelease_from_keysym(XK_Shift_L as Keysym); } + if shift_needed { dpy.send_fake_keypress_from_keysym(XK_Shift_L as Keysym, delay); } + dpy.send_fake_keypress_from_code(keycode, delay); + dpy.send_fake_keyrelease_from_code(keycode, delay); + if shift_needed { dpy.send_fake_keyrelease_from_keysym(XK_Shift_L as Keysym, delay); } } \ No newline at end of file diff --git a/src/x11_safe_wrapper.rs b/src/x11_safe_wrapper.rs index 07ffeb2..a8e982d 100644 --- a/src/x11_safe_wrapper.rs +++ b/src/x11_safe_wrapper.rs @@ -133,42 +133,42 @@ impl XDisplay { 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], delay: u64) { + self.send_fake_keypress_from_keysym(string_to_keysym(string), delay) } - 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, delay: u64) { + self.send_fake_keypress_from_code(self.keysym_to_keycode(ks), delay) } - pub fn send_fake_keypress_from_code(&self, code: Keycode) { - unsafe { XTestFakeKeyEvent(self.ptr, code, TRUE_C, 10) }; + pub fn send_fake_keypress_from_code(&self, code: Keycode, delay: u64) { + unsafe { XTestFakeKeyEvent(self.ptr, code, TRUE_C, delay) }; 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, delay: u64) { + unsafe { XTestFakeButtonEvent(self.ptr, button, TRUE_C, delay) }; } - pub fn send_fake_buttonrelease(&self, button: u32) { - unsafe { XTestFakeButtonEvent(self.ptr, button, FALSE_C, 10) }; + pub fn send_fake_buttonrelease(&self, button: u32, delay: u64) { + unsafe { XTestFakeButtonEvent(self.ptr, button, FALSE_C, delay) }; } - 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], delay: u64) { + self.send_fake_keyrelease_from_keysym(string_to_keysym(string), delay) } - 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, delay: u64) { + self.send_fake_keyrelease_from_code(self.keysym_to_keycode(ks), delay) } - pub fn send_fake_keyrelease_from_code(&self, code: Keycode) { - unsafe { XTestFakeKeyEvent(self.ptr, code, FALSE_C, 10) }; + pub fn send_fake_keyrelease_from_code(&self, code: Keycode, delay: u64) { + unsafe { XTestFakeKeyEvent(self.ptr, code, FALSE_C, delay) }; self.flush(); } - pub fn send_fake_motion_event(&self, x: i32, y: i32) { - unsafe { XTestFakeMotionEvent(self.ptr, -1, x, y, 10) }; + pub fn send_fake_motion_event(&self, x: i32, y: i32, delay: u64) { + unsafe { XTestFakeMotionEvent(self.ptr, -1, x, y, delay) }; self.flush(); }