Refactor macOS implementation
This commit is contained in:
parent
a57092517e
commit
75ca7ec071
|
@ -31,7 +31,7 @@ use log::{error, trace, warn};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::event::Status::*;
|
use crate::{Source, SourceCallback, event::Status::*};
|
||||||
use crate::event::Variant::*;
|
use crate::event::Variant::*;
|
||||||
use crate::event::{InputEvent, Key, KeyboardEvent, Variant};
|
use crate::event::{InputEvent, Key, KeyboardEvent, Variant};
|
||||||
use crate::event::{Key::*, MouseButton, MouseEvent};
|
use crate::event::{Key::*, MouseButton, MouseEvent};
|
||||||
|
@ -123,7 +123,7 @@ impl Source for CocoaSource {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eventloop(&self, event_callback: SourceCallback) {
|
fn eventloop(&self, event_callback: SourceCallback) -> Result<()> {
|
||||||
if let Some(receiver) = self.receiver.borrow() {
|
if let Some(receiver) = self.receiver.borrow() {
|
||||||
loop {
|
loop {
|
||||||
let event = receiver.recv();
|
let event = receiver.recv();
|
||||||
|
@ -138,8 +138,11 @@ impl Source for CocoaSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("Unable to start event loop if CocoaSource receiver is null");
|
error!("Unable to start event loop if CocoaSource receiver is null");
|
||||||
|
return Err(CocoaSourceError::Unknown().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ use raw_keys::convert_key_to_vkey;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{keys, Injector};
|
use crate::{InjectionOptions, Injector, keys};
|
||||||
|
|
||||||
#[allow(improper_ctypes)]
|
#[allow(improper_ctypes)]
|
||||||
#[link(name = "espansoinject", kind = "static")]
|
#[link(name = "espansoinject", kind = "static")]
|
||||||
|
@ -60,7 +60,7 @@ impl MacInjector {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Injector for MacInjector {
|
impl Injector for MacInjector {
|
||||||
fn send_string(&self, string: &str) -> Result<()> {
|
fn send_string(&self, string: &str, _: InjectionOptions) -> Result<()> {
|
||||||
let c_string = CString::new(string)?;
|
let c_string = CString::new(string)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
inject_string(c_string.as_ptr());
|
inject_string(c_string.as_ptr());
|
||||||
|
@ -68,21 +68,21 @@ impl Injector for MacInjector {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_keys(&self, keys: &[keys::Key], delay: i32) -> Result<()> {
|
fn send_keys(&self, keys: &[keys::Key], options: InjectionOptions) -> Result<()> {
|
||||||
let virtual_keys = Self::convert_to_vk_array(keys)?;
|
let virtual_keys = Self::convert_to_vk_array(keys)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
inject_separate_vkeys(virtual_keys.as_ptr(), virtual_keys.len() as i32, delay);
|
inject_separate_vkeys(virtual_keys.as_ptr(), virtual_keys.len() as i32, options.delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_key_combination(&self, keys: &[keys::Key], delay: i32) -> Result<()> {
|
fn send_key_combination(&self, keys: &[keys::Key], options: InjectionOptions) -> Result<()> {
|
||||||
let virtual_keys = Self::convert_to_vk_array(keys)?;
|
let virtual_keys = Self::convert_to_vk_array(keys)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
inject_vkeys_combination(virtual_keys.as_ptr(), virtual_keys.len() as i32, delay);
|
inject_vkeys_combination(virtual_keys.as_ptr(), virtual_keys.len() as i32, options.delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -55,9 +55,10 @@ pub fn create_ui(options: UIOptions) -> Result<(Box<dyn UIRemote>, Box<dyn UIEve
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn create_ui(options: UIOptions) -> Result<(Box<dyn UIRemote>, Box<dyn UIEventLoop>)> {
|
pub fn create_ui(options: UIOptions) -> Result<(Box<dyn UIRemote>, Box<dyn UIEventLoop>)> {
|
||||||
let (remote, eventloop) = linux::create(linux::LinuxUIOptions {
|
let (remote, eventloop) = mac::create(mac::MacUIOptions {
|
||||||
notification_icon_path: options.notification_icon_path.expect("missing notification icon path")
|
show_icon: options.show_icon,
|
||||||
});
|
icon_paths: &options.icon_paths,
|
||||||
|
})?;
|
||||||
Ok((Box::new(remote), Box::new(eventloop)))
|
Ok((Box::new(remote), Box::new(eventloop)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,12 @@
|
||||||
|
|
||||||
use std::{cmp::min, collections::HashMap, ffi::CString, os::raw::c_char, thread::ThreadId};
|
use std::{cmp::min, collections::HashMap, ffi::CString, os::raw::c_char, thread::ThreadId};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use thiserror::Error;
|
||||||
use lazycell::LazyCell;
|
use lazycell::LazyCell;
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
|
|
||||||
use crate::{event::UIEvent, icons::TrayIcon, menu::Menu};
|
use crate::{UIEventLoop, UIRemote, event::UIEvent, icons::TrayIcon, menu::Menu};
|
||||||
|
|
||||||
// IMPORTANT: if you change these, also edit the native.h file.
|
// IMPORTANT: if you change these, also edit the native.h file.
|
||||||
const MAX_FILE_PATH: usize = 1024;
|
const MAX_FILE_PATH: usize = 1024;
|
||||||
|
@ -63,7 +65,7 @@ pub struct MacUIOptions<'a> {
|
||||||
pub icon_paths: &'a Vec<(TrayIcon, String)>,
|
pub icon_paths: &'a Vec<(TrayIcon, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(options: MacUIOptions) -> (MacRemote, MacEventLoop) {
|
pub fn create(options: MacUIOptions) -> Result<(MacRemote, MacEventLoop)> {
|
||||||
// Validate icons
|
// Validate icons
|
||||||
if options.icon_paths.len() > MAX_ICON_COUNT {
|
if options.icon_paths.len() > MAX_ICON_COUNT {
|
||||||
panic!("MacOS UI received too many icon paths, please increase the MAX_ICON_COUNT constant to support more");
|
panic!("MacOS UI received too many icon paths, please increase the MAX_ICON_COUNT constant to support more");
|
||||||
|
@ -80,7 +82,7 @@ pub fn create(options: MacUIOptions) -> (MacRemote, MacEventLoop) {
|
||||||
let eventloop = MacEventLoop::new(icons, options.show_icon);
|
let eventloop = MacEventLoop::new(icons, options.show_icon);
|
||||||
let remote = MacRemote::new(icon_indexes);
|
let remote = MacRemote::new(icon_indexes);
|
||||||
|
|
||||||
(remote, eventloop)
|
Ok((remote, eventloop))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type MacUIEventCallback = Box<dyn Fn(UIEvent)>;
|
pub type MacUIEventCallback = Box<dyn Fn(UIEvent)>;
|
||||||
|
@ -104,13 +106,16 @@ impl MacEventLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize(&mut self) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UIEventLoop for MacEventLoop {
|
||||||
|
fn initialize(&mut self) -> Result<()> {
|
||||||
// Convert the icon paths to the raw representation
|
// Convert the icon paths to the raw representation
|
||||||
let mut icon_paths: [[u8; MAX_FILE_PATH]; MAX_ICON_COUNT] =
|
let mut icon_paths: [[u8; MAX_FILE_PATH]; MAX_ICON_COUNT] =
|
||||||
[[0; MAX_FILE_PATH]; MAX_ICON_COUNT];
|
[[0; MAX_FILE_PATH]; MAX_ICON_COUNT];
|
||||||
for (i, icon_path) in icon_paths.iter_mut().enumerate().take(self.icons.len()) {
|
for (i, icon_path) in icon_paths.iter_mut().enumerate().take(self.icons.len()) {
|
||||||
let c_path = CString::new(self.icons[i].clone())
|
let c_path = CString::new(self.icons[i].clone())?;
|
||||||
.expect("unable to create CString for UI tray icon path");
|
|
||||||
let len = min(c_path.as_bytes().len(), MAX_FILE_PATH - 1);
|
let len = min(c_path.as_bytes().len(), MAX_FILE_PATH - 1);
|
||||||
icon_path[0..len].clone_from_slice(&c_path.as_bytes()[..len]);
|
icon_path[0..len].clone_from_slice(&c_path.as_bytes()[..len]);
|
||||||
}
|
}
|
||||||
|
@ -128,9 +133,11 @@ impl MacEventLoop {
|
||||||
._init_thread_id
|
._init_thread_id
|
||||||
.fill(std::thread::current().id())
|
.fill(std::thread::current().id())
|
||||||
.expect("Unable to set initialization thread id");
|
.expect("Unable to set initialization thread id");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self, event_callback: MacUIEventCallback) {
|
fn run(&self, event_callback: MacUIEventCallback) -> Result<()> {
|
||||||
// Make sure the run() method is called in the same thread as initialize()
|
// Make sure the run() method is called in the same thread as initialize()
|
||||||
if let Some(init_id) = self._init_thread_id.borrow() {
|
if let Some(init_id) = self._init_thread_id.borrow() {
|
||||||
if init_id != &std::thread::current().id() {
|
if init_id != &std::thread::current().id() {
|
||||||
|
@ -139,7 +146,8 @@ impl MacEventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self._event_callback.fill(event_callback).is_err() {
|
if self._event_callback.fill(event_callback).is_err() {
|
||||||
panic!("Unable to set MacEventLoop callback");
|
error!("Unable to set MacEventLoop callback");
|
||||||
|
return Err(MacUIError::InternalError().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn callback(_self: *mut MacEventLoop, event: RawUIEvent) {
|
extern "C" fn callback(_self: *mut MacEventLoop, event: RawUIEvent) {
|
||||||
|
@ -156,8 +164,11 @@ impl MacEventLoop {
|
||||||
let error_code = unsafe { ui_eventloop(callback) };
|
let error_code = unsafe { ui_eventloop(callback) };
|
||||||
|
|
||||||
if error_code <= 0 {
|
if error_code <= 0 {
|
||||||
panic!("MacEventLoop exited with <= 0 code")
|
error!("MacEventLoop exited with <= 0 code");
|
||||||
|
return Err(MacUIError::InternalError().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,8 +181,10 @@ impl MacRemote {
|
||||||
pub(crate) fn new(icon_indexes: HashMap<TrayIcon, usize>) -> Self {
|
pub(crate) fn new(icon_indexes: HashMap<TrayIcon, usize>) -> Self {
|
||||||
Self { icon_indexes }
|
Self { icon_indexes }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_tray_icon(&self, icon: TrayIcon) {
|
impl UIRemote for MacRemote {
|
||||||
|
fn update_tray_icon(&self, icon: TrayIcon) {
|
||||||
if let Some(index) = self.icon_indexes.get(&icon) {
|
if let Some(index) = self.icon_indexes.get(&icon) {
|
||||||
unsafe { ui_update_tray_icon((*index) as i32) }
|
unsafe { ui_update_tray_icon((*index) as i32) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -179,7 +192,7 @@ impl MacRemote {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_notification(&self, message: &str) {
|
fn show_notification(&self, message: &str) {
|
||||||
let c_string = CString::new(message);
|
let c_string = CString::new(message);
|
||||||
match c_string {
|
match c_string {
|
||||||
Ok(message) => unsafe { ui_show_notification(message.as_ptr(), 3.0) },
|
Ok(message) => unsafe { ui_show_notification(message.as_ptr(), 3.0) },
|
||||||
|
@ -189,7 +202,7 @@ impl MacRemote {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_context_menu(&self, menu: &Menu) {
|
fn show_context_menu(&self, menu: &Menu) {
|
||||||
match menu.to_json() {
|
match menu.to_json() {
|
||||||
Ok(payload) => {
|
Ok(payload) => {
|
||||||
let c_string = CString::new(payload);
|
let c_string = CString::new(payload);
|
||||||
|
@ -224,3 +237,9 @@ impl From<RawUIEvent> for Option<UIEvent> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum MacUIError {
|
||||||
|
#[error("internal error")]
|
||||||
|
InternalError(),
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user