Rewild Your Web
web browser dweb
at main 64 lines 2.3 kB view raw
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}