idk
This commit is contained in:
parent
29b50eb7b5
commit
d0a060a6b8
|
@ -7,4 +7,5 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nix = "0.19.1"
|
||||
x11 = {version = "2.18.2", features = ["xlib"] }
|
112
src/main.rs
112
src/main.rs
|
@ -3,15 +3,23 @@ use x11::xlib;
|
|||
use std::ptr::{null, null_mut};
|
||||
use std::sync::Arc;
|
||||
use std::ffi::CString;
|
||||
use std::io::{Result /*, Error, ErrorKind */};
|
||||
use std::io::{Result, Error, ErrorKind};
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
use x11::xlib::{ButtonPressMask, ButtonReleaseMask, PointerMotionMask,
|
||||
GrabModeAsync, XEvent};
|
||||
|
||||
use x11::xlib::{LockMask, ShiftMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask};
|
||||
|
||||
use nix::unistd::{fork, ForkResult, close, setsid, execvp};
|
||||
|
||||
|
||||
type Display = Arc<AtomicPtr<xlib::Display>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct XlibState {
|
||||
display: Display,
|
||||
//buttons: Vec<(u32, u32, Box<dyn FnMut(&mut Self)>)>,
|
||||
keys: Vec<(i32, u32, Box<dyn Fn(&Self, &XEvent)>)>,
|
||||
}
|
||||
|
||||
impl XlibState {
|
||||
|
@ -23,6 +31,7 @@ impl XlibState {
|
|||
|
||||
Ok(Self {
|
||||
display,
|
||||
keys: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -34,6 +43,53 @@ impl XlibState {
|
|||
unsafe { xlib::XDefaultRootWindow(self.dpy()) }
|
||||
}
|
||||
|
||||
fn add_key<S: Into<String>>(mut self, key: S, mask: u32, handler: Box<dyn Fn(&Self, &XEvent)>)
|
||||
-> Self {
|
||||
let keycode = self.keycode(key);
|
||||
self.keys.push((keycode, mask, Box::new(handler)));
|
||||
|
||||
unsafe {
|
||||
xlib::XGrabKey(self.dpy(),
|
||||
keycode,
|
||||
mask,
|
||||
self.root(),
|
||||
1 /* true */,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
// spawn a new process / calls execvp
|
||||
pub fn spawn<T: ToString>(&self, command: T, args: &[T]) -> Result<()> {
|
||||
let fd = unsafe {xlib::XConnectionNumber(self.dpy())};
|
||||
|
||||
match unsafe { fork() } {
|
||||
Ok(ForkResult::Parent{..}) => {Ok(())},
|
||||
Ok(ForkResult::Child) => {
|
||||
// i dont think i want to exit this block without closing the program,
|
||||
// so unwrap everything
|
||||
|
||||
close(fd).or_else(|_| Err("failed to close x connection")).unwrap();
|
||||
setsid().ok().ok_or("failed to setsid").unwrap();
|
||||
|
||||
let c_cmd = CString::new(command.to_string()).unwrap();
|
||||
|
||||
let c_args: Vec<_> = args.iter()
|
||||
.map(|s| CString::new(s.to_string()).unwrap())
|
||||
.collect();
|
||||
|
||||
execvp(&c_cmd, &c_args.iter().map(|s| s.as_c_str()).collect::<Vec<_>>())
|
||||
.or(Err("failed to execvp()")).unwrap();
|
||||
|
||||
eprintln!("execvp({}) failed.", c_cmd.to_str().unwrap());
|
||||
std::process::exit(0);
|
||||
},
|
||||
Err(_) => {Err(Error::new(ErrorKind::Other, "failed to fork."))},
|
||||
}
|
||||
}
|
||||
|
||||
fn keycode<S: Into<String>>(&self, string: S) -> i32 {
|
||||
let c_string = CString::new(string.into()).unwrap();
|
||||
unsafe {
|
||||
|
@ -41,15 +97,50 @@ impl XlibState {
|
|||
xlib::XKeysymToKeycode(self.dpy(), keysym) as i32
|
||||
}
|
||||
}
|
||||
|
||||
fn numlock_mask(&self) -> u32 {
|
||||
unsafe {
|
||||
let modmap = xlib::XGetModifierMapping(self.dpy());
|
||||
let max_keypermod = (*modmap).max_keypermod;
|
||||
|
||||
for i in 0..8 {
|
||||
for j in 0..max_keypermod {
|
||||
if *(*modmap).modifiermap.offset((i * max_keypermod + j) as isize) ==
|
||||
xlib::XKeysymToKeycode(self.dpy(), x11::keysym::XK_Num_Lock as u64) {
|
||||
return 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn clean_mask(&self) -> u32 {
|
||||
!(self.numlock_mask() | LockMask)
|
||||
//& (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
|
||||
}
|
||||
}
|
||||
|
||||
use x11::xlib::{ButtonPressMask, ButtonReleaseMask, PointerMotionMask, GrabModeAsync, Mod1Mask};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
println!("Hello, world!");
|
||||
|
||||
let state = XlibState::new()?;
|
||||
|
||||
let state =
|
||||
state.add_key("T", Mod1Mask, Box::new(|state, _| {
|
||||
let _ = state.spawn("xterm", &[]);
|
||||
}))
|
||||
.add_key("F1", Mod1Mask, Box::new(|state, event| {
|
||||
unsafe {
|
||||
if event.key.subwindow != 0 {
|
||||
xlib::XRaiseWindow(state.dpy(), event.key.subwindow);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
unsafe {
|
||||
xlib::XGrabKey(state.dpy(),
|
||||
state.keycode("F1"),
|
||||
|
@ -86,8 +177,19 @@ fn main() -> Result<()> {
|
|||
let mut event: xlib::XEvent = std::mem::MaybeUninit::uninit().assume_init();
|
||||
xlib::XNextEvent(state.dpy(), &mut event);
|
||||
|
||||
if event.get_type() == xlib::KeyPress && event.key.subwindow != 0 {
|
||||
xlib::XRaiseWindow(state.dpy(), event.key.subwindow);
|
||||
// run keypress handlers
|
||||
if event.get_type() == xlib::KeyPress {
|
||||
|
||||
// cache clean mask, that way numlock_mask doesnt get called for every cmp
|
||||
let clean_mask = state.clean_mask();
|
||||
|
||||
for (key, mask, handler) in state.keys.iter() {
|
||||
// check if key and mask with any numlock state fit
|
||||
if event.key.keycode == *key as u32 &&
|
||||
event.key.state & clean_mask == *mask & clean_mask {
|
||||
handler(&state, &event);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if event.get_type() == xlib::ButtonPress && event.button.subwindow != 0 {
|
||||
xlib::XGetWindowAttributes(state.dpy(), event.button.subwindow, &mut attr);
|
||||
|
|
Loading…
Reference in a new issue