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

@ -201,3 +201,28 @@ void send_string(const wchar_t * string) {
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));
}

View File

@ -34,4 +34,9 @@ extern "C" void eventloop();
*/
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

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 {
fn send_string(&self, s: &str);
fn delete_string(&self, count: i32);
}
#[cfg(target_os = "windows")]
pub fn get_backend(sender: mpsc::Sender<char>) -> (impl KeyboardInterceptor, impl KeyboardSender) {
(windows::WindowsKeyboardInterceptor {sender}, windows::WindowsKeyboardSender{})
pub fn get_interceptor(sender: mpsc::Sender<char>) -> impl KeyboardInterceptor {
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::sync::mpsc;
use widestring::{WideString, WideStr};
use widestring::{U16CString};
#[repr(C)]
pub struct WindowsKeyboardInterceptor {
@ -29,11 +29,23 @@ pub struct WindowsKeyboardSender {
impl super::KeyboardSender for WindowsKeyboardSender {
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 {
delete_string(count)
}
}
}
// Native bridge code
@ -49,10 +61,12 @@ extern fn keypress_callback(_self: *mut WindowsKeyboardInterceptor, raw_buffer:
}
}
#[allow(improper_ctypes)]
#[link(name="winbridge", kind="static")]
extern {
fn register_keypress_callback(s: *const WindowsKeyboardInterceptor, cb: extern fn(_self: *mut WindowsKeyboardInterceptor, *const i32, i32));
fn initialize_window();
fn eventloop();
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 crate::keyboard::KeyboardInterceptor;
use crate::keyboard::KeyboardSender;
use crate::matcher::Matcher;
use crate::matcher::scrolling::ScrollingMatcher;
use crate::engine::Engine;
mod keyboard;
mod matcher;
mod engine;
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.start();
let matcher = Matcher{receiver};
matcher.watch();
let sender = keyboard::get_sender();
let engine = Engine::new(&sender);
let matcher = ScrollingMatcher::new(&engine);
matcher.watch(&rxc);
}

View File

@ -1,24 +1,25 @@
use std::sync::mpsc::Receiver;
pub(crate) mod scrolling;
pub struct Match {
pub trigger: String,
pub result: String
}
pub struct Matcher {
pub receiver: Receiver<char>
pub trait MatchReceiver {
fn on_match(&self, m: Match);
}
impl Matcher {
pub fn watch(&self) {
pub trait Matcher {
fn handle_char(&self, c: char);
fn watch(&self, receiver: &Receiver<char>) {
loop {
match self.receiver.recv() {
match receiver.recv() {
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 }
}
}