diff --git a/native/libmacbridge/AppDelegate.mm b/native/libmacbridge/AppDelegate.mm index 2d02544..92b19a7 100644 --- a/native/libmacbridge/AppDelegate.mm +++ b/native/libmacbridge/AppDelegate.mm @@ -24,13 +24,24 @@ void * interceptor_instance; NSLog(@"registering keydown mask"); [NSEvent addGlobalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged) handler:^(NSEvent *event){ - if (event.type == NSEventTypeKeyDown) { + if (event.type == NSEventTypeKeyDown + && event.keyCode != 0x33) { // Send backspace as a modifier + const char * chars = [event.characters UTF8String]; int len = event.characters.length; - keypress_callback(interceptor_instance, chars, len); - NSLog(@"keydown: %@, %d", event.characters, event.keyCode); + + keypress_callback(interceptor_instance, chars, len, 0, event.keyCode); + //NSLog(@"keydown: %@, %d", event.characters, event.keyCode); }else{ - NSLog(@"keydown: %d", event.keyCode); + // Because this event is triggered for both the press and release of a modifier, trigger the callback + // only on release + if (([event modifierFlags] & (NSEventModifierFlagShift | NSEventModifierFlagCommand | + NSEventModifierFlagControl | NSEventModifierFlagOption)) == 0) { + + keypress_callback(interceptor_instance, NULL, 0, 1, event.keyCode); + } + + //NSLog(@"keydown: %d", event.keyCode); } }]; } diff --git a/native/libmacbridge/bridge.h b/native/libmacbridge/bridge.h index f9fa950..556c24c 100644 --- a/native/libmacbridge/bridge.h +++ b/native/libmacbridge/bridge.h @@ -19,7 +19,7 @@ int32_t eventloop(); * Called when a new keypress is made, the first argument is an char array, * while the second is the size of the array. */ -typedef void (*KeypressCallback)(void * self, const char *buffer, int32_t len); +typedef void (*KeypressCallback)(void * self, const char *buffer, int32_t len, int32_t is_modifier, int32_t key_code); extern KeypressCallback keypress_callback; extern void * interceptor_instance; diff --git a/native/libmacbridge/bridge.mm b/native/libmacbridge/bridge.mm index 6fa24d0..6e74b96 100644 --- a/native/libmacbridge/bridge.mm +++ b/native/libmacbridge/bridge.mm @@ -2,6 +2,7 @@ #import #include "AppDelegate.h" +#include extern "C" { } @@ -25,33 +26,40 @@ int32_t eventloop() { } void send_string(const char * string) { - // Convert the c string to a UniChar array as required by the CGEventKeyboardSetUnicodeString method - NSString * nsString = [NSString stringWithUTF8String:string]; - CFStringRef cfString = (__bridge CFStringRef)nsString; - std::vector buffer(nsString.length); - CFStringGetCharacters(cfString, CFRangeMake(0, nsString.length), buffer.data()); + char * stringCopy = strdup(string); + dispatch_async(dispatch_get_main_queue(), ^(void) { + // Convert the c string to a UniChar array as required by the CGEventKeyboardSetUnicodeString method + NSString *nsString = [NSString stringWithUTF8String:stringCopy]; + CFStringRef cfString = (__bridge CFStringRef) nsString; + std::vector buffer(nsString.length); + CFStringGetCharacters(cfString, CFRangeMake(0, nsString.length), buffer.data()); - // Send the event - CGEventRef e = CGEventCreateKeyboardEvent(NULL, 0x31, true); - CGEventKeyboardSetUnicodeString(e, buffer.size(), buffer.data()); - CGEventPost(kCGHIDEventTap, e); - CFRelease(e); + free(stringCopy); + + // Send the event + CGEventRef e = CGEventCreateKeyboardEvent(NULL, 0x31, true); + CGEventKeyboardSetUnicodeString(e, buffer.size(), buffer.data()); + CGEventPost(kCGHIDEventTap, e); + CFRelease(e); + }); } void delete_string(int32_t count) { - for (int i = 0; i } +impl Default for Configs { + fn default() -> Self { + Configs { + backspace_enabled: false, + matches: Vec::new() + } + } +} + impl Configs { pub fn load(path: &Path) -> Configs { let file_res = File::open(path); diff --git a/src/keyboard/linux.rs b/src/keyboard/linux.rs index a8c6350..087e7b2 100644 --- a/src/keyboard/linux.rs +++ b/src/keyboard/linux.rs @@ -2,10 +2,11 @@ use std::thread; use std::sync::mpsc; use std::os::raw::c_char; use std::ffi::CString; +use crate::keyboard::KeyEvent; #[repr(C)] pub struct LinuxKeyboardInterceptor { - pub sender: mpsc::Sender + pub sender: mpsc::Sender } impl super::KeyboardInterceptor for LinuxKeyboardInterceptor { diff --git a/src/keyboard/macos.rs b/src/keyboard/macos.rs index e05f526..c3df31a 100644 --- a/src/keyboard/macos.rs +++ b/src/keyboard/macos.rs @@ -1,10 +1,12 @@ use std::sync::mpsc; use std::os::raw::c_char; use std::ffi::CString; +use crate::keyboard::{KeyEvent, KeyModifier}; +use crate::keyboard::KeyModifier::*; #[repr(C)] pub struct MacKeyboardInterceptor { - pub sender: mpsc::Sender + pub sender: mpsc::Sender } impl super::KeyboardInterceptor for MacKeyboardInterceptor { @@ -39,16 +41,31 @@ impl super::KeyboardSender for MacKeyboardSender { // Native bridge code -extern fn keypress_callback(_self: *mut MacKeyboardInterceptor, raw_buffer: *const u8, len: i32) { +extern fn keypress_callback(_self: *mut MacKeyboardInterceptor, raw_buffer: *const u8, 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 = String::from_utf8_lossy(buffer).chars().nth(0); + 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 = String::from_utf8_lossy(buffer).chars().nth(0); - // Send the char through the channel - if let Some(c) = r { - //println!("'{}'",c); - (*_self).sender.send(c).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 { + 0x37 => Some(META), + 0x38 => Some(SHIFT), + 0x3A => Some(ALT), + 0x3B => Some(CTRL), + 0x33 => Some(BACKSPACE), + _ => None, + }; + + if let Some(modifier) = modifier { + (*_self).sender.send(KeyEvent::Modifier(modifier)).unwrap(); + } } } } @@ -56,7 +73,9 @@ extern fn keypress_callback(_self: *mut MacKeyboardInterceptor, raw_buffer: *con #[allow(improper_ctypes)] #[link(name="macbridge", kind="static")] extern { - fn register_keypress_callback(s: *const MacKeyboardInterceptor, cb: extern fn(_self: *mut MacKeyboardInterceptor, *const u8, i32)); + fn register_keypress_callback(s: *const MacKeyboardInterceptor, + cb: extern fn(_self: *mut MacKeyboardInterceptor, *const u8, + i32, i32, i32)); fn initialize(); fn eventloop(); fn send_string(string: *const c_char); diff --git a/src/keyboard/mod.rs b/src/keyboard/mod.rs index 71a587c..0f949e6 100644 --- a/src/keyboard/mod.rs +++ b/src/keyboard/mod.rs @@ -14,6 +14,21 @@ pub trait KeyboardInterceptor { fn start(&self); } +#[derive(Debug)] +pub enum KeyModifier { + CTRL, + SHIFT, + ALT, + META, + BACKSPACE, +} + +#[derive(Debug)] +pub enum KeyEvent { + Char(char), + Modifier(KeyModifier) +} + pub trait KeyboardSender { fn send_string(&self, s: &str); fn delete_string(&self, count: i32); @@ -22,7 +37,7 @@ pub trait KeyboardSender { // WINDOWS IMPLEMENTATIONS #[cfg(target_os = "windows")] -pub fn get_interceptor(sender: mpsc::Sender) -> impl KeyboardInterceptor { +pub fn get_interceptor(sender: mpsc::Sender) -> impl KeyboardInterceptor { windows::WindowsKeyboardInterceptor {sender} } @@ -34,7 +49,7 @@ pub fn get_sender() -> impl KeyboardSender { // LINUX IMPLEMENTATIONS #[cfg(target_os = "linux")] -pub fn get_interceptor(sender: mpsc::Sender) -> impl KeyboardInterceptor { +pub fn get_interceptor(sender: mpsc::Sender) -> impl KeyboardInterceptor { linux::LinuxKeyboardInterceptor {sender} } @@ -45,7 +60,7 @@ pub fn get_sender() -> impl KeyboardSender { // MAC IMPLEMENTATION #[cfg(target_os = "macos")] -pub fn get_interceptor(sender: mpsc::Sender) -> impl KeyboardInterceptor { +pub fn get_interceptor(sender: mpsc::Sender) -> impl KeyboardInterceptor { macos::MacKeyboardInterceptor {sender} } diff --git a/src/keyboard/windows.rs b/src/keyboard/windows.rs index 201169a..d7ce04b 100644 --- a/src/keyboard/windows.rs +++ b/src/keyboard/windows.rs @@ -1,10 +1,11 @@ use std::thread; use std::sync::mpsc; use widestring::{U16CString}; +use crate::keyboard::KeyEvent; #[repr(C)] pub struct WindowsKeyboardInterceptor { - pub sender: mpsc::Sender + pub sender: mpsc::Sender } impl super::KeyboardInterceptor for WindowsKeyboardInterceptor { diff --git a/src/matcher/mod.rs b/src/matcher/mod.rs index f14c22a..a8c66ca 100644 --- a/src/matcher/mod.rs +++ b/src/matcher/mod.rs @@ -1,5 +1,6 @@ use std::sync::mpsc::Receiver; use serde::{Serialize, Deserialize}; +use crate::keyboard::{KeyEvent, KeyModifier}; pub(crate) mod scrolling; @@ -15,11 +16,19 @@ pub trait MatchReceiver { pub trait Matcher<'a>: Send { fn handle_char(&'a self, c: char); - fn watch(&'a self, receiver: Receiver) { + fn handle_modifier(&'a self, m: KeyModifier); + fn watch(&'a self, receiver: Receiver) { loop { match receiver.recv() { - Ok(c) => { - self.handle_char(c); + Ok(event) => { + match event { + KeyEvent::Char(c) => { + self.handle_char(c); + }, + KeyEvent::Modifier(m) => { + self.handle_modifier(m); + }, + } }, Err(_) => panic!("Keyboard interceptor broke receiver stream."), } diff --git a/src/matcher/scrolling.rs b/src/matcher/scrolling.rs index 508559e..1c7a445 100644 --- a/src/matcher/scrolling.rs +++ b/src/matcher/scrolling.rs @@ -1,5 +1,6 @@ use crate::matcher::{Match, MatchReceiver}; use std::cell::RefCell; +use crate::keyboard::KeyModifier; pub struct ScrollingMatcher<'a, R> where R: MatchReceiver{ matches: Vec, @@ -44,6 +45,10 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv self.receiver.on_match(_match); } } + + fn handle_modifier(&'a self, m: KeyModifier) { + + } } impl <'a, R> ScrollingMatcher<'a, R> where R: MatchReceiver {