feat(shortcuts): improve global shortcut management and documentation

This commit is contained in:
2025-04-22 21:00:48 +02:00
parent 2b022c31cb
commit 2eb346bb6a

View File

@ -9,27 +9,32 @@ use tauri_plugin_global_shortcut::ShortcutState;
use tauri_plugin_store::JsonValue; use tauri_plugin_store::JsonValue;
use tauri_plugin_store::StoreExt; use tauri_plugin_store::StoreExt;
/// Name of the Tauri storage /// Constants for Tauri store configuration
const HAYSTACK_TAURI_STORE: &str = "haystack_tauri_store"; const HAYSTACK_TAURI_STORE: &str = "haystack_tauri_store"; // Name of the persistent store
const HAYSTACK_GLOBAL_SHORTCUT: &str = "haystack_global_shortcut"; // Key for storing the shortcut
/// Key for storing global shortcuts /// Platform-specific default shortcuts
const HAYSTACK_GLOBAL_SHORTCUT: &str = "haystack_global_shortcut";
/// Default shortcut for macOS
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
const DEFAULT_SHORTCUT: &str = "command+shift+k"; const DEFAULT_SHORTCUT: &str = "command+shift+k"; // macOS uses Command key
/// Default shortcut for Windows and Linux
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_SHORTCUT: &str = "ctrl+shift+k"; const DEFAULT_SHORTCUT: &str = "ctrl+shift+k"; // Windows/Linux use Ctrl key
/// Set shortcut during application startup /// Initializes the global shortcut during application startup.
/// This function:
/// 1. Checks if a shortcut is already stored
/// 2. Uses the stored shortcut if it exists
/// 3. Falls back to the platform-specific default if no shortcut is stored
/// 4. Registers the shortcut with the system
pub fn enable_shortcut(app: &App) { pub fn enable_shortcut(app: &App) {
// Get or create the persistent store
let store = app let store = app
.store(HAYSTACK_TAURI_STORE) .store(HAYSTACK_TAURI_STORE)
.expect("Creating the store should not fail"); .expect("Creating the store should not fail");
// Determine which shortcut to use (stored or default)
let shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_GLOBAL_SHORTCUT) { let shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_GLOBAL_SHORTCUT) {
// Parse the stored shortcut string
let stored_shortcut_str = match stored_shortcut { let stored_shortcut_str = match stored_shortcut {
JsonValue::String(str) => str, JsonValue::String(str) => str,
unexpected_type => panic!( unexpected_type => panic!(
@ -41,6 +46,7 @@ pub fn enable_shortcut(app: &App) {
.parse::<Shortcut>() .parse::<Shortcut>()
.expect("Stored shortcut string should be valid") .expect("Stored shortcut string should be valid")
} else { } else {
// Store and use the default shortcut
store.set( store.set(
HAYSTACK_GLOBAL_SHORTCUT, HAYSTACK_GLOBAL_SHORTCUT,
JsonValue::String(DEFAULT_SHORTCUT.to_string()), JsonValue::String(DEFAULT_SHORTCUT.to_string()),
@ -50,16 +56,19 @@ pub fn enable_shortcut(app: &App) {
.expect("Default shortcut should be valid") .expect("Default shortcut should be valid")
}; };
// Register the determined shortcut
register_shortcut_upon_start(app, shortcut); register_shortcut_upon_start(app, shortcut);
} }
/// Get the current stored shortcut as a string /// Returns the currently configured shortcut as a string.
/// This is exposed as a Tauri command for the frontend to query.
#[tauri::command] #[tauri::command]
pub fn get_current_shortcut<R: Runtime>(app: AppHandle<R>) -> Result<String, String> { pub fn get_current_shortcut<R: Runtime>(app: AppHandle<R>) -> Result<String, String> {
Ok(get_shortcut_from_store(&app)) Ok(get_shortcut_from_store(&app))
} }
/// Unregister the current shortcut in Tauri /// Unregisters the current global shortcut from the system.
/// This is exposed as a Tauri command for the frontend to trigger.
#[tauri::command] #[tauri::command]
pub fn unregister_shortcut<R: Runtime>(app: AppHandle<R>) { pub fn unregister_shortcut<R: Runtime>(app: AppHandle<R>) {
let shortcut_str = get_shortcut_from_store(&app); let shortcut_str = get_shortcut_from_store(&app);
@ -72,7 +81,11 @@ pub fn unregister_shortcut<R: Runtime>(app: AppHandle<R>) {
.expect("Failed to unregister shortcut") .expect("Failed to unregister shortcut")
} }
/// Change the global shortcut /// Changes the global shortcut to a new key combination.
/// This function:
/// 1. Validates the new shortcut
/// 2. Stores it in the persistent store
/// 3. Registers it with the system
#[tauri::command] #[tauri::command]
pub fn change_shortcut<R: Runtime>( pub fn change_shortcut<R: Runtime>(
app: AppHandle<R>, app: AppHandle<R>,
@ -97,7 +110,11 @@ pub fn change_shortcut<R: Runtime>(
Ok(()) Ok(())
} }
/// Helper function to handle window visibility toggle /// Handles the window visibility toggle logic when the shortcut is pressed.
/// This function:
/// 1. Hides the window if it's visible
/// 2. Shows and focuses the window if it's hidden
/// 3. Emits a 'focus-search' event when showing the window
fn handle_window_visibility<R: Runtime>(app: &AppHandle<R>, window: &tauri::WebviewWindow<R>) { fn handle_window_visibility<R: Runtime>(app: &AppHandle<R>, window: &tauri::WebviewWindow<R>) {
if window.is_visible().unwrap() { if window.is_visible().unwrap() {
window.hide().unwrap(); window.hide().unwrap();
@ -108,7 +125,12 @@ fn handle_window_visibility<R: Runtime>(app: &AppHandle<R>, window: &tauri::Webv
} }
} }
/// Helper function to register a shortcut, primarily for updating shortcuts /// Registers a new shortcut with the system.
/// This is used when changing shortcuts during runtime.
/// The function:
/// 1. Gets the main window
/// 2. Sets up the shortcut handler
/// 3. Registers the shortcut with the system
fn register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) { fn register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
let main_window = app.get_webview_window("main").unwrap(); let main_window = app.get_webview_window("main").unwrap();
@ -124,7 +146,12 @@ fn register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
.unwrap(); .unwrap();
} }
/// Helper function to register shortcuts during application startup /// Registers a shortcut during application startup.
/// This is similar to register_shortcut but handles the initial plugin setup.
/// The function:
/// 1. Gets the main window
/// 2. Sets up the global shortcut plugin
/// 3. Registers the shortcut with the system
fn register_shortcut_upon_start(app: &App, shortcut: Shortcut) { fn register_shortcut_upon_start(app: &App, shortcut: Shortcut) {
let window = app let window = app
.get_webview_window("main") .get_webview_window("main")
@ -146,7 +173,8 @@ fn register_shortcut_upon_start(app: &App, shortcut: Shortcut) {
app.global_shortcut().register(shortcut).unwrap(); app.global_shortcut().register(shortcut).unwrap();
} }
/// Retrieve the stored global shortcut as a string /// Retrieves the currently stored shortcut from the persistent store.
/// This is a helper function used by other functions to access the stored shortcut.
fn get_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String { fn get_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
let store = app let store = app
.get_store(HAYSTACK_TAURI_STORE) .get_store(HAYSTACK_TAURI_STORE)