painful segfault apparently! :,)
This commit is contained in:
parent
8232c4f6a9
commit
8a20bb2d25
2 changed files with 79 additions and 36 deletions
|
@ -1,12 +1,15 @@
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
use std::os::raw::{c_char, c_uchar, 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, slice_from_raw_parts};
|
use std::ptr::{addr_of, slice_from_raw_parts};
|
||||||
use std::{slice, thread};
|
use std::{slice, thread};
|
||||||
|
use std::ffi::c_void;
|
||||||
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, XFree, XKeyEvent, XKeyPressedEvent, XPointer};
|
use x11::xlib::{ButtonPress, ButtonRelease, CurrentTime, GrabModeAsync, GrabModeSync, GrabSuccess, KeyCode, KeyPress, KeyPressMask, KeyRelease, MotionNotify, SyncPointer, XEvent, XFree, XKeyEvent, XKeyPressedEvent, XPointer};
|
||||||
use x11::xrecord::{XRecordContext, XRecordCreateContext, XRecordDisableContext, XRecordEndOfData, XRecordFreeData, XRecordInterceptData, XRecordStartOfData};
|
use x11::xrecord::{XRecordAllocRange, 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.
|
||||||
|
@ -70,8 +73,9 @@ fn get_stop_key(display: XDisplay) -> Keycode {
|
||||||
|
|
||||||
fn ev_loop(display: XDisplay, recordeddpy: 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 protocol_ranges = unsafe { XRecordAllocRange() };
|
||||||
|
|
||||||
let ctx = recordeddpy.create_record_context();
|
let ctx = recordeddpy.create_record_context(protocol_ranges);
|
||||||
let ev_cb_data = EvCallbackData {
|
let ev_cb_data = EvCallbackData {
|
||||||
xdpy: display,
|
xdpy: display,
|
||||||
recdpy: recordeddpy,
|
recdpy: recordeddpy,
|
||||||
|
@ -81,13 +85,16 @@ fn ev_loop(display: XDisplay, recordeddpy: XDisplay, screen: i32, stop_key: Keyc
|
||||||
working: true
|
working: true
|
||||||
};
|
};
|
||||||
|
|
||||||
recordeddpy.enable_context_async(ctx, Some(ev_callback), addr_of!(ev_cb_data) as *mut c_char);
|
if !recordeddpy.enable_context_async(ctx, Some(ev_callback), addr_of!(ev_cb_data) as *mut c_char) {
|
||||||
|
panic!("Failed to enable record context")
|
||||||
|
}
|
||||||
while ev_cb_data.working {
|
while ev_cb_data.working {
|
||||||
recordeddpy.process_replies();
|
recordeddpy.process_replies();
|
||||||
}
|
}
|
||||||
|
|
||||||
display.disable_context(ctx);
|
display.disable_context(ctx);
|
||||||
display.free_context(ctx);
|
display.free_context(ctx);
|
||||||
|
unsafe { XFree(protocol_ranges as *mut c_void) };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -105,10 +112,12 @@ pub struct EvCallbackData {
|
||||||
|
|
||||||
|
|
||||||
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) {
|
||||||
println!("Got event!!!");
|
dbg!(intercept_data);
|
||||||
|
dbg!(closure);
|
||||||
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;
|
||||||
|
dbg!(&intercept_data);
|
||||||
|
dbg!(&data);
|
||||||
|
|
||||||
if intercept_data.category == XRecordStartOfData {
|
if intercept_data.category == XRecordStartOfData {
|
||||||
println!("Got start of data!");
|
println!("Got start of data!");
|
||||||
|
@ -118,26 +127,41 @@ unsafe extern "C" fn ev_callback(closure: *mut c_char, intercept_data: *mut XRec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.nr_evs += 1;
|
data.nr_evs += 1;
|
||||||
println!("nr: {:?}, len: {:?}", data, intercept_data.len);
|
// println!("nr: {:?}, len: {:?}", data, intercept_data.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 {
|
dbg!(intercept_data.data);
|
||||||
if ev[1] == data.stop_key as i32 {
|
let ev_type = *(intercept_data.data as *const u8);
|
||||||
println!("stop key detected!");
|
match ev_type {
|
||||||
// if !data.xdpy.disable_context() {
|
KEYPRESS_U8 => {
|
||||||
// println!("failed to disable context");
|
let kc = *((intercept_data.data as usize + 1) as *const u8);
|
||||||
// }
|
let stop = kc == data.stop_key as u8;
|
||||||
// let res = data.xdpy.disable_context(data.ctx);
|
if stop {
|
||||||
// println!("disabling context: {:?}", res);
|
println!("stop key detected!");
|
||||||
data.working = false;
|
data.working = false;
|
||||||
return;
|
XRecordFreeData(intercept_data)
|
||||||
|
} else {
|
||||||
|
// let keyname = data.xdpy.keycode_to_string(kc as u32);
|
||||||
|
let keyname = data.xdpy.keycode_to_string(44);
|
||||||
|
let rstring = format!("KeyPress {}", &keyname.to_str().unwrap());
|
||||||
|
// let rstring = format!("KeyPress {}", kc);
|
||||||
|
// dbg!(kc);
|
||||||
|
dbg!(&rstring);
|
||||||
|
std::mem::forget(keyname);
|
||||||
|
// XRecordFreeData(intercept_data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
KEYRELEASE_U8 => {}
|
||||||
|
BUTTONPRESS_U8 => {}
|
||||||
|
BUTTONRELEASE_U8 => {}
|
||||||
|
MOTIONNOTIFY_U8 => {}
|
||||||
|
_ => eprintln!("Unknown event type: {:?}", ev_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
XRecordFreeData(intercept_data)
|
}
|
||||||
}
|
|
||||||
|
const KEYPRESS_U8: u8 = KeyPress as u8;
|
||||||
|
const KEYRELEASE_U8: u8 = KeyRelease as u8;
|
||||||
|
const BUTTONPRESS_U8: u8 = ButtonPress as u8;
|
||||||
|
const BUTTONRELEASE_U8: u8 = ButtonRelease as u8;
|
||||||
|
const MOTIONNOTIFY_U8: u8 = MotionNotify as u8;
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ 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, KeyCode, KeyPress, MotionNotify, Status, Time, Window, XAllowEvents, XAnyEvent, XCloseDisplay, XDefaultScreen, XEvent, XFlush, XGrabKeyboard, XKeycodeToKeysym, XKeyEvent, XKeysymToKeycode, XKeysymToString, XOpenDisplay, XRootWindow, XStringToKeysym, XSync, XUngrabKeyboard, XUngrabPointer, XWindowEvent};
|
||||||
use x11::xrecord::{XRecordAllClients, XRecordAllocRange, XRecordClientInfo, XRecordClientSpec, XRecordContext, XRecordCreateContext, XRecordDisableContext, XRecordEnableContext, XRecordEnableContextAsync, XRecordFreeContext, XRecordInterceptData, XRecordProcessReplies, XRecordQueryVersion};
|
use x11::xrecord::{XRecordAllClients, XRecordAllocRange, XRecordClientInfo, 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,
|
||||||
|
@ -57,7 +57,7 @@ impl XDisplay {
|
||||||
unsafe { XRootWindow(self.ptr, screen_nr) }
|
unsafe { XRootWindow(self.ptr, screen_nr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keysym_to_keycode(&self, keysym: c_ulong) -> Keycode {
|
pub fn keysym_to_keycode(&self, keysym: Keysym) -> Keycode {
|
||||||
unsafe { XKeysymToKeycode(self.ptr, keysym) as Keycode }
|
unsafe { XKeysymToKeycode(self.ptr, keysym) as Keycode }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,16 @@ impl XDisplay {
|
||||||
self.keysym_to_keycode(string_to_keysym(string))
|
self.keysym_to_keycode(string_to_keysym(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn keycode_to_keysym(&self, keycode: Keycode) -> Keysym {
|
||||||
|
unsafe {
|
||||||
|
XKeycodeToKeysym(self.ptr, keycode as c_uchar, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keycode_to_string(&self, keycode: Keycode) -> CString {
|
||||||
|
keysym_to_string(self.keycode_to_keysym(keycode))
|
||||||
|
}
|
||||||
|
|
||||||
// XTest stuff
|
// XTest stuff
|
||||||
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);
|
||||||
|
@ -159,8 +169,7 @@ impl XDisplay {
|
||||||
xrec_res == 0
|
xrec_res == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_record_context(&self) -> XRecordContext {
|
pub fn create_record_context(&self, mut protocol_ranges: *mut XRecordRange) -> XRecordContext {
|
||||||
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;
|
||||||
(*protocol_ranges).device_events.last = MotionNotify as c_uchar;
|
(*protocol_ranges).device_events.last = MotionNotify as c_uchar;
|
||||||
|
@ -184,19 +193,19 @@ impl XDisplay {
|
||||||
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 {
|
||||||
unsafe {
|
unsafe {
|
||||||
XRecordEnableContext( self.ptr, ctx, cb, closure as *mut c_char );
|
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 {
|
||||||
unsafe {
|
unsafe {
|
||||||
XRecordEnableContextAsync( self.ptr, ctx, cb, closure as *mut c_char );
|
XRecordEnableContextAsync( self.ptr, ctx, cb, closure as *mut c_char ) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,3 +230,13 @@ 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 {
|
||||||
|
unsafe {
|
||||||
|
let raw = XKeysymToString(keysym);
|
||||||
|
dbg!(raw);
|
||||||
|
let r = CString::from_raw(raw);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
// .into_string()
|
||||||
|
// .expect("failed to convert CString into Rust String")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue