holy shitttt do NOT run this version it WILL break your desktop PLEASE DO NOT RUN

This commit is contained in:
Schrottkatze 2022-06-28 00:56:20 +02:00
parent 0b1cbcea0e
commit 39916cd6db
4 changed files with 223 additions and 139 deletions

0
.envrc Normal file
View file

13
shell.nix Normal file
View file

@ -0,0 +1,13 @@
with import <nixpkgs> {};
pkgs.mkShell {
buildInputs = with pkgs; [
cargo
rustc
rust-analyzer
rustfmt
pkg-config
xorg.libX11
xorg.libXtst
];
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
}

View file

@ -1,10 +1,12 @@
use std::os::raw::{c_char, c_uint}; use std::os::raw::{c_char, c_uint};
use std::process::{exit, ExitCode}; use std::process::{exit, ExitCode};
use std::ptr::addr_of;
use std::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, XPointer};
use x11::xrecord::{XRecordEndOfData, XRecordInterceptData, XRecordStartOfData}; use x11::xrecord::{XRecordCreateContext, XRecordEndOfData, 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,12 +25,15 @@ fn main() {
let display = XDisplay::open(args.display); let display = XDisplay::open(args.display);
let stop_key = get_stop_key(display); let stop_key = get_stop_key(&display);
let screen = display.get_default_screen();
dbg!(stop_key); dbg!(stop_key);
ev_loop(display, screen, stop_key);
} }
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);
@ -63,20 +68,38 @@ fn get_stop_key(display: XDisplay) -> Keycode {
fn ev_loop(display: XDisplay, screen: i32, stop_key: Keycode) { fn ev_loop(display: 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};
display.create_record_context();
display.enable_context_async(Some(ev_callback), addr_of!(ev_cb_data) as *mut c_char);
while ev_cb_data.working {
display.process_replies();
thread::sleep(std::time::Duration::from_millis(100))
}
} }
struct EvCallbackData { #[repr(C)]
stop_key: Keycode, pub struct EvCallbackData {
x: i32, pub stop_key: Keycode,
y: i32, pub nr_evs: u32,
pub working: bool,
// x: i32,
// y: i32,
} }
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!!!");
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 { println!("Got start of data!"); }
else if intercept_data.category == XRecordEndOfData { println!("Got end of data!");} else if intercept_data.category == XRecordEndOfData { println!("Got end of data!");}
data.nr_evs += 1;
print!("nr: {}", data.nr_evs);
if data.nr_evs >= 10 {
data.working = false;
}
} }

View file

@ -1,8 +1,9 @@
use std::cell::RefCell;
use std::env; use std::env;
use std::ffi::CString; use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_uint, c_ulong}; use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ulong};
use x11::xlib::{Display, GenericEvent, 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::XRecordQueryVersion; use x11::xrecord::{XRecordAllClients, XRecordAllocRange, XRecordClientInfo, XRecordClientSpec, XRecordContext, XRecordCreateContext, XRecordEnableContextAsync, XRecordInterceptData, XRecordProcessReplies, XRecordQueryVersion};
use x11::xtest::{ use x11::xtest::{
XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl,
XTestQueryExtension, XTestQueryExtension,
@ -10,6 +11,7 @@ use x11::xtest::{
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;
@ -24,12 +26,14 @@ 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) };
Self { ptr: display_ptr } Self {
ptr: display_ptr,
xrecordctx: RefCell::new(None),
}
} }
pub fn close(self) { pub fn close(self) {
@ -123,14 +127,16 @@ impl XDisplay {
} }
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 { XGrabKeyboard( unsafe {
XGrabKeyboard(
self.ptr, self.ptr,
window, window,
c_int::from(owner_events), c_int::from(owner_events),
pointer_mode, pointer_mode,
keyboard_mode, keyboard_mode,
time time,
)} )
}
} }
pub fn ungrab_keyboard(&self, time: Time) { pub fn ungrab_keyboard(&self, time: Time) {
@ -156,6 +162,48 @@ impl XDisplay {
xrec_res == 0 xrec_res == 0
} }
pub fn create_record_context(&self) {
if self.xrecordctx.borrow().is_some() {
panic!("Tried to create xrecord context with one already present");
}
let mut protocol_ranges = unsafe { XRecordAllocRange() };
unsafe {
(*protocol_ranges).device_events.first = KeyPress as c_uchar;
(*protocol_ranges).device_events.last = MotionNotify as c_uchar;
}
let mut clients: XRecordClientSpec = XRecordAllClients;
let ctx: XRecordContext = unsafe {
XRecordCreateContext(
self.ptr,
0,
&mut clients,
1,
&mut protocol_ranges,
1
)
};
self.xrecordctx.replace(Some(ctx));
}
pub fn enable_context_async(&self,
cb: Option<unsafe extern "C" fn(_: *mut c_char, _: *mut XRecordInterceptData)>,
closure: *mut c_char,
) {
unsafe {
XRecordEnableContextAsync(
self.ptr,
self.xrecordctx.borrow_mut().unwrap(),
cb,
closure as *mut c_char
)
};
}
pub fn process_replies(&self) {
unsafe { XRecordProcessReplies(self.ptr) };
}
} }
/// Wrapper for XStringToKeysym. Remember to give a null terminated string! /// Wrapper for XStringToKeysym. Remember to give a null terminated string!