mod types; mod config; mod maps; mod lua_config; extern crate x11; use x11::xlib; use x11::xtest; use std::mem; use std::ffi::{CStr, CString}; use std::ptr::null; use x11::xlib::{AnyModifier, ButtonPress, ButtonRelease, ButtonReleaseMask, ButtonPressMask, GrabModeAsync, RevertToNone, BadCursor, XEvent, xError, XAnyEvent, xEvent, Display, XKeyEvent, InputFocus, KeyPress, KeyRelease, KeyPressMask, KeyReleaseMask, XButtonEvent, CurrentTime, Button1Mask, Button2Mask, Window}; use std::io::Cursor; use x11::xinput2::XINotifyDetailNone; use crate::types::{Bind, Action, Handler}; use std::os::raw::c_long; use std::collections::HashMap; use crate::types::Bind::{Key, Mouse}; struct XInfo { root: u64, display: *mut Display, } struct Subscription { on: Bind, handler: Handler, } impl Subscription { pub fn subscribe(&self, xinfo: &XInfo) { unsafe { match self.on { Bind::Key(key) => { xlib::XGrabKey(xinfo.display, key as i32, AnyModifier, xinfo.root, 0, GrabModeAsync, GrabModeAsync); } Bind::Mouse(button) => { xlib::XGrabButton(xinfo.display, button, AnyModifier, xinfo.root, 0, (ButtonReleaseMask | ButtonPressMask) as u32, GrabModeAsync, GrabModeAsync, xinfo.root, 0); } _ => {} } } } pub fn unsubscribe(&self, xinfo: &XInfo) { unsafe { match self.on { Bind::Key(key) => { xlib::XUngrabKey(xinfo.display, key as i32, AnyModifier, xinfo.root); } Bind::Mouse(button) => { xlib::XUngrabButton(xinfo.display, button, AnyModifier, xinfo.root); } _ => {} } } } pub fn handle(&self, pressed: bool, xinfo: &XInfo, coords: Target) { println!("Handling trigger={:?} pressed={:?} action={:?}", self.on, pressed, self.handler.action); match &self.handler.action { Action::Sync(bind) => { match bind { Bind::Key(key) => { unsafe { xtest::XTestFakeKeyEvent(xinfo.display, *key, pressed as i32, CurrentTime); } } Bind::Mouse(key) => { unsafe { xtest::XTestFakeButtonEvent(xinfo.display, *key, pressed as i32, CurrentTime); } } _ => {} } } _ => {} } } } fn main() { let config = lua_config::load_config("\ # sync up keys with others # tables defined in maps.rs # manual key codes can be given via k.n() or m.n() sync(k.n(52), m.left)\ \ ").unwrap(); let display = unsafe { xlib::XOpenDisplay(null()) }; let root = unsafe { xlib::XDefaultRootWindow(display) }; unsafe { xtest::XTestGrabControl(display, true as i32) }; let xinfo = XInfo { display, root }; let mut subs: HashMap = HashMap::new(); for (bind, handler) in config.binds.iter() { let sub = Subscription { handler: (*handler).clone(), on: (*bind).clone() }; sub.subscribe(&xinfo); subs.insert((*bind).clone(), sub); } let mut event: xlib::XEvent = unsafe { mem::MaybeUninit::uninit().assume_init() }; loop { unsafe { xlib::XNextEvent(display, &mut event); } match event.get_type() { xlib::KeyPress => { let key = Key(unsafe { event.key.keycode }); if let Some(sub) = subs.get(&key) { sub.handle(true, &xinfo, unsafe { event.key.to_coords() }); } } xlib::KeyRelease => { let key = Key(unsafe { event.key.keycode }); if let Some(sub) = subs.get(&key) { sub.handle(false, &xinfo, unsafe { event.key.to_coords() }); } } xlib::ButtonPress => { let key = Mouse(unsafe { event.button.button }); if let Some(sub) = subs.get(&key) { sub.handle(true, &xinfo, unsafe { event.button.to_coords() }); } } xlib::ButtonRelease => { let key = Mouse(unsafe { event.button.button }); if let Some(sub) = subs.get(&key) { sub.handle(false, &xinfo, unsafe { event.button.to_coords() }); } } _ => {} } } } struct Target { x: i32, y: i32, x_root: i32, y_root: i32, window: Window, subwindow: Window, } trait ToCoords { fn to_coords(&self) -> Target; } impl ToCoords for XKeyEvent { fn to_coords(&self) -> Target { Target { x: self.x, y: self.y, x_root: self.x_root, y_root: self.y_root, window: self.window, subwindow: self.subwindow, } } } impl ToCoords for XButtonEvent { fn to_coords(&self) -> Target { Target { x: self.x, y: self.y, x_root: self.x_root, y_root: self.y_root, window: self.window, subwindow: self.subwindow, } } }