1use rustc_hash::FxHashMap;
2
3use crate::{HotkeyId, HotkeyManager, HotkeyManagerImpl, ModifiersKey, VirtualKey};
4use core::fmt;
5use std::sync::{
6 atomic::{AtomicBool, Ordering},
7 Arc, Mutex,
8};
9
10#[derive(Clone)]
11pub struct GlobalHotkey<T> {
12 key: VirtualKey,
13 modifiers: Option<Vec<ModifiersKey>>,
14 extras: Option<Vec<VirtualKey>>,
15 action: Option<Arc<Mutex<dyn Fn() -> T + Send + 'static>>>, }
17
18impl<T> fmt::Debug for GlobalHotkey<T>
19where
20 T: fmt::Debug, {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 f.debug_struct("GlobalHotkey")
24 .field("key", &self.key)
25 .field("modifiers", &self.modifiers)
26 .field("extras", &self.extras)
27 .field(
28 "action",
29 &self.action.as_ref().map_or_else(
30 || "None".to_string(),
31 |_| "Some(Fn() -> T + Send)".to_string(),
32 ),
33 )
34 .finish()
35 }
36}
37
38#[derive(Clone, Debug)]
39pub struct GlobalHotkeyManager<T: Send + 'static> {
40 hotkeys: Arc<Mutex<FxHashMap<String, GlobalHotkey<T>>>>,
41 manager: Arc<Mutex<HotkeyManager<T>>>,
42 listening: Arc<AtomicBool>,
43 key_ids: Arc<Mutex<Vec<HotkeyId>>>,
44}
45
46impl<T: Send + 'static> GlobalHotkey<T> {
47 pub fn set_action(&mut self, action: impl Fn() -> T + Send + 'static) {
48 self.action = Some(Arc::new(Mutex::new(action)));
49 }
50}
51
52impl<T: Send + 'static> Default for GlobalHotkeyManager<T> {
53 fn default() -> Self {
54 let mut hkm = HotkeyManager::new();
55 hkm.set_no_repeat(false);
56 Self {
57 manager: Arc::new(Mutex::new(hkm)),
58 listening: Arc::new(AtomicBool::new(false)),
59 hotkeys: Arc::new(Mutex::new(FxHashMap::default())),
60 key_ids: Arc::new(Mutex::new(Vec::new())),
61 }
62 }
63}
64
65pub trait GlobalHotkeyManagerImpl<T> {
66 fn new() -> Self;
67 fn register_hotkey(
68 &self,
69 name: String,
70 key: VirtualKey,
71 modifiers: Option<Vec<ModifiersKey>>,
72 extras: Option<Vec<VirtualKey>>,
73 callback: Option<impl Fn() -> T + Send + 'static>,
74 );
75 fn add_hotkey(&self, name: String, hotkey: GlobalHotkey<T>);
76 fn remove_hotkey(&self, name: String) -> Option<GlobalHotkey<T>>;
77 fn start(&self);
78 fn stop(&self) -> bool;
79 #[cfg(feature = "upcoming_update")]
80 fn update(&mut self);
81}
82
83impl<T: Send + 'static> GlobalHotkeyManagerImpl<T> for GlobalHotkeyManager<T> {
84 fn new() -> Self {
85 Self::default()
86 }
87
88 fn register_hotkey(
89 &self,
90 name: String,
91 key: VirtualKey,
92 modifiers: Option<Vec<ModifiersKey>>,
93 extras: Option<Vec<VirtualKey>>,
94 callback: Option<impl Fn() -> T + Send + 'static>,
95 ) {
96 let mut hotkeys = self.hotkeys.lock().unwrap();
97 hotkeys.insert(
98 name,
99 GlobalHotkey {
100 key,
101 modifiers,
102 extras,
103 action: callback.map(|cb| {
104 Arc::new(Mutex::new(cb)) as Arc<Mutex<dyn Fn() -> T + Send + 'static>>
105 }),
106 },
107 );
108 }
109
110 fn add_hotkey(&self, name: String, hotkey: GlobalHotkey<T>) {
111 let mut hotkeys = self.hotkeys.lock().unwrap();
112 hotkeys.insert(name, hotkey);
113 }
114
115 fn remove_hotkey(&self, key: String) -> Option<GlobalHotkey<T>> {
116 let mut hotkeys = self.hotkeys.lock().unwrap();
117 hotkeys.remove(&key)
118 }
119
120 #[cfg(feature = "upcoming_update")]
121 fn update(&mut self) {
122 let listening = self.listening.clone();
123 let hotkey_manager = self.manager.clone();
124
125 let mut hotkey_manager_mut = hotkey_manager.lock().unwrap();
127 let hotkeys = self.hotkeys.lock().unwrap();
128 let mut key_ids = self.key_ids.lock().unwrap();
129
130 if let Err(e) = hotkey_manager_mut.unregister_all() {
131 eprintln!("failed to unregister all keybindings: {}", e);
132 }
133
134 let handle = hotkey_manager_mut.interrupt_handle();
135 handle.interrupt();
136 key_ids.clear();
137
138 let mut new_hk = HotkeyManager::new();
139 new_hk.set_no_repeat(false);
140 let new_hkm = Arc::new(Mutex::new(new_hk));
141 self.manager = new_hkm.clone();
142
143 let hotkey_manager = self.manager.clone();
144 let mut hotkey_manager_mut = hotkey_manager.lock().unwrap();
145
146 for hotkey in hotkeys.values() {
148 let action = hotkey.action.clone();
149 let result = if let Some(action) = action {
150 hotkey_manager_mut.register_extrakeys(
152 hotkey.key,
153 hotkey.modifiers.as_deref(),
154 hotkey.extras.as_deref(),
155 Some(move || {
156 let action = action.clone();
157 let action = action.lock().unwrap();
158 action()
159 }),
160 )
161 } else {
162 hotkey_manager_mut.register_extrakeys(
164 hotkey.key,
165 hotkey.modifiers.as_deref(),
166 hotkey.extras.as_deref(),
167 None::<fn() -> T>,
168 )
169 };
170
171 match result {
172 Ok(hotkey_id) => key_ids.push(hotkey_id),
173 Err(e) => {
174 eprintln!("failed to register keybinding {:?}: {}", hotkey.key, e);
175 }
176 }
177 }
178
179 let hkm = hotkey_manager.clone();
180
181 std::thread::spawn(move || {
182 while listening.load(Ordering::SeqCst) {
184 hkm.lock().unwrap().event_loop();
185 }
186 });
187 }
188
189 fn start(&self) {
190 if self.listening.load(Ordering::SeqCst) {
191 eprintln!("already listening for hotkeys.");
192 return;
193 }
194
195 let hotkey_manager = self.manager.clone();
196 let listening = self.listening.clone();
197
198 listening.store(true, Ordering::SeqCst);
199
200 let mut hotkey_manager_mut = hotkey_manager.lock().unwrap();
202 let hotkeys = self.hotkeys.lock().unwrap();
203 let mut key_ids = self.key_ids.lock().unwrap();
204
205 for hotkey in hotkeys.values() {
207 let action = hotkey.action.clone();
208 let result = if let Some(action) = action {
209 hotkey_manager_mut.register_extrakeys(
211 hotkey.key,
212 hotkey.modifiers.as_deref(),
213 hotkey.extras.as_deref(),
214 Some(move || {
215 let action = action.clone();
216 let action = action.lock().unwrap();
217 action()
218 }),
219 )
220 } else {
221 hotkey_manager_mut.register_extrakeys(
223 hotkey.key,
224 hotkey.modifiers.as_deref(),
225 hotkey.extras.as_deref(),
226 None::<fn() -> T>,
227 )
228 };
229
230 match result {
231 Ok(hotkey_id) => key_ids.push(hotkey_id),
232 Err(e) => {
233 eprintln!("failed to register keybinding {:?}: {}", hotkey.key, e);
234 }
235 }
236 }
237
238 let hkm = hotkey_manager.clone();
239
240 std::thread::spawn(move || {
241 while listening.load(Ordering::SeqCst) {
243 hkm.lock().unwrap().event_loop();
244 }
245 });
246 }
247
248 fn stop(&self) -> bool {
249 if !self.listening.load(Ordering::SeqCst) {
250 return false;
251 }
252
253 self.listening.store(false, Ordering::SeqCst);
254
255 true
256 }
257}
258
259#[derive(Debug)]
260pub enum HotKeyParseError {
261 UnsupportedKey(String),
262 EmptyToken(String),
263 InvalidFormat(String),
264}
265
266impl std::fmt::Display for HotKeyParseError {
267 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
268 match *self {
269 HotKeyParseError::UnsupportedKey(ref key) => {
270 write!(
271 f,
272 "Couldn't recognize \"{}\" as a valid key for hotkey",
273 key
274 )
275 }
276 HotKeyParseError::EmptyToken(ref token) => {
277 write!(f, "Found empty token while parsing hotkey: {}", token)
278 }
279 HotKeyParseError::InvalidFormat(ref format) => {
280 write!(
281 f,
282 "Invalid hotkey format: \"{}\", a hotkey should have the modifiers first and only one main key, for example: \"Shift + Alt + K\"",
283 format
284 )
285 }
286 }
287 }
288}
289
290impl std::error::Error for HotKeyParseError {
291 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
292 None
294 }
295}
296
297impl<T: Send + 'static> TryInto<GlobalHotkey<T>> for &str {
298 type Error = HotKeyParseError;
299
300 fn try_into(self) -> Result<GlobalHotkey<T>, Self::Error> {
301 let tokens = self.split('+').collect::<Vec<&str>>();
302 let mut modifiers: Vec<ModifiersKey> = Vec::new();
303 let mut key = None;
304 let mut extras: Vec<VirtualKey> = Vec::new();
305
306 match tokens.len() {
307 1 => {
308 key = Some(
310 VirtualKey::try_from(tokens[0].trim())
311 .map_err(|e| HotKeyParseError::UnsupportedKey(e.to_string()))?,
312 );
313 }
314 _ => {
315 let mut found_key = false;
316
317 for raw in tokens {
318 let token = raw.trim();
319
320 if token.is_empty() {
321 return Err(HotKeyParseError::EmptyToken(self.to_string()));
322 }
323
324 if found_key {
326 let extra_key = VirtualKey::try_from(token)
327 .map_err(|e| HotKeyParseError::UnsupportedKey(e.to_string()))?;
328 extras.push(extra_key);
329 } else {
330 if key.is_some() {
331 return Err(HotKeyParseError::InvalidFormat(self.to_string()));
332 }
333
334 let temp_key = VirtualKey::try_from(token)
335 .map_err(|e| HotKeyParseError::UnsupportedKey(e.to_string()))?;
336
337 if let Ok(modifier) = temp_key.try_into() {
339 modifiers.push(modifier);
340 } else {
341 key = Some(temp_key);
343 found_key = true; }
345 }
346 }
347 }
348 }
349
350 let key = key.ok_or_else(|| HotKeyParseError::InvalidFormat(self.to_string()))?;
352
353 Ok(GlobalHotkey {
354 key,
355 modifiers: if modifiers.is_empty() {
356 None
357 } else {
358 Some(modifiers)
359 },
360 extras: if extras.is_empty() {
361 None
362 } else {
363 Some(extras)
364 },
365 action: None, })
367 }
368}