added macro playing delay!!!!!!!!1
This commit is contained in:
parent
b9770f43f1
commit
f52e2914d7
2 changed files with 125 additions and 130 deletions
|
@ -12,140 +12,135 @@ use easymacros::chartbl::CHARTBL;
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
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: Option<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 = "D", long)]
|
#[clap(short = 'D', long)]
|
||||||
display: Option<String>,
|
display: Option<String>,
|
||||||
// Delay for events to be sent.
|
/// Delay for events to be sent.
|
||||||
// #[clap(short, long)]
|
#[clap(short, long)]
|
||||||
// event_delay: Option<u16>,
|
delay: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
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 {
|
if let Some(input_file_path) = args.input_file {
|
||||||
let input_file_contents = fs::read_to_string(input_file_path)
|
let input_file_contents = fs::read_to_string(input_file_path).expect("Couldn't read macro file");
|
||||||
.expect("Couldn't read macro file");
|
|
||||||
|
|
||||||
for instruction in input_file_contents.lines() {
|
for instruction in input_file_contents.lines() {
|
||||||
run_instruction(instruction, &display);
|
run_instruction(instruction, &display, delay);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("No input file specified, reading from stdin.");
|
println!("No input file specified, reading from stdin.");
|
||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
stdin.read_line(&mut line).expect("Couldn't read line from stdin");
|
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?
|
// Without this it crashes because apparently it doesn't properly read the next input line?
|
||||||
println!();
|
println!();
|
||||||
line = line.trim().to_string();
|
line = line.trim().to_string();
|
||||||
run_instruction(&*line, &display);
|
run_instruction(&*line, &display, delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display.close();
|
display.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_remote(display_name: Option<String>) -> XDisplay {
|
fn get_remote(display_name: Option<String>) -> XDisplay {
|
||||||
let display = XDisplay::open(display_name);
|
let display = XDisplay::open(display_name);
|
||||||
|
|
||||||
if !display.has_xtest() {
|
if !display.has_xtest() {
|
||||||
eprintln!("XTest not supported!");
|
eprintln!("XTest not supported!");
|
||||||
display.close();
|
display.close();
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
display.grab_control();
|
display.grab_control();
|
||||||
display.sync();
|
display.sync();
|
||||||
|
|
||||||
display
|
display
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_instruction(instruction: &str, dpy: &XDisplay) {
|
fn run_instruction(instruction: &str, dpy: &XDisplay, delay: u64) {
|
||||||
let instruction_split: Vec<&str> = instruction.split(' ').collect();
|
let instruction_split: Vec<&str> = instruction.split(' ').collect();
|
||||||
|
|
||||||
match instruction_split[0] {
|
match instruction_split[0] {
|
||||||
"Delay" => thread::sleep(Duration::from_millis(instruction_split[1].parse().unwrap())),
|
"Delay" => thread::sleep(Duration::from_millis(instruction_split[1].parse().unwrap())),
|
||||||
"ButtonPress" => dpy.send_fake_buttonpress(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()),
|
"ButtonRelease" => dpy.send_fake_buttonrelease(instruction_split[1].parse().unwrap(), delay),
|
||||||
"MotionNotify" => dpy
|
"MotionNotify" => dpy.send_fake_motion_event(instruction_split[1].parse().unwrap(), instruction_split[2].parse().unwrap(), delay),
|
||||||
.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(), delay),
|
||||||
"KeyCodePress" => dpy.send_fake_keypress_from_code(instruction_split[1].parse().unwrap()),
|
"KeyCodeRelease" => dpy.send_fake_keyrelease_from_code(instruction_split[1].parse().unwrap(), delay),
|
||||||
"KeyCodeRelease" => dpy.send_fake_keyrelease_from_code(instruction_split[1].parse().unwrap()),
|
"KeySymPress" => dpy.send_fake_keypress_from_keysym(instruction_split[1].parse().unwrap(), delay),
|
||||||
"KeySymPress" => dpy.send_fake_keypress_from_keysym(instruction_split[1].parse().unwrap()),
|
"KeySymRelease" => dpy.send_fake_keyrelease_from_keysym(instruction_split[1].parse().unwrap(), delay),
|
||||||
"KeySymRelease" => {
|
|
||||||
dpy.send_fake_keyrelease_from_keysym(instruction_split[1].parse().unwrap())
|
"KeySym" => {
|
||||||
}
|
let key: Keysym = instruction_split[1].parse().unwrap();
|
||||||
"KeySym" => {
|
dpy.send_fake_keypress_from_keysym(key, delay);
|
||||||
let key: Keysym = instruction_split[1].parse().unwrap();
|
dpy.send_fake_keyrelease_from_keysym(key, delay);
|
||||||
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(), delay),
|
||||||
}
|
"KeyStrRelease" => dpy.send_fake_keyrelease_from_string(CString::new(instruction_split[1]).unwrap().as_bytes(), delay),
|
||||||
"KeyStrPress" => {
|
"KeyStr" => {
|
||||||
dpy.send_fake_keypress_from_string(CString::new(instruction_split[1]).unwrap().as_bytes())
|
let keystring = CString::new(instruction_split[1]).unwrap();
|
||||||
}
|
dpy.send_fake_keypress_from_string(keystring.as_bytes(), delay);
|
||||||
"KeyStrRelease" => dpy
|
dpy.send_fake_keyrelease_from_string(keystring.as_bytes(), delay);
|
||||||
.send_fake_keyrelease_from_string(CString::new(instruction_split[1]).unwrap().as_bytes()),
|
}
|
||||||
"KeyStr" => {
|
"String" => {
|
||||||
let keystring = CString::new(instruction_split[1]).unwrap();
|
for c in instruction["String".len() + 1..].chars() {
|
||||||
dpy.send_fake_keypress_from_string(keystring.as_bytes());
|
send_char(dpy, c, delay);
|
||||||
dpy.send_fake_keyrelease_from_string(keystring.as_bytes());
|
}
|
||||||
}
|
}
|
||||||
"String" => {
|
"ExecBlock" | "ExecNoBlock" => {
|
||||||
for c in instruction["String".len()+1..].chars() {
|
let mut command = Command::new(instruction_split[1]);
|
||||||
send_char(dpy, c);
|
for arg in &instruction_split[2..] {
|
||||||
}
|
command.arg(arg);
|
||||||
}
|
}
|
||||||
"ExecBlock" | "ExecNoBlock" => {
|
if instruction_split[0] == "ExecBlock" {
|
||||||
let mut command = Command::new(instruction_split[1]);
|
command.status().unwrap();
|
||||||
for arg in &instruction_split[2..] {
|
} else {
|
||||||
command.arg(arg);
|
command.spawn().unwrap();
|
||||||
}
|
}
|
||||||
if instruction_split[0] == "ExecBlock" {
|
}
|
||||||
command.status().unwrap();
|
c => panic!("Unknown command {:?}", instruction_split),
|
||||||
} else {
|
}
|
||||||
command.spawn().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c => panic!("Unknown command {:?}", instruction_split),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_char(dpy: &XDisplay, c: char) {
|
fn send_char(dpy: &XDisplay, c: char, delay: u64) {
|
||||||
// get keystring from character and turn it into a keysym
|
// get keystring from character and turn it into a keysym
|
||||||
let keysym = string_to_keysym(CHARTBL[c as usize].as_ref());
|
let keysym = string_to_keysym(CHARTBL[c as usize].as_ref());
|
||||||
let keycode = dpy.keysym_to_keycode(keysym);
|
let keycode = dpy.keysym_to_keycode(keysym);
|
||||||
|
|
||||||
if keycode == 0 {
|
if keycode == 0 {
|
||||||
eprintln!("No keycode found for character '{}'", c);
|
eprintln!("No keycode found for character '{}'", c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let map_ks = dpy.get_keyboard_mapping(keycode, 1);
|
let map_ks = dpy.get_keyboard_mapping(keycode, 1);
|
||||||
if map_ks[0] == 0 {
|
if map_ks[0] == 0 {
|
||||||
eprintln!("XGetKeyboardMapping failed (keycode: {})", keycode);
|
eprintln!("XGetKeyboardMapping failed (keycode: {})", keycode);
|
||||||
return;
|
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
|
// check if shift has to be pressed as well
|
||||||
let mut shift_needed = true;
|
let mut shift_needed = true;
|
||||||
if keysym == map_ks[0] && (keysym == ks_lower && keysym == ks_upper) {
|
if keysym == map_ks[0] && (keysym == ks_lower && keysym == ks_upper) {
|
||||||
shift_needed = false;
|
shift_needed = false;
|
||||||
}
|
}
|
||||||
if keysym == ks_lower && keysym != ks_upper {
|
if keysym == ks_lower && keysym != ks_upper {
|
||||||
shift_needed = false;
|
shift_needed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if shift_needed { dpy.send_fake_keypress_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);
|
dpy.send_fake_keypress_from_code(keycode, delay);
|
||||||
dpy.send_fake_keyrelease_from_code(keycode);
|
dpy.send_fake_keyrelease_from_code(keycode, delay);
|
||||||
if shift_needed { dpy.send_fake_keyrelease_from_keysym(XK_Shift_L as Keysym); }
|
if shift_needed { dpy.send_fake_keyrelease_from_keysym(XK_Shift_L as Keysym, delay); }
|
||||||
}
|
}
|
|
@ -133,42 +133,42 @@ impl XDisplay {
|
||||||
has_extension != 0
|
has_extension != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_keypress_from_string(&self, string: &[u8]) {
|
pub fn send_fake_keypress_from_string(&self, string: &[u8], delay: u64) {
|
||||||
self.send_fake_keypress_from_keysym(string_to_keysym(string))
|
self.send_fake_keypress_from_keysym(string_to_keysym(string), delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_keypress_from_keysym(&self, ks: Keysym) {
|
pub fn send_fake_keypress_from_keysym(&self, ks: Keysym, delay: u64) {
|
||||||
self.send_fake_keypress_from_code(self.keysym_to_keycode(ks))
|
self.send_fake_keypress_from_code(self.keysym_to_keycode(ks), delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_keypress_from_code(&self, code: Keycode) {
|
pub fn send_fake_keypress_from_code(&self, code: Keycode, delay: u64) {
|
||||||
unsafe { XTestFakeKeyEvent(self.ptr, code, TRUE_C, 10) };
|
unsafe { XTestFakeKeyEvent(self.ptr, code, TRUE_C, delay) };
|
||||||
self.flush();
|
self.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_buttonpress(&self, button: u32) {
|
pub fn send_fake_buttonpress(&self, button: u32, delay: u64) {
|
||||||
unsafe { XTestFakeButtonEvent(self.ptr, button, TRUE_C, 10) };
|
unsafe { XTestFakeButtonEvent(self.ptr, button, TRUE_C, delay) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_buttonrelease(&self, button: u32) {
|
pub fn send_fake_buttonrelease(&self, button: u32, delay: u64) {
|
||||||
unsafe { XTestFakeButtonEvent(self.ptr, button, FALSE_C, 10) };
|
unsafe { XTestFakeButtonEvent(self.ptr, button, FALSE_C, delay) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_keyrelease_from_string(&self, string: &[u8]) {
|
pub fn send_fake_keyrelease_from_string(&self, string: &[u8], delay: u64) {
|
||||||
self.send_fake_keyrelease_from_keysym(string_to_keysym(string))
|
self.send_fake_keyrelease_from_keysym(string_to_keysym(string), delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_keyrelease_from_keysym(&self, ks: Keysym) {
|
pub fn send_fake_keyrelease_from_keysym(&self, ks: Keysym, delay: u64) {
|
||||||
self.send_fake_keyrelease_from_code(self.keysym_to_keycode(ks))
|
self.send_fake_keyrelease_from_code(self.keysym_to_keycode(ks), delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_keyrelease_from_code(&self, code: Keycode) {
|
pub fn send_fake_keyrelease_from_code(&self, code: Keycode, delay: u64) {
|
||||||
unsafe { XTestFakeKeyEvent(self.ptr, code, FALSE_C, 10) };
|
unsafe { XTestFakeKeyEvent(self.ptr, code, FALSE_C, delay) };
|
||||||
self.flush();
|
self.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_fake_motion_event(&self, x: i32, y: i32) {
|
pub fn send_fake_motion_event(&self, x: i32, y: i32, delay: u64) {
|
||||||
unsafe { XTestFakeMotionEvent(self.ptr, -1, x, y, 10) };
|
unsafe { XTestFakeMotionEvent(self.ptr, -1, x, y, delay) };
|
||||||
self.flush();
|
self.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue