From 43a82872d36367fd13c36e192d0add4aad901f9a Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 8 Mar 2020 20:11:57 +0100 Subject: [PATCH] Add "other" event type on macOS to improve word matches reliability --- native/libmacbridge/AppDelegate.mm | 8 ++++++-- native/libmacbridge/bridge.h | 2 +- src/context/macos.rs | 33 +++++++++++++++++++++++------- src/context/mod.rs | 4 ++-- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/native/libmacbridge/AppDelegate.mm b/native/libmacbridge/AppDelegate.mm index 35e9177..29d1213 100644 --- a/native/libmacbridge/AppDelegate.mm +++ b/native/libmacbridge/AppDelegate.mm @@ -36,16 +36,20 @@ [myStatusItem.button setTarget:self]; // Setup key listener - [NSEvent addGlobalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged) + [NSEvent addGlobalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged | NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown) handler:^(NSEvent *event){ + if (event.type == NSEventTypeKeyDown && event.keyCode != 0x33) { // Send backspace as a modifier - const char * chars = [event.characters UTF8String]; + const char *chars = [event.characters UTF8String]; int len = event.characters.length; keypress_callback(context_instance, chars, len, 0, event.keyCode); //NSLog(@"keydown: %@, %d", event.characters, event.keyCode); + }else if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown) { + // Send the mouse button clicks as "other" events, used to improve word matches reliability + keypress_callback(context_instance, NULL, 0, 2, event.buttonNumber); }else{ // Because this event is triggered for both the press and release of a modifier, trigger the callback // only on release diff --git a/native/libmacbridge/bridge.h b/native/libmacbridge/bridge.h index 3fc9f9d..dc74187 100644 --- a/native/libmacbridge/bridge.h +++ b/native/libmacbridge/bridge.h @@ -46,7 +46,7 @@ int32_t headless_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, int32_t is_modifier, int32_t key_code); +typedef void (*KeypressCallback)(void * self, const char *buffer, int32_t len, int32_t event_type, int32_t key_code); extern KeypressCallback keypress_callback; diff --git a/src/context/macos.rs b/src/context/macos.rs index 6c66ed3..b3f621f 100644 --- a/src/context/macos.rs +++ b/src/context/macos.rs @@ -24,17 +24,21 @@ use crate::event::{Event, KeyEvent, KeyModifier, ActionType}; use crate::event::KeyModifier::*; use std::ffi::{CString, CStr}; use std::fs; -use log::{info, error}; +use log::{info, error, debug}; use std::process::exit; +use std::sync::atomic::AtomicBool; +use std::sync::Arc; +use std::sync::atomic::Ordering::Acquire; const STATUS_ICON_BINARY : &[u8] = include_bytes!("../res/mac/icon.png"); pub struct MacContext { - pub send_channel: Sender + pub send_channel: Sender, + is_injecting: Arc, } impl MacContext { - pub fn new(send_channel: Sender) -> Box { + pub fn new(send_channel: Sender, is_injecting: Arc) -> Box { // Check accessibility unsafe { let res = prompt_accessibility(); @@ -48,7 +52,8 @@ impl MacContext { } let context = Box::new(MacContext { - send_channel + send_channel, + is_injecting }); // Initialize the status icon path @@ -89,11 +94,19 @@ impl super::Context for MacContext { // Native bridge code extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const u8, len: i32, - is_modifier: i32, key_code: i32) { + event_type: i32, key_code: i32) { unsafe { let _self = _self as *mut MacContext; - if is_modifier == 0 { // Char event + // If espanso is currently injecting text, we should avoid processing + // external events, as it could happen that espanso reinterpret its + // own input. + if (*_self).is_injecting.load(Acquire) { + debug!("Input ignored while espanso is injecting text..."); + return; + } + + if event_type == 0 { // Char event // Convert the received buffer to a string let c_str = CStr::from_ptr(raw_buffer as (*const c_char)); let char_str = c_str.to_str(); @@ -108,7 +121,7 @@ extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const u8, len: i32, error!("Unable to receive char: {}",e); }, } - }else{ // Modifier event + }else if event_type == 1 { // Modifier event let modifier: Option = match key_code { 0x37 => Some(META), 0x38 => Some(SHIFT), @@ -121,7 +134,13 @@ extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const u8, len: i32, if let Some(modifier) = modifier { let event = Event::Key(KeyEvent::Modifier(modifier)); (*_self).send_channel.send(event).unwrap(); + }else{ // Not one of the default modifiers, send an "other" event + let event = Event::Key(KeyEvent::Other); + (*_self).send_channel.send(event).unwrap(); } + }else{ // Other type of event + let event = Event::Key(KeyEvent::Other); + (*_self).send_channel.send(event).unwrap(); } } } diff --git a/src/context/mod.rs b/src/context/mod.rs index dec7eca..332ba4f 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -39,8 +39,8 @@ pub trait Context { // MAC IMPLEMENTATION #[cfg(target_os = "macos")] -pub fn new(send_channel: Sender) -> Box { - macos::MacContext::new(send_channel) +pub fn new(send_channel: Sender, is_injecting: Arc) -> Box { + macos::MacContext::new(send_channel, is_injecting) } // LINUX IMPLEMENTATION