Rewild Your Web
web
browser
dweb
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3//! Global keyboard shortcut management.
4
5use global_hotkey::hotkey::{Code, HotKey, Modifiers};
6use global_hotkey::{GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState};
7use log::warn;
8use winit::event_loop::EventLoopProxy;
9
10use crate::WakerEvent;
11
12/// Manages global keyboard shortcuts.
13pub(crate) struct HotkeyManager {
14 _manager: GlobalHotKeyManager,
15 search_hotkey_id: u32,
16}
17
18impl HotkeyManager {
19 /// Creates a new hotkey manager and registers global shortcuts.
20 /// Returns None if the hotkey manager cannot be created or shortcuts cannot be registered.
21 pub fn new(event_loop_proxy: EventLoopProxy<WakerEvent>) -> Option<Self> {
22 let manager = match GlobalHotKeyManager::new() {
23 Ok(m) => m,
24 Err(e) => {
25 warn!("Failed to create global hotkey manager: {e}");
26 return None;
27 },
28 };
29
30 // Register Cmd+Shift+Space (macOS) or Ctrl+Shift+Space (others)
31 #[cfg(target_os = "macos")]
32 let modifiers = Modifiers::META | Modifiers::SHIFT;
33 #[cfg(not(target_os = "macos"))]
34 let modifiers = Modifiers::CONTROL | Modifiers::SHIFT;
35
36 let search_hotkey = HotKey::new(Some(modifiers), Code::Space);
37 let search_hotkey_id = search_hotkey.id();
38
39 if let Err(e) = manager.register(search_hotkey) {
40 warn!(
41 "Failed to register global hotkey (Ctrl/Cmd+Shift+Space): {e}. It may already be in use by another application."
42 );
43 return None;
44 }
45
46 // Set up event handler to forward hotkey events to the winit event loop.
47 // Only forward key press events, not release events.
48 GlobalHotKeyEvent::set_event_handler(Some(move |event: GlobalHotKeyEvent| {
49 if event.state == HotKeyState::Pressed {
50 let _ = event_loop_proxy.send_event(WakerEvent::GlobalHotkey(event.id));
51 }
52 }));
53
54 Some(Self {
55 _manager: manager,
56 search_hotkey_id,
57 })
58 }
59
60 /// Returns true if the given hotkey ID corresponds to the search hotkey.
61 pub fn is_search_hotkey(&self, id: u32) -> bool {
62 id == self.search_hotkey_id
63 }
64}