@@ -20,11 +20,11 @@ use std::{
20
20
sync:: { Arc , Mutex } ,
21
21
} ;
22
22
23
+ use global_hotkey:: GlobalHotKeyEvent ;
23
24
pub use global_hotkey:: {
24
25
hotkey:: { Code , HotKey as Shortcut , Modifiers } ,
25
26
GlobalHotKeyEvent as ShortcutEvent , HotKeyState as ShortcutState ,
26
27
} ;
27
- use global_hotkey:: { GlobalHotKeyEvent , GlobalHotKeyManager } ;
28
28
use serde:: Serialize ;
29
29
use tauri:: {
30
30
ipc:: Channel ,
@@ -60,13 +60,33 @@ struct RegisteredShortcut<R: Runtime> {
60
60
handler : Option < Arc < HandlerFn < R > > > ,
61
61
}
62
62
63
+ struct GlobalHotKeyManager ( global_hotkey:: GlobalHotKeyManager ) ;
64
+
65
+ /// SAFETY: we ensure it is run on main thread only
66
+ unsafe impl Send for GlobalHotKeyManager { }
67
+ /// SAFETY: we ensure it is run on main thread only
68
+ unsafe impl Sync for GlobalHotKeyManager { }
69
+
63
70
pub struct GlobalShortcut < R : Runtime > {
64
71
#[ allow( dead_code) ]
65
72
app : AppHandle < R > ,
66
- manager : GlobalHotKeyManager ,
73
+ manager : Arc < GlobalHotKeyManager > ,
67
74
shortcuts : Arc < Mutex < HashMap < HotKeyId , RegisteredShortcut < R > > > > ,
68
75
}
69
76
77
+ macro_rules! run_main_thread {
78
+ ( $handle: expr, $manager: expr, |$m: ident| $ex: expr) => { {
79
+ let ( tx, rx) = std:: sync:: mpsc:: channel( ) ;
80
+ let manager = $manager. clone( ) ;
81
+ let task = move || {
82
+ let f = |$m: & GlobalHotKeyManager | $ex;
83
+ let _ = tx. send( f( & * manager) ) ;
84
+ } ;
85
+ $handle. run_on_main_thread( task) ?;
86
+ rx. recv( ) ?
87
+ } } ;
88
+ }
89
+
70
90
impl < R : Runtime > GlobalShortcut < R > {
71
91
fn register_internal < F : Fn ( & AppHandle < R > , & Shortcut , ShortcutEvent ) + Send + Sync + ' static > (
72
92
& self ,
@@ -75,8 +95,7 @@ impl<R: Runtime> GlobalShortcut<R> {
75
95
) -> Result < ( ) > {
76
96
let id = shortcut. id ( ) ;
77
97
let handler = handler. map ( |h| Arc :: new ( Box :: new ( h) as HandlerFn < R > ) ) ;
78
-
79
- self . manager . register ( shortcut) ?;
98
+ run_main_thread ! ( self . app, self . manager, |m| m. 0 . register( shortcut) ) ?;
80
99
self . shortcuts
81
100
. lock ( )
82
101
. unwrap ( )
@@ -95,7 +114,7 @@ impl<R: Runtime> GlobalShortcut<R> {
95
114
96
115
let mut shortcuts = self . shortcuts . lock ( ) . unwrap ( ) ;
97
116
for shortcut in hotkeys {
98
- self . manager . register ( shortcut) ?;
117
+ run_main_thread ! ( self . app , self . manager, |m| m . 0 . register( shortcut) ) ?;
99
118
shortcuts. insert (
100
119
shortcut. id ( ) ,
101
120
RegisteredShortcut {
@@ -167,7 +186,7 @@ impl<R: Runtime> GlobalShortcut<R> {
167
186
S :: Error : std:: error:: Error ,
168
187
{
169
188
let shortcut = try_into_shortcut ( shortcut) ?;
170
- self . manager . unregister ( shortcut) ?;
189
+ run_main_thread ! ( self . app , self . manager, |m| m . 0 . unregister( shortcut) ) ?;
171
190
self . shortcuts . lock ( ) . unwrap ( ) . remove ( & shortcut. id ( ) ) ;
172
191
Ok ( ( ) )
173
192
}
@@ -180,15 +199,19 @@ impl<R: Runtime> GlobalShortcut<R> {
180
199
where
181
200
T :: Error : std:: error:: Error ,
182
201
{
183
- let mut s = Vec :: new ( ) ;
202
+ let mut mapped_shortcuts = Vec :: new ( ) ;
184
203
for shortcut in shortcuts {
185
- s . push ( try_into_shortcut ( shortcut) ?) ;
204
+ mapped_shortcuts . push ( try_into_shortcut ( shortcut) ?) ;
186
205
}
187
206
188
- self . manager . unregister_all ( & s) ?;
207
+ {
208
+ let mapped_shortcuts = mapped_shortcuts. clone ( ) ;
209
+ #[ rustfmt:: skip]
210
+ run_main_thread ! ( self . app, self . manager, |m| m. 0 . unregister_all( & mapped_shortcuts) ) ?;
211
+ }
189
212
190
213
let mut shortcuts = self . shortcuts . lock ( ) . unwrap ( ) ;
191
- for s in s {
214
+ for s in mapped_shortcuts {
192
215
shortcuts. remove ( & s. id ( ) ) ;
193
216
}
194
217
@@ -200,9 +223,9 @@ impl<R: Runtime> GlobalShortcut<R> {
200
223
let mut shortcuts = self . shortcuts . lock ( ) . unwrap ( ) ;
201
224
let hotkeys = std:: mem:: take ( & mut * shortcuts) ;
202
225
let hotkeys = hotkeys. values ( ) . map ( |s| s. shortcut ) . collect :: < Vec < _ > > ( ) ;
203
- self . manager
204
- . unregister_all ( hotkeys. as_slice ( ) )
205
- . map_err ( Into :: into)
226
+ # [ rustfmt :: skip ]
227
+ let res = run_main_thread ! ( self . app , self . manager , |m| m . 0 . unregister_all( hotkeys. as_slice( ) ) ) ;
228
+ res . map_err ( Into :: into)
206
229
}
207
230
208
231
/// Determines whether the given shortcut is registered by this application or not.
@@ -375,7 +398,7 @@ impl<R: Runtime> Builder<R> {
375
398
is_registered,
376
399
] )
377
400
. setup ( move |app, _api| {
378
- let manager = GlobalHotKeyManager :: new ( ) ?;
401
+ let manager = global_hotkey :: GlobalHotKeyManager :: new ( ) ?;
379
402
let mut store = HashMap :: < HotKeyId , RegisteredShortcut < R > > :: new ( ) ;
380
403
for shortcut in shortcuts {
381
404
manager. register ( shortcut) ?;
@@ -405,7 +428,7 @@ impl<R: Runtime> Builder<R> {
405
428
406
429
app. manage ( GlobalShortcut {
407
430
app : app. clone ( ) ,
408
- manager,
431
+ manager : Arc :: new ( GlobalHotKeyManager ( manager ) ) ,
409
432
shortcuts,
410
433
} ) ;
411
434
Ok ( ( ) )
0 commit comments