Add "other" event type on macOS to improve word matches reliability
This commit is contained in:
parent
5273d8b805
commit
43a82872d3
|
@ -36,16 +36,20 @@
|
||||||
[myStatusItem.button setTarget:self];
|
[myStatusItem.button setTarget:self];
|
||||||
|
|
||||||
// Setup key listener
|
// Setup key listener
|
||||||
[NSEvent addGlobalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged)
|
[NSEvent addGlobalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged | NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown)
|
||||||
handler:^(NSEvent *event){
|
handler:^(NSEvent *event){
|
||||||
|
|
||||||
if (event.type == NSEventTypeKeyDown
|
if (event.type == NSEventTypeKeyDown
|
||||||
&& event.keyCode != 0x33) { // Send backspace as a modifier
|
&& 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;
|
int len = event.characters.length;
|
||||||
|
|
||||||
keypress_callback(context_instance, chars, len, 0, event.keyCode);
|
keypress_callback(context_instance, chars, len, 0, event.keyCode);
|
||||||
//NSLog(@"keydown: %@, %d", event.characters, 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{
|
}else{
|
||||||
// Because this event is triggered for both the press and release of a modifier, trigger the callback
|
// Because this event is triggered for both the press and release of a modifier, trigger the callback
|
||||||
// only on release
|
// only on release
|
||||||
|
|
|
@ -46,7 +46,7 @@ int32_t headless_eventloop();
|
||||||
* Called when a new keypress is made, the first argument is an char array,
|
* Called when a new keypress is made, the first argument is an char array,
|
||||||
* while the second is the size of the 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;
|
extern KeypressCallback keypress_callback;
|
||||||
|
|
||||||
|
|
|
@ -24,17 +24,21 @@ use crate::event::{Event, KeyEvent, KeyModifier, ActionType};
|
||||||
use crate::event::KeyModifier::*;
|
use crate::event::KeyModifier::*;
|
||||||
use std::ffi::{CString, CStr};
|
use std::ffi::{CString, CStr};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use log::{info, error};
|
use log::{info, error, debug};
|
||||||
use std::process::exit;
|
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");
|
const STATUS_ICON_BINARY : &[u8] = include_bytes!("../res/mac/icon.png");
|
||||||
|
|
||||||
pub struct MacContext {
|
pub struct MacContext {
|
||||||
pub send_channel: Sender<Event>
|
pub send_channel: Sender<Event>,
|
||||||
|
is_injecting: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacContext {
|
impl MacContext {
|
||||||
pub fn new(send_channel: Sender<Event>) -> Box<MacContext> {
|
pub fn new(send_channel: Sender<Event>, is_injecting: Arc<AtomicBool>) -> Box<MacContext> {
|
||||||
// Check accessibility
|
// Check accessibility
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = prompt_accessibility();
|
let res = prompt_accessibility();
|
||||||
|
@ -48,7 +52,8 @@ impl MacContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
let context = Box::new(MacContext {
|
let context = Box::new(MacContext {
|
||||||
send_channel
|
send_channel,
|
||||||
|
is_injecting
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize the status icon path
|
// Initialize the status icon path
|
||||||
|
@ -89,11 +94,19 @@ impl super::Context for MacContext {
|
||||||
// Native bridge code
|
// Native bridge code
|
||||||
|
|
||||||
extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const u8, len: i32,
|
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 {
|
unsafe {
|
||||||
let _self = _self as *mut MacContext;
|
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
|
// Convert the received buffer to a string
|
||||||
let c_str = CStr::from_ptr(raw_buffer as (*const c_char));
|
let c_str = CStr::from_ptr(raw_buffer as (*const c_char));
|
||||||
let char_str = c_str.to_str();
|
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);
|
error!("Unable to receive char: {}",e);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}else{ // Modifier event
|
}else if event_type == 1 { // Modifier event
|
||||||
let modifier: Option<KeyModifier> = match key_code {
|
let modifier: Option<KeyModifier> = match key_code {
|
||||||
0x37 => Some(META),
|
0x37 => Some(META),
|
||||||
0x38 => Some(SHIFT),
|
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 {
|
if let Some(modifier) = modifier {
|
||||||
let event = Event::Key(KeyEvent::Modifier(modifier));
|
let event = Event::Key(KeyEvent::Modifier(modifier));
|
||||||
(*_self).send_channel.send(event).unwrap();
|
(*_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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,8 @@ pub trait Context {
|
||||||
|
|
||||||
// MAC IMPLEMENTATION
|
// MAC IMPLEMENTATION
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn new(send_channel: Sender<Event>) -> Box<dyn Context> {
|
pub fn new(send_channel: Sender<Event>, is_injecting: Arc<AtomicBool>) -> Box<dyn Context> {
|
||||||
macos::MacContext::new(send_channel)
|
macos::MacContext::new(send_channel, is_injecting)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINUX IMPLEMENTATION
|
// LINUX IMPLEMENTATION
|
||||||
|
|
Loading…
Reference in New Issue
Block a user