added basic xmacro support! now can record macros!

This commit is contained in:
Schrottkatze 2022-06-15 12:50:44 +02:00
parent 8d47ad6475
commit 0facd53b48
5 changed files with 98 additions and 28 deletions

View file

@ -8,4 +8,4 @@ edition = "2021"
[dependencies] [dependencies]
x11 = { version = "2.19.1", features = ["xlib", "xtest"] } x11 = { version = "2.19.1", features = ["xlib", "xtest"] }
x11-keysymdef = "0.2.0" x11-keysymdef = "0.2.0"
clap = { version = "3.1.18", features = ["derive"] } clap = { version = "3.2.4", features = ["derive"] }

View file

@ -1,3 +1,18 @@
# easymacros # easymacros
This program is inspired by xmacro, however it isn't xmacro. This program is inspired by xmacro, however it isn't xmacro.
## TODOs
- [ ] Playing macros (xmacro)
- [x] Delay support
- [x] KeySym/KeyCode/KeyStr action support
- [x] MotionNotify and button support
- [ ] String typing support
- [ ] Screenshot support
- [ ] ExecBlock/ExecNoBlock support
- [ ] Recording macros (xmacro)
- [ ] Delay
- [ ] Keyboard actions
- [ ] Mouse actions
- [ ] Screenshot

View file

@ -2,38 +2,74 @@ use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int, c_uint}; use std::os::raw::{c_char, c_int, c_uint};
use std::process::exit; use std::process::exit;
use std::slice::from_raw_parts; use std::slice::from_raw_parts;
use std::thread; use std::{fs, thread};
use std::time::Duration; use std::time::Duration;
use x11::xlib::{Display, XCloseDisplay, XDisplayString, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync}; use x11::xlib::{Display, XCloseDisplay, XDisplayString, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync};
use easymacros::add;
use clap::Parser; use clap::Parser;
use x11::keysym::{XK_d, XK_Super_L}; use x11::keysym::{XK_d, XK_Super_L};
use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension}; use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension};
use x11_keysymdef::lookup_by_name; use x11_keysymdef::lookup_by_name;
use easymacros::x11_safe_wrapper::XDisplay; use easymacros::x11_safe_wrapper::{Keysym, XDisplay};
/// Macro program inspired by xmacro. /// Macro program inspired by xmacro.
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)] #[clap(author, version, about, long_about = None)]
struct Args { struct Args {
/// Input file
#[clap(value_parser, value_name = "input_file", value_hint = clap::ValueHint::FilePath)]
input_file: std::path::PathBuf,
/// Display /// Display
#[clap(short, long)] #[clap(short, long)]
display: String, display: Option<String>,
/// xmacro compatibility // xmacro compatibility, currently the only supported input format anyway
#[clap(long)] // #[clap(long)]
xmacro: bool, // xmacro: bool,
} }
fn main () { fn main () {
let args = Args::parse(); let args = Args::parse();
let xmacro_mode = args.xmacro; // let xmacro_mode = args.xmacro;
let display = get_remote(None); let input_file_contents = fs::read_to_string(args.input_file).expect("couldn't read macro file");
let display = get_remote(args.display);
display.send_fake_keypress_from_string(b"Super_L\0"); for instruction in input_file_contents.lines() {
display.send_fake_keypress_from_string(b"d\0"); println!("Instruction: {}", instruction);
display.send_fake_keyrelease_from_string(b"d\0"); let command: Vec<&str> = instruction.split(' ').collect();
display.send_fake_keyrelease_from_string(b"Super_L\0");
match command[0] {
"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()),
"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()),
"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()),
"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();
} }

View file

@ -2,15 +2,21 @@ extern crate core;
pub mod x11_safe_wrapper; pub mod x11_safe_wrapper;
pub fn add(a: i32, b: i32) -> i32 { pub enum XMacroInstructions {
a + b Delay,
} ButtonPress,
ButtonRelease,
#[cfg(test)] MotionNotify,
mod tests { KeyCodePress,
#[test] KeyCodeRelease,
fn it_works() { // Screenshot,
let result = 2 + 2; KeySymPress,
assert_eq!(result, 4); KeySymRelease,
} KeySym,
KeyStrPress,
KeyStrRelease,
KeyStr,
String,
// ExecBlock,
// ExecNoBlock,
} }

View file

@ -2,14 +2,14 @@ use std::env;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ulong}; 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::xlib::{Display, XCloseDisplay, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync};
use x11::xtest::{XTestFakeKeyEvent, XTestGrabControl, XTestQueryExtension}; use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension};
pub struct XDisplay { pub struct XDisplay {
ptr: *mut Display, ptr: *mut Display,
} }
type Keysym = c_ulong; pub type Keysym = c_ulong;
type Keycode = c_uint; pub type Keycode = c_uint;
const FALSE_C: c_int = 0; const FALSE_C: c_int = 0;
const TRUE_C: c_int = 1; const TRUE_C: c_int = 1;
@ -70,6 +70,14 @@ impl XDisplay {
self.flush(); self.flush();
} }
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_keyrelease_from_string(&self, string: &[u8]) { pub fn send_fake_keyrelease_from_string(&self, string: &[u8]) {
self.send_fake_keyrelease_from_keysym(string_to_keysym(string)) self.send_fake_keyrelease_from_keysym(string_to_keysym(string))
} }
@ -83,6 +91,11 @@ impl XDisplay {
self.flush(); 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) { pub fn grab_control(&self) {
unsafe { XTestGrabControl(self.ptr, TRUE_C); } unsafe { XTestGrabControl(self.ptr, TRUE_C); }
} }