formatted with cargo, cleaned up imports and dependencies.

This commit is contained in:
Schrottkatze 2022-06-15 14:06:27 +02:00
parent 5dc96d6da4
commit b651009949
5 changed files with 117 additions and 104 deletions

View file

@ -1,11 +1,11 @@
[package] [package]
name = "easymacros" name = "easymacros"
version = "0.1.0" version = "0.1.0"
author = "obsidianical"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
x11 = { version = "2.19.1", features = ["xlib", "xtest"] } x11 = { version = "2.19.1", features = ["xlib", "xtest"] }
x11-keysymdef = "0.2.0"
clap = { version = "3.2.4", features = ["derive"] } clap = { version = "3.2.4", features = ["derive"] }

View file

@ -45,3 +45,7 @@ I may or may not do these, but they sound fun to implement to me!
- [ ] 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!) - [ ] 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?) - [ ] MacOS (Might work because of XQuartz?)
- [ ] Windows (Yeah, I'm not doing that myself. Unless I have to use Windows for anything.) - [ ] 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.

View file

@ -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 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 easymacros::x11_safe_wrapper::{Keysym, XDisplay};
use std::ffi::CString;
use std::process::exit;
use std::time::Duration;
use std::{fs, thread};
/// Macro player module for easymacros. It's partially compatible with xmacro macros, with aim for full compatibility.
/// 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 /// 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: std::path::PathBuf,
/// Display /// 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 // xmacro compatibility, currently the only supported input format anyway
@ -32,7 +24,8 @@ fn main () {
let args = Args::parse(); let args = Args::parse();
// let xmacro_mode = args.xmacro; // 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); let display = get_remote(args.display);
for instruction in input_file_contents.lines() { for instruction in input_file_contents.lines() {
@ -43,23 +36,29 @@ fn main () {
"Delay" => thread::sleep(Duration::from_millis(command[1].parse().unwrap())), "Delay" => thread::sleep(Duration::from_millis(command[1].parse().unwrap())),
"ButtonPress" => display.send_fake_buttonpress(command[1].parse().unwrap()), "ButtonPress" => display.send_fake_buttonpress(command[1].parse().unwrap()),
"ButtonRelease" => display.send_fake_buttonrelease(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()), "KeyCodePress" => display.send_fake_keypress_from_code(command[1].parse().unwrap()),
"KeyCodeRelease" => display.send_fake_keyrelease_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()), "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" => { "KeySym" => {
let key: Keysym = command[1].parse().unwrap(); let key: Keysym = command[1].parse().unwrap();
display.send_fake_keypress_from_keysym(key); display.send_fake_keypress_from_keysym(key);
display.send_fake_keyrelease_from_keysym(key); display.send_fake_keyrelease_from_keysym(key);
}, }
"KeyStrPress" => display.send_fake_keypress_from_string(CString::new(command[1]).unwrap().as_bytes()), "KeyStrPress" => {
"KeyStrRelease" => display.send_fake_keyrelease_from_string(CString::new(command[1]).unwrap().as_bytes()), 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" => { "KeyStr" => {
let keystring = CString::new(command[1]).unwrap(); let keystring = CString::new(command[1]).unwrap();
display.send_fake_keypress_from_string(keystring.as_bytes()); display.send_fake_keypress_from_string(keystring.as_bytes());
display.send_fake_keyrelease_from_string(keystring.as_bytes()); display.send_fake_keyrelease_from_string(keystring.as_bytes());
}, }
"String" => { "String" => {
println!("Strings are currently not supported."); println!("Strings are currently not supported.");
// for c in instruction[7..].chars() { // 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()); // display.send_fake_keyrelease_from_string(CString::new(c.to_string()).unwrap().as_bytes());
// } // }
} }
c => {panic!("Unknown command {}", c)} c => {
panic!("Unknown command {}", c)
}
} }
} }

View file

@ -1,5 +1,3 @@
use easymacros::add;
fn main() { fn main() {
println!("rec: {}", add(2, 2)); todo!();
} }

View file

@ -1,8 +1,13 @@
use std::env; use std::env;
use std::ffi::{CStr, CString}; use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ulong}; use std::os::raw::{c_char, c_int, c_uint, c_ulong};
use x11::xlib::{Display, XCloseDisplay, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync}; use x11::xlib::{
use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension}; Display, XCloseDisplay, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync,
};
use x11::xtest::{
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
XTestQueryExtension,
};
pub struct XDisplay { pub struct XDisplay {
ptr: *mut Display, ptr: *mut Display,
@ -16,7 +21,12 @@ const TRUE_C: c_int = 1;
impl XDisplay { impl XDisplay {
pub fn open(display_name: Option<String>) -> Self { pub fn open(display_name: Option<String>) -> Self {
let name = CString::new(if let Some(name) = display_name { name } else { env::var("DISPLAY").expect("DISPLAY is not set") }).unwrap(); 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 name_ptr = name.as_bytes().as_ptr();
let display_ptr = unsafe { XOpenDisplay(name_ptr as *const i8) }; let display_ptr = unsafe { XOpenDisplay(name_ptr as *const i8) };
@ -28,11 +38,15 @@ impl XDisplay {
} }
pub fn sync(&self) { pub fn sync(&self) {
unsafe { XSync(self.ptr, c_int::from(false)); } unsafe {
XSync(self.ptr, c_int::from(false));
}
} }
pub fn flush(&self) { pub fn flush(&self) {
unsafe { XFlush(self.ptr); } unsafe {
XFlush(self.ptr);
}
} }
pub fn keysym_to_keycode(&self, keysym: c_ulong) -> Keycode { pub fn keysym_to_keycode(&self, keysym: c_ulong) -> Keycode {
@ -46,13 +60,7 @@ impl XDisplay {
pub fn has_xtest(&self) -> bool { pub fn has_xtest(&self) -> bool {
let mut vals: (c_int, c_int, c_int, c_int) = (0, 0, 0, 0); let mut vals: (c_int, c_int, c_int, c_int) = (0, 0, 0, 0);
let has_extension = unsafe { let has_extension = unsafe {
XTestQueryExtension( XTestQueryExtension(self.ptr, &mut vals.0, &mut vals.1, &mut vals.2, &mut vals.3)
self.ptr,
&mut vals.0,
&mut vals.1,
&mut vals.2,
&mut vals.3
)
}; };
has_extension != 0 has_extension != 0
} }
@ -97,7 +105,9 @@ impl XDisplay {
} }
pub fn grab_control(&self) { pub fn grab_control(&self) {
unsafe { XTestGrabControl(self.ptr, TRUE_C); } unsafe {
XTestGrabControl(self.ptr, TRUE_C);
}
} }
} }