Implemented ExecBlock command support.

This commit is contained in:
Schrottkatze 2022-07-01 12:08:27 +02:00
parent d4b2353400
commit 4581e8972e
2 changed files with 69 additions and 48 deletions

View file

@ -15,6 +15,8 @@ This program is inspired by [**xmacro**](https://github.com/Ortega-Dan/xmacroInc
- [x] MotionNotify and button support - [x] MotionNotify and button support
- [ ] String typing support (Not too high priority, but I'll add it some time probably) - [ ] String typing support (Not too high priority, but I'll add it some time probably)
- [ ] ExecBlock/ExecNoBlock support (not high priority) - [ ] ExecBlock/ExecNoBlock support (not high priority)
- [x] ExecBlock
- [ ] ExecNoBlock
- [x] Recording macros (xmacro like) - [x] Recording macros (xmacro like)
- [x] Delay - [x] Delay
- [x] Keyboard actions - [x] Keyboard actions

View file

@ -1,9 +1,10 @@
use clap::Parser; use clap::Parser;
use easymacros::x11_safe_wrapper::{Keysym, XDisplay}; use easymacros::x11_safe_wrapper::{Keysym, XDisplay};
use std::ffi::CString; use std::ffi::CString;
use std::process::exit; use std::process::{Command, exit};
use std::time::Duration; use std::time::Duration;
use std::{fs, thread}; use std::{fs, thread};
use std::io::stdin;
/// Macro player module for easymacros. It's partially compatible with xmacro macros, with aim for full compatibility. /// Macro player module for easymacros. It's partially compatible with xmacro macros, with aim for full compatibility.
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -11,67 +12,39 @@ use std::{fs, thread};
struct Args { struct Args {
/// The file that contains the macro to run. /// The file that contains the macro to run.
#[clap(value_parser, value_name = "input_file", value_hint = clap::ValueHint::FilePath)] #[clap(value_parser, value_name = "input_file", value_hint = clap::ValueHint::FilePath)]
input_file: std::path::PathBuf, input_file: Option<std::path::PathBuf>,
/// Display to run the macro on. This uses the $DISPLAY environment variable by default. /// Display to run the macro on. This uses the $DISPLAY environment variable by default.
#[clap(short, long)] #[clap(short, long)]
display: Option<String>, display: Option<String>,
// xmacro compatibility, currently the only supported input format anyway
// #[clap(long)]
// xmacro: bool,
} }
fn main() { fn main() {
let args = Args::parse(); 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 display = get_remote(args.display); let display = get_remote(args.display);
for instruction in input_file_contents.lines() { if let Some(input_file_path) = args.input_file {
println!("Instruction: {}", instruction); let input_file_contents = fs::read_to_string(input_file_path)
let command: Vec<&str> = instruction.split(' ').collect(); .expect("Couldn't read macro file");
match command[0] { for instruction in input_file_contents.lines() {
"Delay" => thread::sleep(Duration::from_millis(command[1].parse().unwrap())), run_instruction(instruction, &display);
"ButtonPress" => display.send_fake_buttonpress(command[1].parse().unwrap()), }
"ButtonRelease" => display.send_fake_buttonrelease(command[1].parse().unwrap()), } else {
"MotionNotify" => display let stdin = stdin();
.send_fake_motion_event(command[1].parse().unwrap(), command[2].parse().unwrap()),
"KeyCodePress" => display.send_fake_keypress_from_code(command[1].parse().unwrap()), loop {
"KeyCodeRelease" => display.send_fake_keyrelease_from_code(command[1].parse().unwrap()), let mut line = String::new();
"KeySymPress" => display.send_fake_keypress_from_keysym(command[1].parse().unwrap()), stdin.read_line(&mut line).expect("Couldn't read line from stdin");
"KeySymRelease" => { // Without this it crashes because apparently it doesn't properly read the next input line?
display.send_fake_keyrelease_from_keysym(command[1].parse().unwrap()) println!();
} line = line.trim().to_string();
"KeySym" => { run_instruction(&*line, &display);
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()),
"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() {
// display.send_fake_keypress_from_string(CString::new(c.to_string()).unwrap().as_bytes());
// display.send_fake_keyrelease_from_string(CString::new(c.to_string()).unwrap().as_bytes());
// }
}
c => {
panic!("Unknown command {}", c)
}
} }
} }
display.close(); display.close();
} }
@ -89,3 +62,49 @@ fn get_remote(display_name: Option<String>) -> XDisplay {
display display
} }
fn run_instruction(instruction: &str, display: &XDisplay) {
let instruction: Vec<&str> = instruction.split(' ').collect();
match instruction[0] {
"Delay" => thread::sleep(Duration::from_millis(instruction[1].parse().unwrap())),
"ButtonPress" => display.send_fake_buttonpress(instruction[1].parse().unwrap()),
"ButtonRelease" => display.send_fake_buttonrelease(instruction[1].parse().unwrap()),
"MotionNotify" => display
.send_fake_motion_event(instruction[1].parse().unwrap(), instruction[2].parse().unwrap()),
"KeyCodePress" => display.send_fake_keypress_from_code(instruction[1].parse().unwrap()),
"KeyCodeRelease" => display.send_fake_keyrelease_from_code(instruction[1].parse().unwrap()),
"KeySymPress" => display.send_fake_keypress_from_keysym(instruction[1].parse().unwrap()),
"KeySymRelease" => {
display.send_fake_keyrelease_from_keysym(instruction[1].parse().unwrap())
}
"KeySym" => {
let key: Keysym = instruction[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(instruction[1]).unwrap().as_bytes())
}
"KeyStrRelease" => display
.send_fake_keyrelease_from_string(CString::new(instruction[1]).unwrap().as_bytes()),
"KeyStr" => {
let keystring = CString::new(instruction[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.");
}
"ExecBlock" => {
let mut command = Command::new(instruction[1]);
for arg in &instruction[2..] {
command.arg(arg);
}
command.status();
}
c => {
panic!("Unknown command {:?}", instruction)
}
}
}