did stuff
This commit is contained in:
parent
9521e26cbc
commit
ea2245d7b1
3 changed files with 229 additions and 128 deletions
|
@ -4,17 +4,25 @@ use std::os::raw::{c_char, c_uchar, c_uint};
|
||||||
use std::process::{exit, ExitCode};
|
use std::process::{exit, ExitCode};
|
||||||
use std::ptr::{addr_of, slice_from_raw_parts};
|
use std::ptr::{addr_of, slice_from_raw_parts};
|
||||||
use std::{io, slice, thread};
|
use std::{io, slice, thread};
|
||||||
|
use std::borrow::BorrowMut;
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::env::args;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::fmt::{format};
|
use std::fmt::format;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
|
use std::mem::size_of;
|
||||||
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use x11::keysym::XK_Escape;
|
use x11::keysym::XK_Escape;
|
||||||
use x11::xinput2::XIGrabModeSync;
|
use x11::xinput2::XIGrabModeSync;
|
||||||
use x11::xlib::{ButtonPress, ButtonRelease, CurrentTime, GrabModeAsync, GrabModeSync, GrabSuccess, KeyCode, KeyPress, KeyPressMask, KeyRelease, MotionNotify, SyncPointer, XEvent, XFree, XKeyEvent, XKeyPressedEvent, XPointer};
|
use x11::xlib::{ButtonPress, ButtonRelease, CurrentTime, GrabModeAsync, GrabModeSync, GrabSuccess, KeyCode, KeyPress, KeyPressMask, KeyRelease, MotionNotify, SyncPointer, Time, XEvent, XFree, XKeyEvent, XKeyPressedEvent, XPointer};
|
||||||
use x11::xrecord::{XRecordAllocRange, XRecordContext, XRecordCreateContext, XRecordDisableContext, XRecordEndOfData, XRecordFreeData, XRecordInterceptData, XRecordStartOfData};
|
use x11::xrecord::{XRecordAllocRange, XRecordContext, XRecordCreateContext, XRecordDisableContext, XRecordEndOfData, XRecordFreeData, XRecordInterceptData, XRecordStartOfData};
|
||||||
|
use easymacros::{Instructions, Position};
|
||||||
use easymacros::x11_safe_wrapper::{Keycode, XDisplay};
|
use easymacros::x11_safe_wrapper::{Keycode, XDisplay};
|
||||||
|
|
||||||
|
const DELAY_DEFAULT_MS: u16 = 10;
|
||||||
|
|
||||||
/// 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)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
@ -23,7 +31,7 @@ struct Args {
|
||||||
#[clap(value_parser, value_name = "output_file", value_hint = clap::ValueHint::FilePath)]
|
#[clap(value_parser, value_name = "output_file", value_hint = clap::ValueHint::FilePath)]
|
||||||
output_file: Option<std::path::PathBuf>,
|
output_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>,
|
||||||
/// Max Delay in milliseconds for macro delays
|
/// Max Delay in milliseconds for macro delays
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
@ -32,25 +40,22 @@ struct Args {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
ignore_delay_capturing: bool,
|
ignore_delay_capturing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let display = XDisplay::open(args.display.clone());
|
let display = XDisplay::open(args.display.clone());
|
||||||
let recorded_display = XDisplay::open(args.display.clone());
|
let recorded_display = XDisplay::open(args.display.clone());
|
||||||
|
|
||||||
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 screen = display.get_default_screen();
|
event_loop(
|
||||||
dbg!(stop_key);
|
display,
|
||||||
|
recorded_display,
|
||||||
// check if the output file argument is specified, if not use stdout
|
stop_key,
|
||||||
let mut outfile: Box<dyn Write> = if let Some(outfile) = args.output_file {
|
writer,
|
||||||
Box::new(File::create(outfile).expect("Failed to create output file"))
|
args.max_delay
|
||||||
} else {
|
);
|
||||||
Box::new(io::stdout())
|
|
||||||
};
|
|
||||||
|
|
||||||
event_loop(display, recorded_display, screen, stop_key, outfile, args.ignore_delay_capturing, args.max_delay);
|
|
||||||
|
|
||||||
display.close();
|
display.close();
|
||||||
}
|
}
|
||||||
|
@ -69,18 +74,11 @@ fn get_stop_key(display: XDisplay) -> Keycode {
|
||||||
println!("Press the key you want to use to stop recording the macro.");
|
println!("Press the key you want to use to stop recording the macro.");
|
||||||
|
|
||||||
let mut stop_key: Keycode = XK_Escape;
|
let mut stop_key: Keycode = XK_Escape;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
display.allow_events(SyncPointer, CurrentTime);
|
display.allow_events(SyncPointer, CurrentTime);
|
||||||
let ev = display.window_event(root, KeyPressMask);
|
let ev = XKeyEvent::from(display.window_event(root, KeyPressMask));
|
||||||
|
stop_key = ev.keycode;
|
||||||
unsafe {
|
break;
|
||||||
//if it's a key event, save the keycode and break out of the loop
|
|
||||||
if let XEvent { key } = ev {
|
|
||||||
stop_key = key.keycode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
display.ungrab_keyboard(CurrentTime);
|
display.ungrab_keyboard(CurrentTime);
|
||||||
|
@ -89,65 +87,99 @@ fn get_stop_key(display: XDisplay) -> Keycode {
|
||||||
stop_key
|
stop_key
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_loop(display: XDisplay, recordeddpy: XDisplay, screen: i32, stop_key: Keycode, mut outfile: Box<dyn Write>, ignore_delay_capturing: bool, max_delay: Option<u64>) {
|
fn event_loop(
|
||||||
|
xdpy: XDisplay,
|
||||||
|
recdpy: XDisplay,
|
||||||
|
stop_key: Keycode,
|
||||||
|
mut writer: MacroWriter,
|
||||||
|
max_delay: Option<Time>
|
||||||
|
) {
|
||||||
// let root = display.get_root_window(screen);
|
// let root = display.get_root_window(screen);
|
||||||
let protocol_ranges = unsafe { XRecordAllocRange() };
|
let protocol_ranges = unsafe { XRecordAllocRange() };
|
||||||
|
|
||||||
let pointer_pos = display.query_pointer_pos();
|
let pointer_pos: Position<i16> = Position::from(xdpy.query_pointer_pos());
|
||||||
|
|
||||||
if pointer_pos != (-1, -1) {
|
if pointer_pos != Position (-1, -1) {
|
||||||
writeln!(&mut outfile, "MotionNotify {} {}", pointer_pos.0, pointer_pos.1)
|
writer.write(Instructions::MotionNotify(pointer_pos))
|
||||||
.expect("Failed to write to outfile");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctx = recordeddpy.create_record_context(protocol_ranges);
|
let ctx = recdpy.create_record_context(protocol_ranges);
|
||||||
let ev_cb_data = EvCallbackData {
|
let ev_cb_data = EvCallbackData::new(writer, xdpy, recdpy, ctx, stop_key, pointer_pos, max_delay);
|
||||||
outfile,
|
|
||||||
xdpy: display,
|
|
||||||
recdpy: recordeddpy,
|
|
||||||
ctx,
|
|
||||||
stop_key,
|
|
||||||
ev_nr: 0,
|
|
||||||
working: true,
|
|
||||||
x: pointer_pos.0 as i16,
|
|
||||||
y: pointer_pos.1 as i16,
|
|
||||||
ignore_delay_capturing,
|
|
||||||
max_delay,
|
|
||||||
no_keypress_yet: true,
|
|
||||||
last_event: 0,
|
|
||||||
moving: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !recordeddpy.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")
|
||||||
}
|
}
|
||||||
while ev_cb_data.working {
|
while ev_cb_data.working {
|
||||||
recordeddpy.process_replies();
|
recdpy.process_replies();
|
||||||
}
|
}
|
||||||
|
|
||||||
display.disable_context(ctx);
|
xdpy.disable_context(ctx);
|
||||||
display.free_context(ctx);
|
xdpy.free_context(ctx);
|
||||||
unsafe { XFree(protocol_ranges as *mut c_void) };
|
unsafe { XFree(protocol_ranges as *mut c_void) };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct EvCallbackData {
|
pub struct EvCallbackData {
|
||||||
outfile: Box<dyn Write>,
|
pub writer: MacroWriter,
|
||||||
xdpy: XDisplay,
|
pub xdpy: XDisplay,
|
||||||
recdpy: XDisplay,
|
pub recdpy: XDisplay,
|
||||||
|
pub ctx: XRecordContext,
|
||||||
stop_key: Keycode,
|
stop_key: Keycode,
|
||||||
ev_nr: u32,
|
ev_nr: u32,
|
||||||
working: bool,
|
working: bool,
|
||||||
ctx: XRecordContext,
|
pos: Position<i16>,
|
||||||
x: i16,
|
max_delay: Option<Time>,
|
||||||
y: i16,
|
|
||||||
ignore_delay_capturing: bool,
|
|
||||||
max_delay: Option<u64>,
|
|
||||||
no_keypress_yet: bool,
|
no_keypress_yet: bool,
|
||||||
last_event: u64,
|
last_event: Time,
|
||||||
moving: bool,
|
moving: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EvCallbackData {
|
||||||
|
pub fn new(
|
||||||
|
writer: MacroWriter,
|
||||||
|
xdpy: XDisplay,
|
||||||
|
recdpy: XDisplay,
|
||||||
|
ctx: XRecordContext,
|
||||||
|
stop_key: Keycode,
|
||||||
|
pos: Position<i16>,
|
||||||
|
max_delay: Option<Time>,
|
||||||
|
) -> Self {
|
||||||
|
EvCallbackData {
|
||||||
|
writer,
|
||||||
|
xdpy,
|
||||||
|
recdpy,
|
||||||
|
ctx,
|
||||||
|
stop_key,
|
||||||
|
ev_nr: 0,
|
||||||
|
working: true,
|
||||||
|
pos,
|
||||||
|
max_delay,
|
||||||
|
no_keypress_yet: true,
|
||||||
|
last_event: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as Time,
|
||||||
|
moving: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptr_is_moving(&self) -> bool { self.moving }
|
||||||
|
|
||||||
|
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.1 = *((intercept_data.data as usize + size_of::<i16>() * 11) as *const i16);
|
||||||
|
self.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_pos(&mut self) {
|
||||||
|
self.writer.write(Instructions::MotionNotify(self.pos));
|
||||||
|
self.moving = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maybe_write_delay(&mut self, server_time: Time) {
|
||||||
|
if server_time - self.last_event > 1 {
|
||||||
|
self.writer.write(Instructions::Delay(calculate_delay(server_time, self.last_event, self.max_delay)));
|
||||||
|
self.last_event = server_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRecordInterceptData) {
|
unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRecordInterceptData) {
|
||||||
let data = &mut *(closure as *mut EvCallbackData);
|
let data = &mut *(closure as *mut EvCallbackData);
|
||||||
|
@ -155,6 +187,7 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
|
|
||||||
if intercept_data.category == XRecordStartOfData {
|
if intercept_data.category == XRecordStartOfData {
|
||||||
println!("Got start of data!");
|
println!("Got start of data!");
|
||||||
|
data.last_event = intercept_data.server_time;
|
||||||
XRecordFreeData(intercept_data);
|
XRecordFreeData(intercept_data);
|
||||||
return;
|
return;
|
||||||
} else if intercept_data.category == XRecordEndOfData {
|
} else if intercept_data.category == XRecordEndOfData {
|
||||||
|
@ -164,14 +197,14 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
}
|
}
|
||||||
|
|
||||||
let ev_type = *(intercept_data.data as *const u8);
|
let ev_type = *(intercept_data.data as *const u8);
|
||||||
if data.x == -1 || data.y == -1 {
|
|
||||||
|
if data.pos.0 == 0 || data.pos.1 == -1 {
|
||||||
if ev_type == MOTIONNOTIFY_U8 {
|
if ev_type == MOTIONNOTIFY_U8 {
|
||||||
data.x = *((intercept_data.data as usize + std::mem::size_of::<i16>() * 10) as *const i16);
|
data.update_pos(intercept_data);
|
||||||
data.y = *((intercept_data.data as usize + std::mem::size_of::<i16>() * 11) as *const i16);
|
data.write_pos();
|
||||||
println!("MotionNotify {} {}", data.x, data.y);
|
|
||||||
} else {
|
} else {
|
||||||
println!("Move your cursor so the macro can start with a fixed cursor position!");
|
println!("Move your cursor so the macro can start with a fixed cursor position!
|
||||||
println!("Skipping event...");
|
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...");
|
||||||
|
@ -179,10 +212,7 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
// if
|
// if
|
||||||
match ev_type {
|
match ev_type {
|
||||||
MOTIONNOTIFY_U8 => {
|
MOTIONNOTIFY_U8 => {
|
||||||
let root_x = *((intercept_data.data as usize + std::mem::size_of::<i16>() * 10) as *const i16);
|
data.update_pos(intercept_data);
|
||||||
let root_y = *((intercept_data.data as usize + std::mem::size_of::<i16>() * 11) as *const i16);
|
|
||||||
data.x = root_x;
|
|
||||||
data.y = root_y;
|
|
||||||
|
|
||||||
if !data.moving {
|
if !data.moving {
|
||||||
data.moving = true;
|
data.moving = true;
|
||||||
|
@ -199,62 +229,81 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
data.no_keypress_yet = false;
|
data.no_keypress_yet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !data.ignore_delay_capturing && (intercept_data.server_time - data.last_event) != 0 {
|
data.maybe_write_delay(intercept_data.server_time);
|
||||||
writeln!(&mut data.outfile,"Delay {}", if let Some(max_delay) = data.max_delay {
|
|
||||||
let delay_res = intercept_data.server_time - data.last_event;
|
|
||||||
if delay_res > max_delay { max_delay } else { delay_res }
|
|
||||||
} else { intercept_data.server_time - data.last_event })
|
|
||||||
.expect("Failed to write to outfile.");
|
|
||||||
data.last_event = intercept_data.server_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.moving {
|
if data.ptr_is_moving() { data.write_pos(); }
|
||||||
writeln!(&mut data.outfile, "MotionNotify {} {}", data.x, data.y)
|
|
||||||
.expect("Failed to write to outfile.");
|
|
||||||
data.moving = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(
|
data.writer.write(if ev_type == KEYPRESS_U8 {
|
||||||
&mut data.outfile,
|
Instructions::KeyStrPress(keyname)
|
||||||
"{} {}",
|
} else {
|
||||||
if ev_type == KEYPRESS_U8 { "KeyStrPress" } else { "KeyRelease" },
|
Instructions::KeyStrRelease(keyname)
|
||||||
keyname.to_str().unwrap()
|
});
|
||||||
).expect("Failed to write to outfile.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BUTTONPRESS_U8 | BUTTONRELEASE_U8 => {
|
BUTTONPRESS_U8 | BUTTONRELEASE_U8 => {
|
||||||
let bc: u8 = *((intercept_data.data as usize + 1) as *const u8);
|
let bc: u8 = *((intercept_data.data as usize + 1) as *const u8);
|
||||||
|
|
||||||
if !data.ignore_delay_capturing && (intercept_data.server_time - data.last_event) != 0 {
|
data.maybe_write_delay(intercept_data.server_time);
|
||||||
writeln!(&mut data.outfile,"Delay {}", if let Some(max_delay) = data.max_delay {
|
|
||||||
let delay_res = intercept_data.server_time - data.last_event;
|
|
||||||
if delay_res > max_delay { max_delay } else { delay_res }
|
|
||||||
} else { intercept_data.server_time - data.last_event })
|
|
||||||
.expect("Failed to write to outfile.");
|
|
||||||
data.last_event = intercept_data.server_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.moving {
|
if data.ptr_is_moving() { data.write_pos(); }
|
||||||
writeln!(&mut data.outfile, "MotionNotify {} {}", data.x, data.y)
|
|
||||||
.expect("Failed to write to outfile.");
|
|
||||||
data.moving = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(
|
if ev_type == BUTTONPRESS_U8 {
|
||||||
&mut data.outfile,
|
data.writer.write(Instructions::ButtonPress(bc));
|
||||||
"{} {}",
|
} else {
|
||||||
if ev_type == BUTTONPRESS_U8 { "ButtonPress" } else { "ButtonRelease" },
|
data.writer.write(Instructions::ButtonRelease(bc));
|
||||||
bc
|
}
|
||||||
).expect("Failed to write to outfile.");
|
|
||||||
}
|
}
|
||||||
_ => eprintln!("Unknown event type: {:?}", ev_type)
|
_ => eprintln!("Unknown event type: {:?}", ev_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.ev_nr += 1;
|
data.ev_nr += 2;
|
||||||
XRecordFreeData(intercept_data)
|
XRecordFreeData(intercept_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calculate_delay(server_time: Time, last_event: Time, max_delay: Option<Time>) -> Time {
|
||||||
|
if let Some(max) = max_delay {
|
||||||
|
let max = max as u64;
|
||||||
|
let delay = server_time - last_event;
|
||||||
|
|
||||||
|
if delay > max {
|
||||||
|
max
|
||||||
|
} else {
|
||||||
|
delay
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
server_time - last_event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MacroWriter {
|
||||||
|
outfile: Box<dyn Write>,
|
||||||
|
ignore_delay_capturing: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MacroWriter {
|
||||||
|
pub fn new(outfile: Option<std::path::PathBuf>, ignore_delay_capturing: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
outfile: if let Some(outfile) = outfile {
|
||||||
|
Box::new(File::create(outfile).expect("Failed to create output file"))
|
||||||
|
} else {
|
||||||
|
Box::new(io::stdout())
|
||||||
|
},
|
||||||
|
ignore_delay_capturing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, instruction: Instructions) {
|
||||||
|
if self.ignore_delay_capturing {
|
||||||
|
if let Instructions::Delay(_) = instruction {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(&mut self.outfile, "{}", instruction).expect("Failed to write instruction to outfile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const KEYPRESS_U8: u8 = KeyPress as u8;
|
const KEYPRESS_U8: u8 = KeyPress as u8;
|
||||||
const KEYRELEASE_U8: u8 = KeyRelease as u8;
|
const KEYRELEASE_U8: u8 = KeyRelease as u8;
|
||||||
const BUTTONPRESS_U8: u8 = ButtonPress as u8;
|
const BUTTONPRESS_U8: u8 = ButtonPress as u8;
|
||||||
|
|
85
src/lib.rs
85
src/lib.rs
|
@ -1,23 +1,74 @@
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::time::Duration;
|
||||||
|
use x11::xlib::Time;
|
||||||
|
use crate::x11_safe_wrapper::{Keycode, Keysym};
|
||||||
|
|
||||||
pub mod x11_safe_wrapper;
|
pub mod x11_safe_wrapper;
|
||||||
pub mod chartbl;
|
pub mod chartbl;
|
||||||
|
|
||||||
pub enum XMacroInstructions {
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
Delay,
|
pub struct Position<T> (pub T, pub T);
|
||||||
ButtonPress,
|
|
||||||
ButtonRelease,
|
impl From<Position<i32>> for Position<i16> {
|
||||||
MotionNotify,
|
fn from(pos: Position<i32>) -> Self {
|
||||||
KeyCodePress,
|
Self (pos.0 as i16, pos.1 as i16)
|
||||||
KeyCodeRelease,
|
}
|
||||||
// Screenshot,
|
}
|
||||||
KeySymPress,
|
|
||||||
KeySymRelease,
|
impl From<(i32, i32)> for Position<i32> {
|
||||||
KeySym,
|
fn from(v: (i32, i32)) -> Self {
|
||||||
KeyStrPress,
|
Position(v.0, v.1)
|
||||||
KeyStrRelease,
|
}
|
||||||
KeyStr,
|
}
|
||||||
String,
|
|
||||||
// ExecBlock,
|
impl From<(i32, i32)> for Position<i16> {
|
||||||
// ExecNoBlock,
|
fn from(v: (i32, i32)) -> Position<i16> {
|
||||||
|
let p1: Position<i32> = Position::from(v);
|
||||||
|
Position::from(p1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Instructions<'a> {
|
||||||
|
Delay(Time),
|
||||||
|
ButtonPress(u8),
|
||||||
|
ButtonRelease(u8),
|
||||||
|
MotionNotify(Position<i16>),
|
||||||
|
KeyCodePress(Keycode),
|
||||||
|
KeyCodeRelease(Keycode),
|
||||||
|
KeySymPress(Keysym),
|
||||||
|
KeySymRelease(Keysym),
|
||||||
|
KeySym(Keysym),
|
||||||
|
KeyStrPress(CString),
|
||||||
|
KeyStrRelease(CString),
|
||||||
|
KeyStr(CString),
|
||||||
|
String(&'a str),
|
||||||
|
ExecBlock(&'a str),
|
||||||
|
ExecNoBlock(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Instructions<'_> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}",
|
||||||
|
match self {
|
||||||
|
Instructions::Delay(d) => format!("Delay {}", d),
|
||||||
|
Instructions::ButtonPress(b) => format!("ButtonPress {}", b),
|
||||||
|
Instructions::ButtonRelease(b) => format!("ButtonRelease {}", b),
|
||||||
|
Instructions::MotionNotify(pos) => format!("MotionNotify {} {}", pos.0, pos.1),
|
||||||
|
Instructions::KeyCodePress(kc) => format!("KeyCodePress {}", kc),
|
||||||
|
Instructions::KeyCodeRelease(kc) => format!("KeyCodeRelease {}", kc),
|
||||||
|
Instructions::KeySymPress(ks) => format!("KeySymPress {}", ks),
|
||||||
|
Instructions::KeySymRelease(ks) => format!("KeySymRelease {}", ks),
|
||||||
|
Instructions::KeySym(ks) => format!("KeySym {}", ks),
|
||||||
|
Instructions::KeyStrPress(kstr) => 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::String(str) => format!("String {}", str),
|
||||||
|
Instructions::ExecBlock(cmd) => format!("ExecBlock {}", cmd),
|
||||||
|
Instructions::ExecNoBlock(cmd) => format!("ExecNoBlock {}", cmd),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use x11::xtest::{
|
||||||
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
|
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
|
||||||
XTestQueryExtension,
|
XTestQueryExtension,
|
||||||
};
|
};
|
||||||
use crate::XMacroInstructions::KeySym;
|
use crate::Instructions::KeySym;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct XDisplay {
|
pub struct XDisplay {
|
||||||
|
@ -277,9 +277,10 @@ impl XDisplay {
|
||||||
pub fn string_to_keysym(string: &[u8]) -> Keysym {
|
pub fn string_to_keysym(string: &[u8]) -> Keysym {
|
||||||
unsafe { XStringToKeysym(string.as_ptr() as *const c_char) }
|
unsafe { XStringToKeysym(string.as_ptr() as *const c_char) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keysym_to_string(keysym: Keysym) -> CString {
|
pub fn keysym_to_string(keysym: Keysym) -> CString {
|
||||||
unsafe {
|
unsafe {
|
||||||
let cstr = CStr::from_ptr(XKeysymToString(keysym));
|
let cstr = CStr::from_ptr(XKeysymToString(keysym));
|
||||||
CString::from(cstr)
|
CString::from(cstr)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue