diff --git a/native/libwinbridge/bridge.cpp b/native/libwinbridge/bridge.cpp index 9c72d7f..cb55b10 100644 --- a/native/libwinbridge/bridge.cpp +++ b/native/libwinbridge/bridge.cpp @@ -17,11 +17,11 @@ HWND window; const wchar_t* const winclass = L"Espanso"; -keypress_callback keypressCallback; +KeypressCallback keypress_callback; void * interceptor_instance; -void register_keypress_callback(void * self, keypress_callback callback) { - keypressCallback = callback; +void register_keypress_callback(void * self, KeypressCallback callback) { + keypress_callback = callback; interceptor_instance = self; } @@ -92,10 +92,14 @@ LRESULT CALLBACK window_worker_procedure(HWND window, unsigned int msg, WPARAM w std::array buffer; int result = ToUnicodeEx(raw->data.keyboard.VKey, raw->data.keyboard.MakeCode, lpKeyState.data(), buffer.data(), buffer.size(), 0, currentKeyboardLayout); - // 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(interceptor_instance, reinterpret_cast(buffer.data()), buffer.size()); + //std::cout << result << " " << buffer[0] << " " << raw->data.keyboard.VKey << std::endl; + + // We need to call the callback in two different ways based on the type of key + // The only modifier we use that has a result > 0 is the BACKSPACE, so we have to consider it. + if (result >= 1 && raw->data.keyboard.VKey != VK_BACK) { + keypress_callback(interceptor_instance, reinterpret_cast(buffer.data()), buffer.size(), 0, raw->data.keyboard.VKey); + }else{ + keypress_callback(interceptor_instance, nullptr, 0, 1, raw->data.keyboard.VKey); } } } diff --git a/native/libwinbridge/bridge.h b/native/libwinbridge/bridge.h index aca4643..8a89442 100644 --- a/native/libwinbridge/bridge.h +++ b/native/libwinbridge/bridge.h @@ -8,15 +8,15 @@ * Called when a new keypress is made, the first argument is an int array, * while the second is the size of the array. */ -typedef void (*keypress_callback)(void * self, int32_t *buffer, int32_t len); +typedef void (*KeypressCallback)(void * self, int32_t *buffer, int32_t len, int32_t is_modifier, int32_t key_code); -extern keypress_callback keypressCallback; +extern KeypressCallback keypress_callback; extern void * interceptor_instance; /* * Register the callback that will be called when a keypress was made */ -extern "C" void register_keypress_callback(void *self, keypress_callback callback); +extern "C" void register_keypress_callback(void *self, KeypressCallback callback); /* * Initialize the Windows worker's parameters diff --git a/src/keyboard/windows.rs b/src/keyboard/windows.rs index d7ce04b..c3af680 100644 --- a/src/keyboard/windows.rs +++ b/src/keyboard/windows.rs @@ -1,7 +1,8 @@ use std::thread; use std::sync::mpsc; use widestring::{U16CString}; -use crate::keyboard::KeyEvent; +use crate::keyboard::{KeyEvent, KeyModifier}; +use crate::keyboard::KeyModifier::*; #[repr(C)] pub struct WindowsKeyboardInterceptor { @@ -12,16 +13,14 @@ impl super::KeyboardInterceptor for WindowsKeyboardInterceptor { fn initialize(&self) { unsafe { register_keypress_callback(self,keypress_callback); + initialize_window(); } } fn start(&self) { - thread::spawn(|| { - unsafe { - initialize_window(); - eventloop(); - } - }); + unsafe { + eventloop(); + } } } @@ -51,21 +50,41 @@ impl super::KeyboardSender for WindowsKeyboardSender { // Native bridge code -extern fn keypress_callback(_self: *mut WindowsKeyboardInterceptor, raw_buffer: *const i32, len: i32) { +extern fn keypress_callback(_self: *mut WindowsKeyboardInterceptor, raw_buffer: *const i32, len: i32, + is_modifier: i32, key_code: i32) { unsafe { - // Convert the received buffer to a character - let buffer = std::slice::from_raw_parts(raw_buffer, len as usize); - let r = std::char::from_u32(buffer[0] as u32).unwrap(); + if is_modifier == 0 { // Char event + // Convert the received buffer to a character + let buffer = std::slice::from_raw_parts(raw_buffer, len as usize); + let r = std::char::from_u32(buffer[0] as u32); - // Send the char through the channel - (*_self).sender.send(r).unwrap(); + // Send the char through the channel + if let Some(c) = r { + (*_self).sender.send(KeyEvent::Char(c)).unwrap(); + } + }else{ // Modifier event + let modifier: Option = match key_code { + 0x5B | 0x5C => Some(META), + 0x10 => Some(SHIFT), + 0x12 => Some(ALT), + 0x11 => Some(CTRL), + 0x08 => Some(BACKSPACE), + _ => None, + }; + + if let Some(modifier) = modifier { + (*_self).sender.send(KeyEvent::Modifier(modifier)).unwrap(); + } + } } } #[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 register_keypress_callback(s: *const WindowsKeyboardInterceptor, + cb: extern fn(_self: *mut WindowsKeyboardInterceptor, *const i32, + i32, i32, i32)); fn initialize_window(); fn eventloop(); fn send_string(string: *const u16);