use tauri::App; use tauri::AppHandle; use tauri::Emitter; use tauri::Manager; use tauri::Runtime; use tauri_plugin_global_shortcut::GlobalShortcutExt; use tauri_plugin_global_shortcut::Shortcut; use tauri_plugin_global_shortcut::ShortcutState; use tauri_plugin_store::JsonValue; use tauri_plugin_store::StoreExt; /// Name of the Tauri storage const HAYSTACK_TAURI_STORE: &str = "haystack_tauri_store"; /// Key for storing global shortcuts const HAYSTACK_GLOBAL_SHORTCUT: &str = "haystack_global_shortcut"; /// Default shortcut for macOS #[cfg(target_os = "macos")] const DEFAULT_SHORTCUT: &str = "command+shift+k"; /// Default shortcut for Windows and Linux #[cfg(any(target_os = "windows", target_os = "linux"))] const DEFAULT_SHORTCUT: &str = "ctrl+shift+k"; /// Set shortcut during application startup pub fn enable_shortcut(app: &App) { let store = app .store(HAYSTACK_TAURI_STORE) .expect("Creating the store should not fail"); // Use stored shortcut if it exists if let Some(stored_shortcut) = store.get(HAYSTACK_GLOBAL_SHORTCUT) { let stored_shortcut_str = match stored_shortcut { JsonValue::String(str) => str, unexpected_type => panic!( "Haystack shortcuts should be stored as strings, found type: {} ", unexpected_type ), }; let stored_shortcut = stored_shortcut_str .parse::() .expect("Stored shortcut string should be valid"); _register_shortcut_upon_start(app, stored_shortcut); // Register stored shortcut } else { // Use default shortcut if none is stored store.set( HAYSTACK_GLOBAL_SHORTCUT, JsonValue::String(DEFAULT_SHORTCUT.to_string()), ); let default_shortcut = DEFAULT_SHORTCUT .parse::() .expect("Default shortcut should be valid"); _register_shortcut_upon_start(app, default_shortcut); // Register default shortcut } } /// Get the current stored shortcut as a string #[tauri::command] pub fn get_current_shortcut(app: AppHandle) -> Result { let shortcut = _get_shortcut(&app); Ok(shortcut) } /// Unregister the current shortcut in Tauri #[tauri::command] pub fn unregister_shortcut(app: AppHandle) { let shortcut_str = _get_shortcut(&app); let shortcut = shortcut_str .parse::() .expect("Stored shortcut string should be valid"); // Unregister the shortcut app.global_shortcut() .unregister(shortcut) .expect("Failed to unregister shortcut") } /// Change the global shortcut #[tauri::command] pub fn change_shortcut( app: AppHandle, _window: tauri::Window, key: String, ) -> Result<(), String> { println!("Key: {}", key); let shortcut = match key.parse::() { Ok(shortcut) => shortcut, Err(_) => return Err(format!("Invalid shortcut {}", key)), }; // Store the new shortcut let store = app .get_store(HAYSTACK_TAURI_STORE) .expect("Store should already be loaded or created"); store.set(HAYSTACK_GLOBAL_SHORTCUT, JsonValue::String(key)); // Register the new shortcut _register_shortcut(&app, shortcut); Ok(()) } /// Helper function to register a shortcut, primarily for updating shortcuts fn _register_shortcut(app: &AppHandle, shortcut: Shortcut) { let main_window = app.get_webview_window("main").unwrap(); // Register global shortcut and define its behavior app.global_shortcut() .on_shortcut(shortcut, move |app, scut, event| { if scut == &shortcut { if let ShortcutState::Pressed = event.state() { // Toggle window visibility if main_window.is_visible().unwrap() { main_window.hide().unwrap(); // Hide window } else { main_window.show().unwrap(); // Show window main_window.set_focus().unwrap(); // Focus window // Emit focus-search event app.emit("focus-search", ()).unwrap(); } } } }) .map_err(|err| format!("Failed to register new shortcut '{}'", err)) .unwrap(); } /// Helper function to register shortcuts during application startup fn _register_shortcut_upon_start(app: &App, shortcut: Shortcut) { let window = app.get_webview_window("main").unwrap(); // Initialize global shortcut and set its handler app.handle() .plugin( tauri_plugin_global_shortcut::Builder::new() .with_handler(move |app, scut, event| { if scut == &shortcut { if let ShortcutState::Pressed = event.state() { // Toggle window visibility if window.is_visible().unwrap() { window.hide().unwrap(); // Hide window } else { window.show().unwrap(); // Show window window.set_focus().unwrap(); // Focus window // Emit focus-search event app.emit("focus-search", ()).unwrap(); } } } }) .build(), ) .unwrap(); app.global_shortcut().register(shortcut).unwrap(); // Register global shortcut } /// Retrieve the stored global shortcut as a string pub fn _get_shortcut(app: &AppHandle) -> String { let store = app .get_store(HAYSTACK_TAURI_STORE) .expect("Store should already be loaded or created"); match store .get(HAYSTACK_GLOBAL_SHORTCUT) .expect("Shortcut should already be stored") { JsonValue::String(str) => str, unexpected_type => panic!( "Haystack shortcuts should be stored as strings, found type: {} ", unexpected_type ), } }