added a safe wrapper for used x11 apis
This commit is contained in:
parent
99d36c93a4
commit
8d47ad6475
3 changed files with 115 additions and 37 deletions
|
@ -10,6 +10,7 @@ use clap::Parser;
|
||||||
use x11::keysym::{XK_d, XK_Super_L};
|
use x11::keysym::{XK_d, XK_Super_L};
|
||||||
use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension};
|
use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl, XTestQueryExtension};
|
||||||
use x11_keysymdef::lookup_by_name;
|
use x11_keysymdef::lookup_by_name;
|
||||||
|
use easymacros::x11_safe_wrapper::XDisplay;
|
||||||
|
|
||||||
/// Macro program inspired by xmacro.
|
/// Macro program inspired by xmacro.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
|
@ -18,57 +19,36 @@ struct Args {
|
||||||
/// Display
|
/// Display
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
display: String,
|
display: String,
|
||||||
|
/// xmacro compatibility
|
||||||
|
#[clap(long)]
|
||||||
|
xmacro: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main () {
|
fn main () {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
let xmacro_mode = args.xmacro;
|
||||||
|
|
||||||
let display = get_remote(args.display);
|
let display = get_remote(None);
|
||||||
|
|
||||||
let super_l_str_ptr = b"Super_L\0".as_ptr();
|
display.send_fake_keypress_from_string(b"Super_L\0");
|
||||||
let super_l_sym = unsafe { XStringToKeysym(super_l_str_ptr as *const i8) };
|
display.send_fake_keypress_from_string(b"d\0");
|
||||||
let super_l_code = unsafe { XKeysymToKeycode(display, super_l_sym) };
|
display.send_fake_keyrelease_from_string(b"d\0");
|
||||||
|
display.send_fake_keyrelease_from_string(b"Super_L\0");
|
||||||
|
|
||||||
let d_str_ptr = b"d\0".as_ptr();
|
display.close();
|
||||||
let d_sym = unsafe { XStringToKeysym(d_str_ptr as *const i8) };
|
|
||||||
let d_code = unsafe { XKeysymToKeycode(display, d_sym) };
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
XTestFakeKeyEvent(display, super_l_code as c_uint, c_int::from(true), 10);
|
|
||||||
XFlush(display);
|
|
||||||
XTestFakeKeyEvent(display, d_code as c_uint, c_int::from(true), 10);
|
|
||||||
XFlush(display);
|
|
||||||
|
|
||||||
XTestFakeKeyEvent(display, d_code as c_uint, c_int::from(false), 10);
|
|
||||||
XFlush(display);
|
|
||||||
XTestFakeKeyEvent(display, super_l_code as c_uint, c_int::from(false), 10);
|
|
||||||
XFlush(display);
|
|
||||||
|
|
||||||
XCloseDisplay(display);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("play: {}", add(5, 10));
|
fn get_remote(display_name: Option<String>) -> XDisplay {
|
||||||
}
|
let display = XDisplay::open(display_name);
|
||||||
|
|
||||||
fn get_remote(dpy_name: String) -> *mut Display {
|
if !display.has_xtest() {
|
||||||
let dpy_name = CString::new(dpy_name).unwrap();
|
|
||||||
let display_ptr: *const u8 = dpy_name.as_bytes().as_ptr();
|
|
||||||
let display = unsafe { XOpenDisplay(display_ptr as *const i8) };
|
|
||||||
|
|
||||||
let mut ev = c_int::default();
|
|
||||||
let mut err = c_int::default();
|
|
||||||
let mut version = (c_int::default(), c_int::default());
|
|
||||||
|
|
||||||
if unsafe { XTestQueryExtension(display, &mut ev, &mut err, &mut version.0, &mut version.1) } == 0 {
|
|
||||||
eprintln!("XTest not supported!");
|
eprintln!("XTest not supported!");
|
||||||
unsafe { XCloseDisplay(display) };
|
display.close();
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
display.grab_control();
|
||||||
XTestGrabControl(display, c_int::from(true));
|
display.sync();
|
||||||
XSync(display, c_int::from(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
display
|
display
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
pub mod x11_safe_wrapper;
|
||||||
|
|
||||||
pub fn add(a: i32, b: i32) -> i32 {
|
pub fn add(a: i32, b: i32) -> i32 {
|
||||||
a + b
|
a + b
|
||||||
}
|
}
|
||||||
|
|
94
src/x11_safe_wrapper.rs
Normal file
94
src/x11_safe_wrapper.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ulong};
|
||||||
|
use x11::xlib::{Display, XCloseDisplay, XFlush, XKeysymToKeycode, XOpenDisplay, XStringToKeysym, XSync};
|
||||||
|
use x11::xtest::{XTestFakeKeyEvent, XTestGrabControl, XTestQueryExtension};
|
||||||
|
|
||||||
|
pub struct XDisplay {
|
||||||
|
ptr: *mut Display,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Keysym = c_ulong;
|
||||||
|
type Keycode = c_uint;
|
||||||
|
|
||||||
|
const FALSE_C: c_int = 0;
|
||||||
|
const TRUE_C: c_int = 1;
|
||||||
|
|
||||||
|
impl XDisplay {
|
||||||
|
pub fn open(display_name: Option<String>) -> Self {
|
||||||
|
let name = CString::new(if let Some(name) = display_name { name } else { env::var("DISPLAY").expect("DISPLAY is not set") }).unwrap();
|
||||||
|
let name_ptr = name.as_bytes().as_ptr();
|
||||||
|
let display_ptr = unsafe { XOpenDisplay(name_ptr as *const i8) };
|
||||||
|
|
||||||
|
Self { ptr: display_ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(self) {
|
||||||
|
unsafe { XCloseDisplay(self.ptr) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sync(&self) {
|
||||||
|
unsafe { XSync(self.ptr, c_int::from(false)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush(&self) {
|
||||||
|
unsafe { XFlush(self.ptr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keysym_to_keycode(&self, keysym: c_ulong) -> Keycode {
|
||||||
|
unsafe { XKeysymToKeycode(self.ptr, keysym) as Keycode }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn string_to_keycode(&self, string: &[u8]) -> Keycode {
|
||||||
|
self.keysym_to_keycode(string_to_keysym(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_xtest(&self) -> bool {
|
||||||
|
let mut vals: (c_int, c_int, c_int, c_int) = (0, 0, 0, 0);
|
||||||
|
let has_extension = unsafe {
|
||||||
|
XTestQueryExtension(
|
||||||
|
self.ptr,
|
||||||
|
&mut vals.0,
|
||||||
|
&mut vals.1,
|
||||||
|
&mut vals.2,
|
||||||
|
&mut vals.3
|
||||||
|
)
|
||||||
|
};
|
||||||
|
has_extension != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fake_keypress_from_string(&self, string: &[u8]) {
|
||||||
|
self.send_fake_keypress_from_keysym(string_to_keysym(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fake_keypress_from_keysym(&self, ks: Keysym) {
|
||||||
|
self.send_fake_keypress_from_code(self.keysym_to_keycode(ks))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fake_keypress_from_code(&self, code: Keycode) {
|
||||||
|
unsafe { XTestFakeKeyEvent(self.ptr, code, TRUE_C, 10) };
|
||||||
|
self.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fake_keyrelease_from_string(&self, string: &[u8]) {
|
||||||
|
self.send_fake_keyrelease_from_keysym(string_to_keysym(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fake_keyrelease_from_keysym(&self, ks: Keysym) {
|
||||||
|
self.send_fake_keyrelease_from_code(self.keysym_to_keycode(ks))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fake_keyrelease_from_code(&self, code: Keycode) {
|
||||||
|
unsafe { XTestFakeKeyEvent(self.ptr, code, FALSE_C, 10) };
|
||||||
|
self.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grab_control(&self) {
|
||||||
|
unsafe { XTestGrabControl(self.ptr, TRUE_C); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for XStringToKeysym. Remember to give a null terminated string!
|
||||||
|
pub fn string_to_keysym(string: &[u8]) -> Keysym {
|
||||||
|
unsafe { XStringToKeysym(string.as_ptr() as *const c_char) }
|
||||||
|
}
|
Loading…
Reference in a new issue