cargo fmt
This commit is contained in:
parent
16c0826d3a
commit
801f8b6265
10 changed files with 887 additions and 818 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -2,6 +2,12 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.65"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -68,6 +74,7 @@ dependencies = [
|
||||||
name = "easymacros"
|
name = "easymacros"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"x11",
|
"x11",
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,5 +6,6 @@ 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]
|
||||||
|
anyhow = "1.0.65"
|
||||||
x11 = { version = "2.19.1", features = ["xlib", "xtest"] }
|
x11 = { version = "2.19.1", features = ["xlib", "xtest"] }
|
||||||
clap = { version = "3.2.4", features = ["derive"] }
|
clap = { version = "3.2.4", features = ["derive"] }
|
|
@ -36,6 +36,7 @@ This program is inspired by [**xmacro**](https://github.com/Ortega-Dan/xmacroInc
|
||||||
- [ ] make modes listen for numbers/amounts of repetitions
|
- [ ] make modes listen for numbers/amounts of repetitions
|
||||||
- [ ] make shortcuts be able to listen for other shortcuts and inputs
|
- [ ] make shortcuts be able to listen for other shortcuts and inputs
|
||||||
- [ ] rofi integration
|
- [ ] rofi integration
|
||||||
|
- [ ] autorun stuff on some windows?
|
||||||
- [ ] Proper, safe xlib wrapper
|
- [ ] Proper, safe xlib wrapper
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use easymacros::x11_safe_wrapper::{Keysym, string_to_keysym, XDisplay};
|
use easymacros::chartbl::CHARTBL;
|
||||||
|
use easymacros::x11_safe_wrapper::{string_to_keysym, Keysym, XDisplay};
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::process::{Command, exit};
|
use std::io::stdin;
|
||||||
|
use std::process::{exit, Command};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{fs, thread};
|
use std::{fs, thread};
|
||||||
use std::io::stdin;
|
|
||||||
use x11::keysym::XK_Shift_L;
|
use x11::keysym::XK_Shift_L;
|
||||||
use easymacros::chartbl::CHARTBL;
|
|
||||||
|
|
||||||
/// Macro player module for easymacros. It's compatible with xmacro macros.
|
/// Macro player module for easymacros. It's compatible with xmacro macros.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
|
@ -30,7 +30,8 @@ fn main() {
|
||||||
let delay = args.delay.unwrap_or(10);
|
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).expect("Couldn't read macro 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() {
|
for instruction in input_file_contents.lines() {
|
||||||
run_instruction(instruction, &display, delay);
|
run_instruction(instruction, &display, delay);
|
||||||
|
@ -41,7 +42,9 @@ fn main() {
|
||||||
|
|
||||||
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();
|
||||||
|
@ -73,20 +76,40 @@ fn run_instruction(instruction: &str, dpy: &XDisplay, delay: u64) {
|
||||||
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(), delay),
|
"ButtonPress" => dpy.send_fake_buttonpress(instruction_split[1].parse().unwrap(), delay),
|
||||||
"ButtonRelease" => dpy.send_fake_buttonrelease(instruction_split[1].parse().unwrap(), delay),
|
"ButtonRelease" => {
|
||||||
"MotionNotify" => dpy.send_fake_motion_event(instruction_split[1].parse().unwrap(), instruction_split[2].parse().unwrap(), delay),
|
dpy.send_fake_buttonrelease(instruction_split[1].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),
|
"MotionNotify" => dpy.send_fake_motion_event(
|
||||||
"KeySymPress" => dpy.send_fake_keypress_from_keysym(instruction_split[1].parse().unwrap(), delay),
|
instruction_split[1].parse().unwrap(),
|
||||||
"KeySymRelease" => dpy.send_fake_keyrelease_from_keysym(instruction_split[1].parse().unwrap(), delay),
|
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" => {
|
"KeySym" => {
|
||||||
let key: Keysym = instruction_split[1].parse().unwrap();
|
let key: Keysym = instruction_split[1].parse().unwrap();
|
||||||
dpy.send_fake_keypress_from_keysym(key, delay);
|
dpy.send_fake_keypress_from_keysym(key, delay);
|
||||||
dpy.send_fake_keyrelease_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),
|
"KeyStrPress" => dpy.send_fake_keypress_from_string(
|
||||||
"KeyStrRelease" => dpy.send_fake_keyrelease_from_string(CString::new(instruction_split[1]).unwrap().as_bytes(), delay),
|
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" => {
|
"KeyStr" => {
|
||||||
let keystring = CString::new(instruction_split[1]).unwrap();
|
let keystring = CString::new(instruction_split[1]).unwrap();
|
||||||
dpy.send_fake_keypress_from_string(keystring.as_bytes(), delay);
|
dpy.send_fake_keypress_from_string(keystring.as_bytes(), delay);
|
||||||
|
@ -139,8 +162,12 @@ fn send_char(dpy: &XDisplay, c: char, delay: u64) {
|
||||||
shift_needed = false;
|
shift_needed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if shift_needed { dpy.send_fake_keypress_from_keysym(XK_Shift_L as Keysym, delay); }
|
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_keypress_from_code(keycode, delay);
|
||||||
dpy.send_fake_keyrelease_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); }
|
if shift_needed {
|
||||||
|
dpy.send_fake_keyrelease_from_keysym(XK_Shift_L as Keysym, delay);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,26 @@
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::os::raw::{c_char};
|
use std::os::raw::c_char;
|
||||||
use std::process::{exit};
|
use std::process::exit;
|
||||||
use std::ptr::addr_of;
|
use std::ptr::addr_of;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use x11::xlib::{CurrentTime, GrabModeAsync, GrabModeSync, GrabSuccess, KeyPressMask, SyncPointer, Time, XFree, XKeyEvent};
|
use x11::xlib::{
|
||||||
use x11::xrecord::{XRecordAllocRange, XRecordEndOfData, XRecordFreeData, XRecordInterceptData, XRecordStartOfData};
|
CurrentTime, GrabModeAsync, GrabModeSync, GrabSuccess, KeyPressMask, SyncPointer, Time, XFree,
|
||||||
|
XKeyEvent,
|
||||||
|
};
|
||||||
|
use x11::xrecord::{
|
||||||
|
XRecordAllocRange, XRecordEndOfData, XRecordFreeData, XRecordInterceptData, XRecordStartOfData,
|
||||||
|
};
|
||||||
|
|
||||||
use easymacros::{BUTTONPRESS_U8, BUTTONRELEASE_U8, Instructions, KEYPRESS_U8, KEYRELEASE_U8, MOTIONNOTIFY_U8, Position};
|
|
||||||
use easymacros::ev_callback_data::EvCallbackData;
|
use easymacros::ev_callback_data::EvCallbackData;
|
||||||
use easymacros::macro_writer::MacroWriter;
|
use easymacros::macro_writer::MacroWriter;
|
||||||
use easymacros::x11_safe_wrapper::{Keycode, XDisplay};
|
use easymacros::x11_safe_wrapper::{Keycode, XDisplay};
|
||||||
|
use easymacros::{
|
||||||
|
Instructions, Position, BUTTONPRESS_U8, BUTTONRELEASE_U8, KEYPRESS_U8, KEYRELEASE_U8,
|
||||||
|
MOTIONNOTIFY_U8,
|
||||||
|
};
|
||||||
|
|
||||||
/// Macro recording module for easymacros. Outputs are partially compatible with xmacro.
|
/// Macro recording module for easymacros. Outputs are partially compatible with xmacro.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
|
@ -40,13 +48,7 @@ fn main() {
|
||||||
let stop_key = get_stop_key(display);
|
let stop_key = get_stop_key(display);
|
||||||
let writer = MacroWriter::new(args.output_file, args.ignore_delay_capturing);
|
let writer = MacroWriter::new(args.output_file, args.ignore_delay_capturing);
|
||||||
|
|
||||||
event_loop(
|
event_loop(display, recorded_display, stop_key, writer, args.max_delay);
|
||||||
display,
|
|
||||||
recorded_display,
|
|
||||||
stop_key,
|
|
||||||
writer,
|
|
||||||
args.max_delay,
|
|
||||||
);
|
|
||||||
|
|
||||||
display.close();
|
display.close();
|
||||||
}
|
}
|
||||||
|
@ -55,7 +57,8 @@ fn get_stop_key(display: XDisplay) -> Keycode {
|
||||||
let screen = display.get_default_screen();
|
let screen = display.get_default_screen();
|
||||||
|
|
||||||
let root = display.get_root_window(screen);
|
let root = display.get_root_window(screen);
|
||||||
let potential_err = display.grab_keyboard(root, false, GrabModeSync, GrabModeAsync, CurrentTime);
|
let potential_err =
|
||||||
|
display.grab_keyboard(root, false, GrabModeSync, GrabModeAsync, CurrentTime);
|
||||||
|
|
||||||
if potential_err != GrabSuccess {
|
if potential_err != GrabSuccess {
|
||||||
eprintln!("Couldn't grab keyboard!");
|
eprintln!("Couldn't grab keyboard!");
|
||||||
|
@ -94,7 +97,8 @@ fn event_loop(
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctx = recdpy.create_record_context(protocol_ranges);
|
let ctx = recdpy.create_record_context(protocol_ranges);
|
||||||
let ev_cb_data = EvCallbackData::new(writer, xdpy, recdpy, ctx, stop_key, pointer_pos, max_delay);
|
let ev_cb_data =
|
||||||
|
EvCallbackData::new(writer, xdpy, recdpy, ctx, stop_key, pointer_pos, max_delay);
|
||||||
|
|
||||||
if !recdpy.enable_context_async(ctx, Some(ev_callback), addr_of!(ev_cb_data) as *mut c_char) {
|
if !recdpy.enable_context_async(ctx, Some(ev_callback), addr_of!(ev_cb_data) as *mut c_char) {
|
||||||
panic!("Failed to enable record context")
|
panic!("Failed to enable record context")
|
||||||
|
@ -130,8 +134,10 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
data.update_pos(intercept_data);
|
data.update_pos(intercept_data);
|
||||||
data.write_pos();
|
data.write_pos();
|
||||||
} else {
|
} else {
|
||||||
println!("Move your cursor so the macro can start with a fixed cursor position!
|
println!(
|
||||||
Skipping event...");
|
"Move your cursor so the macro can start with a fixed cursor position!
|
||||||
|
Skipping event..."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if data.no_keypress_yet && ev_type == KEYRELEASE_U8 {
|
} else if data.no_keypress_yet && ev_type == KEYRELEASE_U8 {
|
||||||
println!("Skipping KeyRelease without recorded KeyPress...");
|
println!("Skipping KeyRelease without recorded KeyPress...");
|
||||||
|
@ -157,7 +163,9 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
|
|
||||||
data.maybe_write_delay(intercept_data.server_time);
|
data.maybe_write_delay(intercept_data.server_time);
|
||||||
|
|
||||||
if data.ptr_is_moving() { data.write_pos(); }
|
if data.ptr_is_moving() {
|
||||||
|
data.write_pos();
|
||||||
|
}
|
||||||
|
|
||||||
data.writer.write(if ev_type == KEYPRESS_U8 {
|
data.writer.write(if ev_type == KEYPRESS_U8 {
|
||||||
Instructions::KeyStrPress(keyname)
|
Instructions::KeyStrPress(keyname)
|
||||||
|
@ -171,7 +179,9 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
|
|
||||||
data.maybe_write_delay(intercept_data.server_time);
|
data.maybe_write_delay(intercept_data.server_time);
|
||||||
|
|
||||||
if data.ptr_is_moving() { data.write_pos(); }
|
if data.ptr_is_moving() {
|
||||||
|
data.write_pos();
|
||||||
|
}
|
||||||
|
|
||||||
data.writer.write(if ev_type == BUTTONPRESS_U8 {
|
data.writer.write(if ev_type == BUTTONPRESS_U8 {
|
||||||
Instructions::ButtonPress(bc)
|
Instructions::ButtonPress(bc)
|
||||||
|
@ -179,11 +189,10 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
Instructions::ButtonRelease(bc)
|
Instructions::ButtonRelease(bc)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => eprintln!("Unknown event type: {:?}", ev_type)
|
_ => eprintln!("Unknown event type: {:?}", ev_type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.ev_nr += 2;
|
data.ev_nr += 2;
|
||||||
XRecordFreeData(intercept_data)
|
XRecordFreeData(intercept_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
use crate::macro_writer::MacroWriter;
|
||||||
|
use crate::x11_safe_wrapper::XDisplay;
|
||||||
|
use crate::{Instructions, Keycode, Position};
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use x11::xlib::Time;
|
use x11::xlib::Time;
|
||||||
use x11::xrecord::{XRecordContext, XRecordInterceptData};
|
use x11::xrecord::{XRecordContext, XRecordInterceptData};
|
||||||
use crate::{Instructions, Keycode, Position};
|
|
||||||
use crate::macro_writer::MacroWriter;
|
|
||||||
use crate::x11_safe_wrapper::XDisplay;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct EvCallbackData {
|
pub struct EvCallbackData {
|
||||||
|
@ -43,14 +43,22 @@ impl EvCallbackData {
|
||||||
pos,
|
pos,
|
||||||
max_delay,
|
max_delay,
|
||||||
no_keypress_yet: true,
|
no_keypress_yet: true,
|
||||||
last_event: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as Time,
|
last_event: SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis() as Time,
|
||||||
moving: false,
|
moving: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ptr_is_moving(&self) -> bool { self.moving }
|
pub fn ptr_is_moving(&self) -> bool {
|
||||||
|
self.moving
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn update_pos(&mut self, intercept_data: &mut XRecordInterceptData) -> Position<i16> {
|
pub unsafe fn update_pos(
|
||||||
|
&mut self,
|
||||||
|
intercept_data: &mut XRecordInterceptData,
|
||||||
|
) -> Position<i16> {
|
||||||
self.pos.0 = *((intercept_data.data as usize + size_of::<i16>() * 10) as *const i16);
|
self.pos.0 = *((intercept_data.data as usize + size_of::<i16>() * 10) as *const i16);
|
||||||
self.pos.1 = *((intercept_data.data as usize + size_of::<i16>() * 11) as *const i16);
|
self.pos.1 = *((intercept_data.data as usize + size_of::<i16>() * 11) as *const i16);
|
||||||
self.pos
|
self.pos
|
||||||
|
@ -63,7 +71,11 @@ impl EvCallbackData {
|
||||||
|
|
||||||
pub fn maybe_write_delay(&mut self, server_time: Time) {
|
pub fn maybe_write_delay(&mut self, server_time: Time) {
|
||||||
if server_time - self.last_event > 1 {
|
if server_time - self.last_event > 1 {
|
||||||
self.writer.write(Instructions::Delay(calculate_delay(server_time, self.last_event, self.max_delay)));
|
self.writer.write(Instructions::Delay(calculate_delay(
|
||||||
|
server_time,
|
||||||
|
self.last_event,
|
||||||
|
self.max_delay,
|
||||||
|
)));
|
||||||
self.last_event = server_time;
|
self.last_event = server_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,4 +95,3 @@ fn calculate_delay(server_time: Time, last_event: Time, max_delay: Option<Time>)
|
||||||
server_time - last_event
|
server_time - last_event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -7,10 +7,12 @@ use x11::xlib::{ButtonPress, ButtonRelease, KeyPress, KeyRelease, MotionNotify,
|
||||||
|
|
||||||
use crate::x11_safe_wrapper::{Keycode, Keysym};
|
use crate::x11_safe_wrapper::{Keycode, Keysym};
|
||||||
|
|
||||||
pub mod x11_safe_wrapper;
|
pub mod xwrap;
|
||||||
|
|
||||||
pub mod chartbl;
|
pub mod chartbl;
|
||||||
pub mod macro_writer;
|
|
||||||
pub mod ev_callback_data;
|
pub mod ev_callback_data;
|
||||||
|
pub mod macro_writer;
|
||||||
|
pub mod x11_safe_wrapper;
|
||||||
|
|
||||||
pub const KEYPRESS_U8: u8 = KeyPress as u8;
|
pub const KEYPRESS_U8: u8 = KeyPress as u8;
|
||||||
pub const KEYRELEASE_U8: u8 = KeyRelease as u8;
|
pub const KEYRELEASE_U8: u8 = KeyRelease as u8;
|
||||||
|
@ -60,7 +62,9 @@ pub enum Instructions<'a> {
|
||||||
|
|
||||||
impl Display for Instructions<'_> {
|
impl Display for Instructions<'_> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}",
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
match self {
|
match self {
|
||||||
Instructions::Delay(d) => format!("Delay {}", d),
|
Instructions::Delay(d) => format!("Delay {}", d),
|
||||||
Instructions::ButtonPress(b) => format!("ButtonPress {}", b),
|
Instructions::ButtonPress(b) => format!("ButtonPress {}", b),
|
||||||
|
@ -71,8 +75,10 @@ impl Display for Instructions<'_> {
|
||||||
Instructions::KeySymPress(ks) => format!("KeySymPress {}", ks),
|
Instructions::KeySymPress(ks) => format!("KeySymPress {}", ks),
|
||||||
Instructions::KeySymRelease(ks) => format!("KeySymRelease {}", ks),
|
Instructions::KeySymRelease(ks) => format!("KeySymRelease {}", ks),
|
||||||
Instructions::KeySym(ks) => format!("KeySym {}", ks),
|
Instructions::KeySym(ks) => format!("KeySym {}", ks),
|
||||||
Instructions::KeyStrPress(kstr) => format!("KeyStrPress {}", kstr.to_str().unwrap()),
|
Instructions::KeyStrPress(kstr) =>
|
||||||
Instructions::KeyStrRelease(kstr) => format!("KeyStrRelease {}", kstr.to_str().unwrap()),
|
format!("KeyStrPress {}", kstr.to_str().unwrap()),
|
||||||
|
Instructions::KeyStrRelease(kstr) =>
|
||||||
|
format!("KeyStrRelease {}", kstr.to_str().unwrap()),
|
||||||
Instructions::KeyStr(kstr) => format!("KeyStr {}", kstr.to_str().unwrap()),
|
Instructions::KeyStr(kstr) => format!("KeyStr {}", kstr.to_str().unwrap()),
|
||||||
Instructions::String(str) => format!("String {}", str),
|
Instructions::String(str) => format!("String {}", str),
|
||||||
Instructions::ExecBlock(cmd) => format!("ExecBlock {}", cmd),
|
Instructions::ExecBlock(cmd) => format!("ExecBlock {}", cmd),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use crate::Instructions;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use crate::Instructions;
|
|
||||||
|
|
||||||
pub struct MacroWriter {
|
pub struct MacroWriter {
|
||||||
outfile: Box<dyn Write>,
|
outfile: Box<dyn Write>,
|
||||||
|
@ -27,7 +27,7 @@ impl MacroWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(&mut self.outfile, "{}", instruction).expect("Failed to write instruction to outfile");
|
writeln!(&mut self.outfile, "{}", instruction)
|
||||||
|
.expect("Failed to write instruction to outfile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
use std::{env, slice};
|
|
||||||
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 std::{env, slice};
|
||||||
|
|
||||||
use x11::xlib::{Display, GenericEvent, KeyPress, MotionNotify, Time, Window, XAllowEvents, XCloseDisplay, XConvertCase, XDefaultScreen, XEvent, XFlush, XGetKeyboardMapping, XGrabKeyboard, XKeycodeToKeysym, XKeysymToKeycode, XKeysymToString, XOpenDisplay, XQueryPointer, XRootWindow, XStringToKeysym, XSync, XUngrabKeyboard, XUngrabPointer, XWindowEvent};
|
use x11::xlib::{
|
||||||
use x11::xrecord::{XRecordAllClients, XRecordClientSpec, XRecordContext, XRecordCreateContext, XRecordDisableContext, XRecordEnableContext, XRecordEnableContextAsync, XRecordFreeContext, XRecordInterceptData, XRecordProcessReplies, XRecordQueryVersion, XRecordRange};
|
Display, GenericEvent, KeyPress, MotionNotify, Time, Window, XAllowEvents, XCloseDisplay,
|
||||||
|
XConvertCase, XDefaultScreen, XEvent, XFlush, XGetKeyboardMapping, XGrabKeyboard,
|
||||||
|
XKeycodeToKeysym, XKeysymToKeycode, XKeysymToString, XOpenDisplay, XQueryPointer, XRootWindow,
|
||||||
|
XStringToKeysym, XSync, XUngrabKeyboard, XUngrabPointer, XWindowEvent,
|
||||||
|
};
|
||||||
|
use x11::xrecord::{
|
||||||
|
XRecordAllClients, XRecordClientSpec, XRecordContext, XRecordCreateContext,
|
||||||
|
XRecordDisableContext, XRecordEnableContext, XRecordEnableContextAsync, XRecordFreeContext,
|
||||||
|
XRecordInterceptData, XRecordProcessReplies, XRecordQueryVersion, XRecordRange,
|
||||||
|
};
|
||||||
use x11::xtest::{
|
use x11::xtest::{
|
||||||
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
|
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
|
||||||
XTestQueryExtension,
|
XTestQueryExtension,
|
||||||
|
@ -26,7 +35,8 @@ impl XDisplay {
|
||||||
name
|
name
|
||||||
} else {
|
} else {
|
||||||
env::var("DISPLAY").expect("DISPLAY is not set")
|
env::var("DISPLAY").expect("DISPLAY is not set")
|
||||||
}).unwrap();
|
})
|
||||||
|
.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) };
|
||||||
|
|
||||||
|
@ -115,9 +125,7 @@ impl XDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keycode_to_keysym(&self, keycode: Keycode) -> Keysym {
|
pub fn keycode_to_keysym(&self, keycode: Keycode) -> Keysym {
|
||||||
unsafe {
|
unsafe { XKeycodeToKeysym(self.ptr, keycode as c_uchar, 0) }
|
||||||
XKeycodeToKeysym(self.ptr, keycode as c_uchar, 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keycode_to_string(&self, keycode: Keycode) -> CString {
|
pub fn keycode_to_string(&self, keycode: Keycode) -> CString {
|
||||||
|
@ -182,7 +190,14 @@ impl XDisplay {
|
||||||
unsafe { XAllowEvents(self.ptr, event_mode, time) };
|
unsafe { XAllowEvents(self.ptr, event_mode, time) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grab_keyboard(&self, window: u64, owner_events: bool, pointer_mode: i32, keyboard_mode: i32, time: Time) -> i32 {
|
pub fn grab_keyboard(
|
||||||
|
&self,
|
||||||
|
window: u64,
|
||||||
|
owner_events: bool,
|
||||||
|
pointer_mode: i32,
|
||||||
|
keyboard_mode: i32,
|
||||||
|
time: Time,
|
||||||
|
) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
XGrabKeyboard(
|
XGrabKeyboard(
|
||||||
self.ptr,
|
self.ptr,
|
||||||
|
@ -204,9 +219,13 @@ impl XDisplay {
|
||||||
}
|
}
|
||||||
pub fn window_event(&self, window: Window, event_mask: i64) -> XEvent {
|
pub fn window_event(&self, window: Window, event_mask: i64) -> XEvent {
|
||||||
// maybe dirty hack to initialize the event var?? idk how else to do this
|
// maybe dirty hack to initialize the event var?? idk how else to do this
|
||||||
let mut r: XEvent = XEvent { type_: GenericEvent };
|
let mut r: XEvent = XEvent {
|
||||||
|
type_: GenericEvent,
|
||||||
|
};
|
||||||
|
|
||||||
unsafe { XWindowEvent(self.ptr, window, event_mask, &mut r); }
|
unsafe {
|
||||||
|
XWindowEvent(self.ptr, window, event_mask, &mut r);
|
||||||
|
}
|
||||||
|
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
@ -214,7 +233,9 @@ impl XDisplay {
|
||||||
// XRecord stuff
|
// XRecord stuff
|
||||||
pub fn has_xrecord(&self) -> bool {
|
pub fn has_xrecord(&self) -> bool {
|
||||||
let mut xrecord_version: (c_int, c_int) = (0, 0);
|
let mut xrecord_version: (c_int, c_int) = (0, 0);
|
||||||
let xrec_res = unsafe { XRecordQueryVersion(self.ptr, &mut xrecord_version.0, &mut xrecord_version.1) };
|
let xrec_res = unsafe {
|
||||||
|
XRecordQueryVersion(self.ptr, &mut xrecord_version.0, &mut xrecord_version.1)
|
||||||
|
};
|
||||||
xrec_res == 0
|
xrec_res == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,49 +246,35 @@ impl XDisplay {
|
||||||
}
|
}
|
||||||
let mut clients: XRecordClientSpec = XRecordAllClients;
|
let mut clients: XRecordClientSpec = XRecordAllClients;
|
||||||
|
|
||||||
let ctx: XRecordContext = unsafe {
|
let ctx: XRecordContext =
|
||||||
XRecordCreateContext(
|
unsafe { XRecordCreateContext(self.ptr, 0, &mut clients, 1, &mut protocol_ranges, 1) };
|
||||||
self.ptr,
|
|
||||||
0,
|
|
||||||
&mut clients,
|
|
||||||
1,
|
|
||||||
&mut protocol_ranges,
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_context(&self,
|
pub fn enable_context(
|
||||||
|
&self,
|
||||||
ctx: XRecordContext,
|
ctx: XRecordContext,
|
||||||
cb: Option<unsafe extern "C" fn(_: *mut c_char, _: *mut XRecordInterceptData)>,
|
cb: Option<unsafe extern "C" fn(_: *mut c_char, _: *mut XRecordInterceptData)>,
|
||||||
closure: *mut c_char,
|
closure: *mut c_char,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
unsafe {
|
unsafe { XRecordEnableContext(self.ptr, ctx, cb, closure as *mut c_char) != 0 }
|
||||||
XRecordEnableContext(self.ptr, ctx, cb, closure as *mut c_char) != 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_context_async(&self,
|
pub fn enable_context_async(
|
||||||
|
&self,
|
||||||
ctx: XRecordContext,
|
ctx: XRecordContext,
|
||||||
cb: Option<unsafe extern "C" fn(_: *mut c_char, _: *mut XRecordInterceptData)>,
|
cb: Option<unsafe extern "C" fn(_: *mut c_char, _: *mut XRecordInterceptData)>,
|
||||||
closure: *mut c_char,
|
closure: *mut c_char,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
unsafe {
|
unsafe { XRecordEnableContextAsync(self.ptr, ctx, cb, closure as *mut c_char) != 0 }
|
||||||
XRecordEnableContextAsync(self.ptr, ctx, cb, closure as *mut c_char) != 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_context(&self, ctx: XRecordContext) -> bool {
|
pub fn disable_context(&self, ctx: XRecordContext) -> bool {
|
||||||
unsafe {
|
unsafe { XRecordDisableContext(self.ptr, ctx) != 0 }
|
||||||
XRecordDisableContext(self.ptr, ctx) != 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_context(&self, ctx: XRecordContext) -> bool {
|
pub fn free_context(&self, ctx: XRecordContext) -> bool {
|
||||||
unsafe {
|
unsafe { XRecordFreeContext(self.ptr, ctx) != 0 }
|
||||||
XRecordFreeContext(self.ptr, ctx) != 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_replies(&self) {
|
pub fn process_replies(&self) {
|
||||||
|
|
Loading…
Reference in a new issue