You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
5.3 KiB
Rust

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<Bind, Subscription> = 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,
}
}
}