what
This commit is contained in:
parent
374e96d231
commit
c8a4f387ae
9 changed files with 104 additions and 173 deletions
15
.gitignore
vendored
15
.gitignore
vendored
|
@ -13,3 +13,18 @@ Cargo.lock
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
#
|
||||||
|
# already existing elements were commented out
|
||||||
|
|
||||||
|
#/target
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
#
|
||||||
|
# already existing elements were commented out
|
||||||
|
|
||||||
|
#/target
|
||||||
|
/Cargo.lock
|
||||||
|
|
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "easymacros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
x11 = { version = "2.19.1", features = ["xlib", "xtest"] }
|
||||||
|
x11-keysymdef = "0.2.0"
|
||||||
|
clap = { version = "3.1.18", features = ["derive"] }
|
|
@ -1,2 +1,3 @@
|
||||||
# easymacros
|
# easymacros
|
||||||
A thing to make macros easily. Inspired by how vim macros work.
|
|
||||||
|
This program is inspired by xmacro, however it isn't xmacro. This project is not using X directly, but evde
|
||||||
|
|
59
src/bin/easymacroplay.rs
Normal file
59
src/bin/easymacroplay.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::os::raw::c_int;
|
||||||
|
use x11::xlib::{XCloseDisplay, XFlush, XOpenDisplay};
|
||||||
|
use easymacros::add;
|
||||||
|
use clap::Parser;
|
||||||
|
use x11::keysym::{XK_d, XK_Super_L};
|
||||||
|
use x11::xtest::{XTestFakeButtonEvent, XTestFakeKeyEvent, XTestFakeMotionEvent, XTestGrabControl};
|
||||||
|
use x11_keysymdef::lookup_by_name;
|
||||||
|
|
||||||
|
/// Macro program inspired by xmacro.
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
struct Args {
|
||||||
|
/// Display
|
||||||
|
#[clap(short, long)]
|
||||||
|
display: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main () {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
// let display_ptr = args.display.as_bytes().as_ptr() as *const i8;
|
||||||
|
println!("Display name: {}", args.display);
|
||||||
|
let display_name = CString::new(args.display).unwrap();
|
||||||
|
println!("Display name cstr: {:?}", display_name);
|
||||||
|
let display_ptr: *const u8 = display_name.as_bytes().as_ptr();
|
||||||
|
println!("Display name ptr: {:?}", display_ptr);
|
||||||
|
let display = unsafe { XOpenDisplay(display_ptr as *const i8) };
|
||||||
|
println!("Display name ptr: {:?}", display);
|
||||||
|
|
||||||
|
let super_l = lookup_by_name("Super_L").unwrap();
|
||||||
|
let d = lookup_by_name("d").unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// XTestFakeKeyEvent(display, super_l.keysym, 1, 0);
|
||||||
|
// XTestFakeKeyEvent(display, d.keysym, 1, 10);
|
||||||
|
//
|
||||||
|
// XTestFakeKeyEvent(display, d.keysym, 0, 20);
|
||||||
|
// XTestFakeKeyEvent(display, super_l.keysym, 0, 30);
|
||||||
|
XTestGrabControl(display, c_int::from(false));
|
||||||
|
XTestFakeKeyEvent(display, XK_Super_L, c_int::from(true), 0);
|
||||||
|
XFlush(display);
|
||||||
|
XTestFakeKeyEvent(display, XK_d, c_int::from(true), 0);
|
||||||
|
XFlush(display);
|
||||||
|
XTestFakeKeyEvent(display, XK_d, c_int::from(false), 0);
|
||||||
|
XFlush(display);
|
||||||
|
XTestFakeKeyEvent(display, XK_Super_L, c_int::from(false), 0);
|
||||||
|
XFlush(display);
|
||||||
|
|
||||||
|
XTestFakeMotionEvent(display, -1, 200, 200, 0);
|
||||||
|
XFlush(display);
|
||||||
|
|
||||||
|
XCloseDisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
println!("play: {}", add(5, 10));
|
||||||
|
}
|
||||||
|
|
5
src/bin/easymacrorec.rs
Normal file
5
src/bin/easymacrorec.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use easymacros::add;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("rec: {}", add(2, 2));
|
||||||
|
}
|
12
src/lib.rs
Normal file
12
src/lib.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
pub fn add(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let result = 2 + 2;
|
||||||
|
assert_eq!(result, 4);
|
||||||
|
}
|
||||||
|
}
|
78
src/main.rs
78
src/main.rs
|
@ -1,78 +0,0 @@
|
||||||
use std::sync::{Arc, mpsc, Mutex};
|
|
||||||
use std::sync::mpsc::Receiver;
|
|
||||||
use std::thread;
|
|
||||||
use evdev::{Device, enumerate, InputEvent};
|
|
||||||
use crate::modifiers::ModifierStates;
|
|
||||||
use crate::virt_kb::VirtKb;
|
|
||||||
|
|
||||||
mod modifiers;
|
|
||||||
mod virt_kb;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let devices = enumerate();
|
|
||||||
let kb_name = "py-evdev-uinput";
|
|
||||||
|
|
||||||
let mut kbs = {
|
|
||||||
let mut r = Vec::new();
|
|
||||||
|
|
||||||
for dev in devices {
|
|
||||||
if let Some(keyboard) = dev.name() {
|
|
||||||
if keyboard == kb_name {
|
|
||||||
r.push(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let virt_kb = VirtKb::new(&kbs);
|
|
||||||
let mod_states = ModifierStates::new();
|
|
||||||
|
|
||||||
let reader = KeyReader::new(kbs);
|
|
||||||
let event_receiver = reader.init();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct KeyReader {
|
|
||||||
keyboards: Arc<Mutex<Vec<Device>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyReader {
|
|
||||||
pub fn new(kbs: Vec<Device>) -> Self {
|
|
||||||
let mut kbs = kbs;
|
|
||||||
|
|
||||||
for kb in kbs.iter_mut() {
|
|
||||||
match kb.grab() {
|
|
||||||
Ok(_) => println!("Keyboard {} grabbed!", kb.name().get_or_insert("[Unnamed]")),
|
|
||||||
Err(_) => println!("Failed to grab keyboard {}.", kb.name().get_or_insert("[Unnamed]")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self { keyboards: Arc::new(Mutex::new(kbs)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(&self) -> Receiver<Vec<InputEvent>>{
|
|
||||||
let (tx, rx) = mpsc::channel();
|
|
||||||
|
|
||||||
let keyboards = self.keyboards.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut kbs_locked = keyboards.lock().unwrap();
|
|
||||||
loop {
|
|
||||||
for kb in kbs_locked.iter_mut() {
|
|
||||||
let mut events = kb
|
|
||||||
.fetch_events()
|
|
||||||
.unwrap()
|
|
||||||
.collect::<Vec<InputEvent>>();
|
|
||||||
|
|
||||||
tx.send(events)
|
|
||||||
.expect("Couldn't send keyboard events from reader to main thread.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rx
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
use evdev::{InputEvent, Key};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ModifierStates {
|
|
||||||
ctrl: bool,
|
|
||||||
alt: bool,
|
|
||||||
shift: bool,
|
|
||||||
meta: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModifierStates {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
ModifierStates {
|
|
||||||
ctrl: false,
|
|
||||||
alt: false,
|
|
||||||
shift: false,
|
|
||||||
meta: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn update(&mut self, event: InputEvent) {
|
|
||||||
let code = event.code();
|
|
||||||
let val = event.value();
|
|
||||||
|
|
||||||
self.update_ctrl(code, val);
|
|
||||||
self.update_alt(code, val);
|
|
||||||
self.update_shift(code, val);
|
|
||||||
self.update_meta(code, val);
|
|
||||||
}
|
|
||||||
pub fn mod_pressed(&self) -> bool {
|
|
||||||
self.ctrl || self.alt || self.shift || self.meta
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_ctrl(&mut self, code: u16, val: i32) {
|
|
||||||
if code == Key::KEY_LEFTCTRL.code() || code == Key::KEY_RIGHTCTRL.code() {
|
|
||||||
self.ctrl = val != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_alt(&mut self, code: u16, val: i32) {
|
|
||||||
if code == Key::KEY_LEFTALT.code() || code == Key::KEY_RIGHTALT.code() {
|
|
||||||
self.ctrl = val != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_shift(&mut self, code: u16, val: i32) {
|
|
||||||
if code == Key::KEY_LEFTSHIFT.code() || code == Key::KEY_RIGHTSHIFT.code() {
|
|
||||||
self.ctrl = val != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_meta(&mut self, code: u16, val: i32) {
|
|
||||||
if code == Key::KEY_LEFTMETA.code() || code == Key::KEY_RIGHTMETA.code() {
|
|
||||||
self.ctrl = val != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
use std::sync::mpsc;
|
|
||||||
use std::sync::mpsc::{Sender, SendError};
|
|
||||||
use std::thread;
|
|
||||||
use evdev::{Device, InputEvent};
|
|
||||||
use evdev::uinput::VirtualDeviceBuilder;
|
|
||||||
|
|
||||||
pub struct VirtKb {
|
|
||||||
tx: Sender<Vec<InputEvent>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VirtKb {
|
|
||||||
pub fn new(physical_kbs: &Vec<Device>) -> Self {
|
|
||||||
let (tx, rx) = mpsc::channel::<Vec<InputEvent>>();
|
|
||||||
|
|
||||||
let mut virt_kb_builder = VirtualDeviceBuilder::new()
|
|
||||||
.expect("Failed to create UInput device")
|
|
||||||
.name("EasyMacros");
|
|
||||||
|
|
||||||
for phys_kb in physical_kbs {
|
|
||||||
virt_kb_builder = virt_kb_builder.with_keys(phys_kb.supported_keys().unwrap()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut virt_kb = virt_kb_builder.build().expect("Failed to build virt_kb");
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
for received in rx {
|
|
||||||
virt_kb.emit(&received).expect("Virtual keyboard failed to send events");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self { tx }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_events(&self, events: Vec<InputEvent>) -> Result<(), SendError<Vec<InputEvent>>> {
|
|
||||||
self.tx.send(events)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue