Add windows send keys

This commit is contained in:
Federico Terzi 2019-08-30 21:24:03 +02:00
parent c05652618f
commit c0cd826b45
10 changed files with 97 additions and 23 deletions

7
Cargo.lock generated
View File

@ -16,8 +16,15 @@ name = "espanso"
version = "0.1.0"
dependencies = [
"cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "widestring"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff"
"checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62"
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"

View File

@ -6,6 +6,7 @@ edition = "2018"
build="build.rs"
[dependencies]
widestring = "0.4.0"
[build-dependencies]
cmake = "0.1.31"

View File

@ -18,11 +18,11 @@ HWND window;
const wchar_t* const winclass = L"Espanso";
keypress_callback keypressCallback;
void * backend_instance;
void * interceptor_instance;
void register_keypress_callback(void * self, keypress_callback callback) {
keypressCallback = callback;
backend_instance = self;
interceptor_instance = self;
}
/*
@ -95,7 +95,7 @@ LRESULT CALLBACK window_worker_procedure(HWND window, unsigned int msg, WPARAM w
// If a result is available, invoke the callback
if (result >= 1) {
//std::cout << buffer[0] << " " << buffer[1] << " res=" << result << " vk=" << raw->data.keyboard.VKey << " rsc=" << raw->data.keyboard.MakeCode << std::endl;
keypressCallback(backend_instance, reinterpret_cast<int32_t*>(buffer.data()), buffer.size());
keypressCallback(interceptor_instance, reinterpret_cast<int32_t*>(buffer.data()), buffer.size());
}
}
}
@ -180,3 +180,24 @@ void eventloop() {
// Something went wrong, this should have been an infinite loop.
}
/*
* Type the given string simulating keyboard presses.
*/
void send_string(const wchar_t * string) {
std::wstring msg = string;
std::vector<INPUT> vec;
for (auto ch : msg)
{
INPUT input = { 0 };
input.type = INPUT_KEYBOARD;
input.ki.dwFlags = KEYEVENTF_UNICODE;
input.ki.wScan = ch;
vec.push_back(input);
input.ki.dwFlags |= KEYEVENTF_KEYUP;
vec.push_back(input);
}
SendInput(vec.size(), vec.data(), sizeof(INPUT));
}

View File

@ -11,7 +11,7 @@
typedef void (*keypress_callback)(void * self, int32_t *buffer, int32_t len);
extern keypress_callback keypressCallback;
extern void * backend_instance;
extern void * interceptor_instance;
/*
* Register the callback that will be called when a keypress was made
@ -29,4 +29,9 @@ extern "C" int32_t initialize_window();
*/
extern "C" void eventloop();
/*
* Type the given string by simulating Key Presses
*/
extern "C" void send_string(const wchar_t * string);
#endif //ESPANSO_BRIDGE_H

0
src/engine.rs Normal file
View File

View File

@ -3,12 +3,16 @@ mod windows;
use std::sync::mpsc;
pub trait KeyboardBackend {
pub trait KeyboardInterceptor {
fn initialize(&self);
fn start(&self);
}
pub trait KeyboardSender {
fn send_string(&self, s: &str);
}
#[cfg(target_os = "windows")]
pub fn get_backend(sender: mpsc::Sender<char>) -> impl KeyboardBackend{
windows::WindowsKeyboardBackend{sender }
pub fn get_backend(sender: mpsc::Sender<char>) -> (impl KeyboardInterceptor, impl KeyboardSender) {
(windows::WindowsKeyboardInterceptor {sender}, windows::WindowsKeyboardSender{})
}

View File

@ -1,12 +1,13 @@
use std::thread;
use std::sync::mpsc;
use widestring::{WideString, WideStr};
#[repr(C)]
pub struct WindowsKeyboardBackend {
pub struct WindowsKeyboardInterceptor {
pub sender: mpsc::Sender<char>
}
impl super::KeyboardBackend for WindowsKeyboardBackend {
impl super::KeyboardInterceptor for WindowsKeyboardInterceptor {
fn initialize(&self) {
unsafe {
register_keypress_callback(self,keypress_callback);
@ -23,9 +24,21 @@ impl super::KeyboardBackend for WindowsKeyboardBackend {
}
}
pub struct WindowsKeyboardSender {
}
impl super::KeyboardSender for WindowsKeyboardSender {
fn send_string(&self, s: &str) {
let s = WideString::from(s.to_owned());
unsafe {
send_string(s.as_ptr());
}
}
}
// Native bridge code
extern fn keypress_callback(_self: *mut WindowsKeyboardBackend, raw_buffer: *const i32, len: i32) {
extern fn keypress_callback(_self: *mut WindowsKeyboardInterceptor, raw_buffer: *const i32, len: i32) {
unsafe {
// Convert the received buffer to a character
let buffer = std::slice::from_raw_parts(raw_buffer, len as usize);
@ -38,7 +51,8 @@ extern fn keypress_callback(_self: *mut WindowsKeyboardBackend, raw_buffer: *con
#[link(name="winbridge", kind="static")]
extern {
fn register_keypress_callback(s: *const WindowsKeyboardBackend, cb: extern fn(_self: *mut WindowsKeyboardBackend, *const i32, i32));
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);
}

View File

@ -1,25 +1,22 @@
use std::thread::sleep;
use std::time::Duration;
use crate::keyboard::KeyboardBackend;
use std::sync::mpsc;
use crate::keyboard::KeyboardInterceptor;
use crate::keyboard::KeyboardSender;
use crate::matcher::Matcher;
mod keyboard;
mod matcher;
fn main() {
println!("Hello, world from Rust!");
let (sender, receiver) = mpsc::channel();
let keyboard = keyboard::get_backend(sender);
keyboard.initialize();
keyboard.start();
let (interceptor, sender) = keyboard::get_backend(sender);
interceptor.initialize();
interceptor.start();
loop {
match receiver.recv() {
Ok(c) => {
println!("Yeah {}",c);
},
Err(_) => panic!("Worker threads disconnected before the solution was found!"),
}
}
let matcher = Matcher{receiver};
matcher.watch();
}

25
src/matcher/mod.rs Normal file
View File

@ -0,0 +1,25 @@
use std::sync::mpsc::Receiver;
pub struct Match {
pub trigger: String,
pub result: String
}
pub struct Matcher {
pub receiver: Receiver<char>
}
impl Matcher {
pub fn watch(&self) {
loop {
match self.receiver.recv() {
Ok(c) => {
println!("Yeah {}",c);
},
Err(_) => panic!("Worker threads disconnected before the solution was found!"),
}
}
}
}

0
src/matcher/scrolling.rs Normal file
View File