can now apparently read events
This commit is contained in:
parent
39916cd6db
commit
8232c4f6a9
2 changed files with 90 additions and 41 deletions
|
@ -1,12 +1,12 @@
|
||||||
use std::os::raw::{c_char, c_uint};
|
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;
|
use std::ptr::{addr_of, slice_from_raw_parts};
|
||||||
use std::thread;
|
use std::{slice, thread};
|
||||||
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::{CurrentTime, GrabModeAsync, GrabModeSync, GrabSuccess, KeyCode, KeyPress, KeyPressMask, SyncPointer, XEvent, XPointer};
|
use x11::xlib::{CurrentTime, GrabModeAsync, GrabModeSync, GrabSuccess, KeyCode, KeyPress, KeyPressMask, SyncPointer, XEvent, XFree, XKeyEvent, XKeyPressedEvent, XPointer};
|
||||||
use x11::xrecord::{XRecordCreateContext, XRecordEndOfData, XRecordInterceptData, XRecordStartOfData};
|
use x11::xrecord::{XRecordContext, XRecordCreateContext, XRecordDisableContext, XRecordEndOfData, XRecordFreeData, XRecordInterceptData, XRecordStartOfData};
|
||||||
use easymacros::x11_safe_wrapper::{Keycode, XDisplay};
|
use easymacros::x11_safe_wrapper::{Keycode, XDisplay};
|
||||||
|
|
||||||
/// Macro recording module for easymacros. Outputs are partially compatible with xmacro.
|
/// Macro recording module for easymacros. Outputs are partially compatible with xmacro.
|
||||||
|
@ -23,17 +23,19 @@ struct Args {
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let display = XDisplay::open(args.display);
|
let 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 screen = display.get_default_screen();
|
let screen = display.get_default_screen();
|
||||||
dbg!(stop_key);
|
dbg!(stop_key);
|
||||||
|
|
||||||
ev_loop(display, screen, stop_key);
|
ev_loop(display, recorded_display, screen, stop_key);
|
||||||
|
display.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_stop_key(display: &XDisplay) -> Keycode {
|
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);
|
||||||
|
@ -66,24 +68,37 @@ fn get_stop_key(display: &XDisplay) -> Keycode {
|
||||||
stop_key
|
stop_key
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ev_loop(display: XDisplay, screen: i32, stop_key: Keycode) {
|
fn ev_loop(display: XDisplay, recordeddpy: XDisplay, screen: i32, stop_key: Keycode) {
|
||||||
let root = display.get_root_window(screen);
|
let root = display.get_root_window(screen);
|
||||||
|
|
||||||
let mut ev_cb_data = EvCallbackData { stop_key, nr_evs: 0, working: true};
|
let ctx = recordeddpy.create_record_context();
|
||||||
display.create_record_context();
|
let ev_cb_data = EvCallbackData {
|
||||||
display.enable_context_async(Some(ev_callback), addr_of!(ev_cb_data) as *mut c_char);
|
xdpy: display,
|
||||||
|
recdpy: recordeddpy,
|
||||||
|
ctx,
|
||||||
|
stop_key,
|
||||||
|
nr_evs: 0,
|
||||||
|
working: true
|
||||||
|
};
|
||||||
|
|
||||||
|
recordeddpy.enable_context_async(ctx, Some(ev_callback), addr_of!(ev_cb_data) as *mut c_char);
|
||||||
while ev_cb_data.working {
|
while ev_cb_data.working {
|
||||||
display.process_replies();
|
recordeddpy.process_replies();
|
||||||
thread::sleep(std::time::Duration::from_millis(100))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display.disable_context(ctx);
|
||||||
|
display.free_context(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct EvCallbackData {
|
pub struct EvCallbackData {
|
||||||
|
pub xdpy: XDisplay,
|
||||||
|
pub recdpy: XDisplay,
|
||||||
pub stop_key: Keycode,
|
pub stop_key: Keycode,
|
||||||
pub nr_evs: u32,
|
pub nr_evs: u32,
|
||||||
pub working: bool,
|
pub working: bool,
|
||||||
|
pub ctx: XRecordContext,
|
||||||
// x: i32,
|
// x: i32,
|
||||||
// y: i32,
|
// y: i32,
|
||||||
}
|
}
|
||||||
|
@ -95,11 +110,34 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
let data = &mut *(closure as *mut EvCallbackData);
|
let data = &mut *(closure as *mut EvCallbackData);
|
||||||
let intercept_data = &mut *intercept_data;
|
let intercept_data = &mut *intercept_data;
|
||||||
|
|
||||||
if intercept_data.category == XRecordStartOfData { println!("Got start of data!"); }
|
if intercept_data.category == XRecordStartOfData {
|
||||||
else if intercept_data.category == XRecordEndOfData { println!("Got end of data!");}
|
println!("Got start of data!");
|
||||||
data.nr_evs += 1;
|
return;
|
||||||
print!("nr: {}", data.nr_evs);
|
} else if intercept_data.category == XRecordEndOfData {
|
||||||
if data.nr_evs >= 10 {
|
println!("Got end of data!");
|
||||||
data.working = false;
|
return;
|
||||||
}
|
}
|
||||||
|
data.nr_evs += 1;
|
||||||
|
println!("nr: {:?}, len: {:?}", data, intercept_data.len);
|
||||||
|
let s: &[i32] = unsafe {
|
||||||
|
slice::from_raw_parts(intercept_data.data as *const i32, 4)
|
||||||
|
};
|
||||||
|
let ev = unsafe { slice::from_raw_parts(intercept_data.data as *const u8, 2) };
|
||||||
|
println!("data: {:?}", s);
|
||||||
|
let x: XKeyPressedEvent;
|
||||||
|
|
||||||
|
if ev[0] == KeyPress {
|
||||||
|
if ev[1] == data.stop_key as i32 {
|
||||||
|
println!("stop key detected!");
|
||||||
|
// if !data.xdpy.disable_context() {
|
||||||
|
// println!("failed to disable context");
|
||||||
|
// }
|
||||||
|
// let res = data.xdpy.disable_context(data.ctx);
|
||||||
|
// println!("disabling context: {:?}", res);
|
||||||
|
data.working = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XRecordFreeData(intercept_data)
|
||||||
}
|
}
|
|
@ -1,17 +1,17 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::{Ref, RefCell};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::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_uchar, c_uint, c_ulong};
|
||||||
use x11::xlib::{Display, GenericEvent, KeyPress, MotionNotify, Time, Window, XAllowEvents, XAnyEvent, XCloseDisplay, XDefaultScreen, XEvent, XFlush, XGrabKeyboard, XKeyEvent, XKeysymToKeycode, XOpenDisplay, XRootWindow, XStringToKeysym, XSync, XUngrabKeyboard, XUngrabPointer, XWindowEvent};
|
use x11::xlib::{Display, GenericEvent, KeyPress, MotionNotify, Time, Window, XAllowEvents, XAnyEvent, XCloseDisplay, XDefaultScreen, XEvent, XFlush, XGrabKeyboard, XKeyEvent, XKeysymToKeycode, XOpenDisplay, XRootWindow, XStringToKeysym, XSync, XUngrabKeyboard, XUngrabPointer, XWindowEvent};
|
||||||
use x11::xrecord::{XRecordAllClients, XRecordAllocRange, XRecordClientInfo, XRecordClientSpec, XRecordContext, XRecordCreateContext, XRecordEnableContextAsync, XRecordInterceptData, XRecordProcessReplies, XRecordQueryVersion};
|
use x11::xrecord::{XRecordAllClients, XRecordAllocRange, XRecordClientInfo, XRecordClientSpec, XRecordContext, XRecordCreateContext, XRecordDisableContext, XRecordEnableContext, XRecordEnableContextAsync, XRecordFreeContext, XRecordInterceptData, XRecordProcessReplies, XRecordQueryVersion};
|
||||||
use x11::xtest::{
|
use x11::xtest::{
|
||||||
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
|
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
|
||||||
XTestQueryExtension,
|
XTestQueryExtension,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct XDisplay {
|
pub struct XDisplay {
|
||||||
ptr: *mut Display,
|
ptr: *mut Display,
|
||||||
xrecordctx: RefCell<Option<XRecordContext>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Keysym = c_ulong;
|
pub type Keysym = c_ulong;
|
||||||
|
@ -30,10 +30,7 @@ impl XDisplay {
|
||||||
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) };
|
||||||
|
|
||||||
Self {
|
Self { ptr: display_ptr }
|
||||||
ptr: display_ptr,
|
|
||||||
xrecordctx: RefCell::new(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self) {
|
pub fn close(self) {
|
||||||
|
@ -162,11 +159,7 @@ impl XDisplay {
|
||||||
xrec_res == 0
|
xrec_res == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_record_context(&self) {
|
pub fn create_record_context(&self) -> XRecordContext {
|
||||||
if self.xrecordctx.borrow().is_some() {
|
|
||||||
panic!("Tried to create xrecord context with one already present");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut protocol_ranges = unsafe { XRecordAllocRange() };
|
let mut protocol_ranges = unsafe { XRecordAllocRange() };
|
||||||
unsafe {
|
unsafe {
|
||||||
(*protocol_ranges).device_events.first = KeyPress as c_uchar;
|
(*protocol_ranges).device_events.first = KeyPress as c_uchar;
|
||||||
|
@ -184,23 +177,41 @@ impl XDisplay {
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
self.xrecordctx.replace(Some(ctx));
|
ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_context(&self,
|
||||||
|
ctx: XRecordContext,
|
||||||
|
cb:Option<unsafe extern "C" fn(_: *mut c_char, _: *mut XRecordInterceptData)>,
|
||||||
|
closure: *mut c_char
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
XRecordEnableContext( self.ptr, ctx, cb, closure as *mut c_char );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_context_async(&self,
|
pub fn enable_context_async(&self,
|
||||||
|
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,
|
||||||
) {
|
) {
|
||||||
unsafe {
|
unsafe {
|
||||||
XRecordEnableContextAsync(
|
XRecordEnableContextAsync( self.ptr, ctx, cb, closure as *mut c_char );
|
||||||
self.ptr,
|
}
|
||||||
self.xrecordctx.borrow_mut().unwrap(),
|
|
||||||
cb,
|
|
||||||
closure as *mut c_char
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn disable_context(&self, ctx: XRecordContext) -> bool {
|
||||||
|
unsafe {
|
||||||
|
XRecordDisableContext( self.ptr, ctx ) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_context(&self, ctx: XRecordContext) -> bool {
|
||||||
|
unsafe {
|
||||||
|
XRecordFreeContext( self.ptr, ctx) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_replies(&self) {
|
pub fn process_replies(&self) {
|
||||||
unsafe { XRecordProcessReplies(self.ptr) };
|
unsafe { XRecordProcessReplies(self.ptr) };
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue