Add engine and connecting between layers

This commit is contained in:
Federico Terzi 2019-08-31 16:07:45 +02:00
parent c0cd826b45
commit 0c860c0b5f
8 changed files with 117 additions and 22 deletions

View File

@ -199,5 +199,30 @@ void send_string(const wchar_t * string) {
vec.push_back(input); vec.push_back(input);
} }
SendInput(vec.size(), vec.data(), sizeof(INPUT));
}
/*
* Send the backspace keypress, *count* times.
*/
void delete_string(int32_t count) {
std::vector<INPUT> vec;
for (int i = 0; i < count; i++) {
INPUT input = { 0 };
input.type = INPUT_KEYBOARD;
input.ki.wScan = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;
input.ki.wVk = VK_BACK;
input.ki.dwFlags = 0; // 0 for key press
vec.push_back(input);
// Release the "A" key
input.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
vec.push_back(input);
}
SendInput(vec.size(), vec.data(), sizeof(INPUT)); SendInput(vec.size(), vec.data(), sizeof(INPUT));
} }

View File

@ -34,4 +34,9 @@ extern "C" void eventloop();
*/ */
extern "C" void send_string(const wchar_t * string); extern "C" void send_string(const wchar_t * string);
/*
* Send the backspace keypress, *count* times.
*/
extern "C" void delete_string(int32_t count);
#endif //ESPANSO_BRIDGE_H #endif //ESPANSO_BRIDGE_H

View File

@ -0,0 +1,19 @@
use crate::matcher::{Match, MatchReceiver};
use crate::keyboard::KeyboardSender;
pub struct Engine<'a>{
sender: &'a KeyboardSender
}
impl <'a> Engine<'a> {
pub fn new(sender: &'a KeyboardSender) -> Engine<'a> {
Engine{sender}
}
}
impl <'a> MatchReceiver for Engine<'a>{
fn on_match(&self, m: Match) {
self.sender.delete_string(m.trigger.len() as i32);
self.sender.send_string(m.result.as_str());
}
}

View File

@ -10,9 +10,15 @@ pub trait KeyboardInterceptor {
pub trait KeyboardSender { pub trait KeyboardSender {
fn send_string(&self, s: &str); fn send_string(&self, s: &str);
fn delete_string(&self, count: i32);
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub fn get_backend(sender: mpsc::Sender<char>) -> (impl KeyboardInterceptor, impl KeyboardSender) { pub fn get_interceptor(sender: mpsc::Sender<char>) -> impl KeyboardInterceptor {
(windows::WindowsKeyboardInterceptor {sender}, windows::WindowsKeyboardSender{}) windows::WindowsKeyboardInterceptor {sender}
}
#[cfg(target_os = "windows")]
pub fn get_sender() -> impl KeyboardSender {
windows::WindowsKeyboardSender{}
} }

View File

@ -1,6 +1,6 @@
use std::thread; use std::thread;
use std::sync::mpsc; use std::sync::mpsc;
use widestring::{WideString, WideStr}; use widestring::{U16CString};
#[repr(C)] #[repr(C)]
pub struct WindowsKeyboardInterceptor { pub struct WindowsKeyboardInterceptor {
@ -29,9 +29,21 @@ pub struct WindowsKeyboardSender {
impl super::KeyboardSender for WindowsKeyboardSender { impl super::KeyboardSender for WindowsKeyboardSender {
fn send_string(&self, s: &str) { fn send_string(&self, s: &str) {
let s = WideString::from(s.to_owned()); let res = U16CString::from_str(s);
match res {
Ok(s) => {
unsafe {
send_string(s.as_ptr());
}
}
Err(e) => println!("Error while sending string: {}", e.to_string())
}
}
fn delete_string(&self, count: i32) {
unsafe { unsafe {
send_string(s.as_ptr()); delete_string(count)
} }
} }
} }
@ -49,10 +61,12 @@ extern fn keypress_callback(_self: *mut WindowsKeyboardInterceptor, raw_buffer:
} }
} }
#[allow(improper_ctypes)]
#[link(name="winbridge", kind="static")] #[link(name="winbridge", kind="static")]
extern { extern {
fn register_keypress_callback(s: *const WindowsKeyboardInterceptor, cb: extern fn(_self: *mut WindowsKeyboardInterceptor, *const i32, i32)); fn register_keypress_callback(s: *const WindowsKeyboardInterceptor, cb: extern fn(_self: *mut WindowsKeyboardInterceptor, *const i32, i32));
fn initialize_window(); fn initialize_window();
fn eventloop(); fn eventloop();
fn send_string(string: *const u16); fn send_string(string: *const u16);
fn delete_string(count: i32);
} }

View File

@ -1,22 +1,26 @@
use std::thread::sleep;
use std::time::Duration;
use std::sync::mpsc; use std::sync::mpsc;
use crate::keyboard::KeyboardInterceptor; use crate::keyboard::KeyboardInterceptor;
use crate::keyboard::KeyboardSender;
use crate::matcher::Matcher; use crate::matcher::Matcher;
use crate::matcher::scrolling::ScrollingMatcher;
use crate::engine::Engine;
mod keyboard; mod keyboard;
mod matcher; mod matcher;
mod engine;
fn main() { fn main() {
println!("Hello, world from Rust!"); println!("espanso is running!");
let (sender, receiver) = mpsc::channel(); let (txc, rxc) = mpsc::channel();
let (interceptor, sender) = keyboard::get_backend(sender); let interceptor = keyboard::get_interceptor(txc);
interceptor.initialize(); interceptor.initialize();
interceptor.start(); interceptor.start();
let matcher = Matcher{receiver}; let sender = keyboard::get_sender();
matcher.watch();
let engine = Engine::new(&sender);
let matcher = ScrollingMatcher::new(&engine);
matcher.watch(&rxc);
} }

View File

@ -1,24 +1,25 @@
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
pub(crate) mod scrolling;
pub struct Match { pub struct Match {
pub trigger: String, pub trigger: String,
pub result: String pub result: String
} }
pub trait MatchReceiver {
fn on_match(&self, m: Match);
pub struct Matcher {
pub receiver: Receiver<char>
} }
impl Matcher { pub trait Matcher {
pub fn watch(&self) { fn handle_char(&self, c: char);
fn watch(&self, receiver: &Receiver<char>) {
loop { loop {
match self.receiver.recv() { match receiver.recv() {
Ok(c) => { Ok(c) => {
println!("Yeah {}",c); self.handle_char(c);
}, },
Err(_) => panic!("Worker threads disconnected before the solution was found!"), Err(_) => panic!("Keyboard interceptor broke receiver stream."),
} }
} }
} }

View File

@ -0,0 +1,21 @@
use crate::matcher::{Match, MatchReceiver};
pub struct ScrollingMatcher<'a>{
receiver: &'a MatchReceiver
}
impl <'a> super::Matcher for ScrollingMatcher<'a> {
fn handle_char(&self, c: char) {
println!("Scroll {}",c);
if c == 'a' {
self.receiver.on_match(Match{trigger: "a".to_owned(), result: "ciao".to_owned()});
}
}
}
impl <'a> ScrollingMatcher<'a> {
pub fn new(receiver: &'a MatchReceiver) -> ScrollingMatcher<'a> {
ScrollingMatcher{ receiver }
}
}