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 thiserror::Error;
|
||||
|
||||
use crate::event::Status::*;
|
||||
use crate::{Source, SourceCallback, event::Status::*};
|
||||
use crate::event::Variant::*;
|
||||
use crate::event::{InputEvent, Key, KeyboardEvent, Variant};
|
||||
use crate::event::{Key::*, MouseButton, MouseEvent};
|
||||
|
@ -123,7 +123,7 @@ impl Source for CocoaSource {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn eventloop(&self, event_callback: SourceCallback) {
|
||||
fn eventloop(&self, event_callback: SourceCallback) -> Result<()> {
|
||||
if let Some(receiver) = self.receiver.borrow() {
|
||||
loop {
|
||||
let event = receiver.recv();
|
||||
|
@ -138,8 +138,11 @@ impl Source for CocoaSource {
|
|||
}
|
||||
}
|
||||
} 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 thiserror::Error;
|
||||
|
||||
use crate::{keys, Injector};
|
||||
use crate::{InjectionOptions, Injector, keys};
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
#[link(name = "espansoinject", kind = "static")]
|
||||
|
@ -60,7 +60,7 @@ impl 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)?;
|
||||
unsafe {
|
||||
inject_string(c_string.as_ptr());
|
||||
|
@ -68,21 +68,21 @@ impl Injector for MacInjector {
|
|||
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)?;
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
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)?;
|
||||
|
||||
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(())
|
||||
|
|
|
@ -55,9 +55,10 @@ pub fn create_ui(options: UIOptions) -> Result<(Box<dyn UIRemote>, Box<dyn UIEve
|
|||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn create_ui(options: UIOptions) -> Result<(Box<dyn UIRemote>, Box<dyn UIEventLoop>)> {
|
||||
let (remote, eventloop) = linux::create(linux::LinuxUIOptions {
|
||||
notification_icon_path: options.notification_icon_path.expect("missing notification icon path")
|
||||
});
|
||||
let (remote, eventloop) = mac::create(mac::MacUIOptions {
|
||||
show_icon: options.show_icon,
|
||||
icon_paths: &options.icon_paths,
|
||||
})?;
|
||||
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 anyhow::Result;
|
||||
use thiserror::Error;
|
||||
use lazycell::LazyCell;
|
||||
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.
|
||||
const MAX_FILE_PATH: usize = 1024;
|
||||
|
@ -63,7 +65,7 @@ pub struct MacUIOptions<'a> {
|
|||
pub icon_paths: &'a Vec<(TrayIcon, String)>,
|
||||
}
|
||||
|
||||
pub fn create(options: MacUIOptions) -> (MacRemote, MacEventLoop) {
|
||||
pub fn create(options: MacUIOptions) -> Result<(MacRemote, MacEventLoop)> {
|
||||
// Validate icons
|
||||
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");
|
||||
|
@ -80,7 +82,7 @@ pub fn create(options: MacUIOptions) -> (MacRemote, MacEventLoop) {
|
|||
let eventloop = MacEventLoop::new(icons, options.show_icon);
|
||||
let remote = MacRemote::new(icon_indexes);
|
||||
|
||||
(remote, eventloop)
|
||||
Ok((remote, eventloop))
|
||||
}
|
||||
|
||||
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
|
||||
let mut icon_paths: [[u8; 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()) {
|
||||
let c_path = CString::new(self.icons[i].clone())
|
||||
.expect("unable to create CString for UI tray icon path");
|
||||
let c_path = CString::new(self.icons[i].clone())?;
|
||||
let len = min(c_path.as_bytes().len(), MAX_FILE_PATH - 1);
|
||||
icon_path[0..len].clone_from_slice(&c_path.as_bytes()[..len]);
|
||||
}
|
||||
|
@ -128,9 +133,11 @@ impl MacEventLoop {
|
|||
._init_thread_id
|
||||
.fill(std::thread::current().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()
|
||||
if let Some(init_id) = self._init_thread_id.borrow() {
|
||||
if init_id != &std::thread::current().id() {
|
||||
|
@ -139,7 +146,8 @@ impl MacEventLoop {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -156,8 +164,11 @@ impl MacEventLoop {
|
|||
let error_code = unsafe { ui_eventloop(callback) };
|
||||
|
||||
if error_code <= 0 {
|
||||
panic!("MacEventLoop exited with <= 0 code")
|
||||
error!("MacEventLoop exited with <= 0 code");
|
||||
return Err(MacUIError::InternalError().into())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,9 +180,11 @@ pub struct MacRemote {
|
|||
impl MacRemote {
|
||||
pub(crate) fn new(icon_indexes: HashMap<TrayIcon, usize>) -> Self {
|
||||
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) {
|
||||
unsafe { ui_update_tray_icon((*index) as i32) }
|
||||
} 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);
|
||||
match c_string {
|
||||
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() {
|
||||
Ok(payload) => {
|
||||
let c_string = CString::new(payload);
|
||||
|
@ -224,3 +237,9 @@ impl From<RawUIEvent> for Option<UIEvent> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MacUIError {
|
||||
#[error("internal error")]
|
||||
InternalError(),
|
||||
}
|
Loading…
Reference in New Issue
Block a user