win_hotkey/
thread_safe.rs

1use core::fmt;
2use std::marker::PhantomData;
3use std::sync::mpsc::channel;
4use std::sync::mpsc::Receiver;
5use std::sync::mpsc::Sender;
6use std::thread::spawn;
7use std::thread::JoinHandle;
8
9use crate::error::HotkeyError;
10use crate::keys::ModifiersKey;
11use crate::keys::VirtualKey;
12use crate::single_thread;
13use crate::HotkeyId;
14use crate::HotkeyManagerImpl;
15use crate::InterruptHandle;
16
17pub struct Hotkey<T: 'static> {
18    virtual_key: VirtualKey,
19    modifiers_key: Option<Vec<ModifiersKey>>,
20    extra_keys: Option<Vec<VirtualKey>>,
21    callback: Option<Box<dyn Fn() -> T + Send + 'static>>,
22}
23
24impl<T> fmt::Debug for Hotkey<T>
25where
26    T: fmt::Debug, // Ensures that T can be printed if necessary
27{
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.debug_struct("Hotkey")
30            .field("virtual_key", &self.virtual_key)
31            .field("modifiers_key", &self.modifiers_key)
32            .field("extra_keys", &self.extra_keys)
33            .field(
34                "callback",
35                &self.callback.as_ref().map_or_else(
36                    || "None".to_string(),
37                    |_| "Some(Fn() -> T + Send)".to_string(),
38                ),
39            ) // Handling Option more explicitly
40            .finish()
41    }
42}
43
44#[derive(Debug)]
45enum HotkeyMessage<T: 'static> {
46    Register(Sender<Result<HotkeyId, HotkeyError>>, Hotkey<T>),
47    HandleHotkey(Sender<Option<T>>),
48    Unregister(Sender<Result<(), HotkeyError>>, HotkeyId),
49    UnregisterAll(Sender<Result<(), HotkeyError>>),
50    EventLoop(Sender<()>),
51    InterruptHandle(Sender<InterruptHandle>),
52    Exit(Sender<()>),
53}
54
55#[derive(Debug)]
56pub struct HotkeyManager<T: 'static> {
57    no_repeat: bool,
58    _phantom: PhantomData<T>,
59    sender: Sender<HotkeyMessage<T>>,
60    backend_handle: Option<JoinHandle<()>>,
61}
62
63struct TSHotkeyManagerBackend<T: 'static> {
64    hkm: single_thread::HotkeyManager<T>,
65    receiver: Receiver<HotkeyMessage<T>>,
66}
67
68impl<T: 'static> HotkeyManager<T> {
69    /// Enable or disable the automatically applied `ModKey::NoRepeat` modifier. By default, this
70    /// option is set to `true` which causes all hotkey registration calls to add the `NoRepeat`
71    /// modifier, thereby disabling automatic retriggers of hotkeys when holding down the keys.
72    ///
73    /// When this option is disabled, the `ModKey::NoRepeat` can still be manually added while
74    /// registering hotkeys.
75    ///
76    /// Note: Setting this flag doesn't change previously registered hotkeys. It only applies to
77    /// registrations performed after calling this function.
78    pub fn set_no_repeat(&mut self, no_repeat: bool) {
79        self.no_repeat = no_repeat;
80    }
81}
82
83impl<T> TSHotkeyManagerBackend<T> {
84    /// Create a new HotkeyManager instance. To work around the same-thread limitation of the
85    /// windows event API, this will launch a new background thread to handle hotkey interactions.
86    ///
87    fn new(receiver: Receiver<HotkeyMessage<T>>) -> Self {
88        let mut hkm = single_thread::HotkeyManager::new();
89        hkm.set_no_repeat(false);
90        Self { hkm, receiver }
91    }
92
93    fn backend_loop(&mut self) {
94        while let Ok(msg) = self.receiver.recv() {
95            match msg {
96                HotkeyMessage::Register(channel, hotkey) => {
97                    let return_value = self.hkm.register_extrakeys(
98                        hotkey.virtual_key,
99                        hotkey.modifiers_key.as_deref(),
100                        hotkey.extra_keys.as_deref(),
101                        hotkey.callback,
102                    );
103                    channel.send(return_value).unwrap();
104                }
105                HotkeyMessage::HandleHotkey(channel) => {
106                    let return_value = self.hkm.handle_hotkey();
107                    channel.send(return_value).unwrap();
108                }
109                HotkeyMessage::Unregister(channel, hotkey_id) => {
110                    let return_value = self.hkm.unregister(hotkey_id);
111                    channel.send(return_value).unwrap();
112                }
113                HotkeyMessage::UnregisterAll(channel) => {
114                    let return_value = self.hkm.unregister_all();
115                    channel.send(return_value).unwrap();
116                }
117                HotkeyMessage::EventLoop(channel) => {
118                    self.hkm.event_loop();
119                    channel.send(()).unwrap();
120                }
121                HotkeyMessage::InterruptHandle(channel) => {
122                    let return_value = self.hkm.interrupt_handle();
123                    channel.send(return_value).unwrap();
124                }
125                HotkeyMessage::Exit(channel) => {
126                    channel.send(()).unwrap();
127                    return;
128                }
129            }
130        }
131    }
132}
133
134impl<T: 'static + Send> HotkeyManagerImpl<T> for HotkeyManager<T> {
135    fn new() -> Self {
136        let (sender, receiver) = channel();
137        let backend_handle = spawn(move || {
138            let mut backend = TSHotkeyManagerBackend::<T>::new(receiver);
139            backend.backend_loop();
140        });
141        Self {
142            no_repeat: true,
143            _phantom: PhantomData,
144            sender,
145            backend_handle: Some(backend_handle),
146        }
147    }
148
149    fn register_extrakeys(
150        &mut self,
151        virtual_key: VirtualKey,
152        modifiers_key: Option<&[ModifiersKey]>,
153        extra_keys: Option<&[VirtualKey]>,
154        callback: Option<impl Fn() -> T + Send + 'static>,
155    ) -> Result<HotkeyId, HotkeyError> {
156        let return_channel = channel();
157
158        let mut modifiers_key = modifiers_key.map(|keys| keys.to_vec());
159
160        if self.no_repeat {
161            modifiers_key
162                .get_or_insert_with(Vec::new)
163                .push(ModifiersKey::NoRepeat);
164        }
165
166        let callback_boxed = callback.map(|cb| Box::new(cb) as Box<dyn Fn() -> T + Send>);
167
168        let hotkey = Hotkey {
169            virtual_key,
170            modifiers_key,
171            extra_keys: extra_keys.map(|keys| keys.to_vec()),
172            callback: callback_boxed,
173        };
174        self.sender
175            .send(HotkeyMessage::Register(return_channel.0, hotkey))
176            .unwrap();
177        return_channel.1.recv().unwrap()
178    }
179
180    fn register(
181        &mut self,
182        virtual_key: VirtualKey,
183        modifiers_key: Option<&[ModifiersKey]>,
184        callback: Option<impl Fn() -> T + Send + 'static>,
185    ) -> Result<HotkeyId, HotkeyError> {
186        self.register_extrakeys(virtual_key, modifiers_key, None, callback)
187    }
188
189    fn unregister(&mut self, id: HotkeyId) -> Result<(), HotkeyError> {
190        let return_channel = channel();
191        self.sender
192            .send(HotkeyMessage::Unregister(return_channel.0, id))
193            .unwrap();
194        return_channel.1.recv().unwrap()
195    }
196
197    fn unregister_all(&mut self) -> Result<(), HotkeyError> {
198        let return_channel = channel();
199        self.sender
200            .send(HotkeyMessage::UnregisterAll(return_channel.0))
201            .unwrap();
202        return_channel.1.recv().unwrap()
203    }
204
205    fn handle_hotkey(&self) -> Option<T> {
206        let return_channel = channel();
207        self.sender
208            .send(HotkeyMessage::HandleHotkey(return_channel.0))
209            .unwrap();
210        return_channel.1.recv().unwrap()
211    }
212
213    fn event_loop(&self) {
214        let return_channel = channel();
215        self.sender
216            .send(HotkeyMessage::EventLoop(return_channel.0))
217            .unwrap();
218        return_channel.1.recv().unwrap()
219    }
220
221    fn interrupt_handle(&self) -> InterruptHandle {
222        let return_channel = channel();
223        self.sender
224            .send(HotkeyMessage::InterruptHandle(return_channel.0))
225            .unwrap();
226        return_channel.1.recv().unwrap()
227    }
228}
229
230impl<T> Drop for HotkeyManager<T> {
231    fn drop(&mut self) {
232        let return_channel = channel();
233        self.sender
234            .send(HotkeyMessage::Exit(return_channel.0))
235            .unwrap();
236        return_channel.1.recv().unwrap();
237        self.backend_handle.take().unwrap().join().unwrap();
238    }
239}