feat(shortcuts): add screenshot shortcut management and registration

This commit is contained in:
Dmytro Kondakov
2025-04-22 21:36:37 +02:00
parent e0fadb2c66
commit 8850b00595
2 changed files with 118 additions and 10 deletions

View File

@ -22,6 +22,9 @@ pub fn run() {
shortcut::change_shortcut,
shortcut::unregister_shortcut,
shortcut::get_current_shortcut,
shortcut::change_screenshot_shortcut,
shortcut::unregister_screenshot_shortcut,
shortcut::get_current_screenshot_shortcut,
])
.setup(|app| {
setup_window(app)?;

View File

@ -11,14 +11,19 @@ use tauri_plugin_store::StoreExt;
/// Constants for Tauri store configuration
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
const HAYSTACK_GLOBAL_SHORTCUT: &str = "haystack_global_shortcut"; // Key for storing the toggle window shortcut
const HAYSTACK_SCREENSHOT_SHORTCUT: &str = "haystack_screenshot_shortcut"; // Key for storing the screenshot shortcut
/// Platform-specific default shortcuts
#[cfg(target_os = "macos")]
const DEFAULT_SHORTCUT: &str = "command+shift+k"; // macOS uses Command key
#[cfg(target_os = "macos")]
const DEFAULT_SCREENSHOT_SHORTCUT: &str = "command+shift+p"; // macOS screenshot shortcut
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_SHORTCUT: &str = "ctrl+shift+k"; // Windows/Linux use Ctrl key
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_SCREENSHOT_SHORTCUT: &str = "ctrl+shift+p"; // Windows/Linux screenshot shortcut
/// Initializes the global shortcut during application startup.
/// This function:
@ -32,9 +37,8 @@ pub fn enable_shortcut(app: &App) {
.store(HAYSTACK_TAURI_STORE)
.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) {
// Parse the stored shortcut string
// Initialize toggle window shortcut
let toggle_shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_GLOBAL_SHORTCUT) {
let stored_shortcut_str = match stored_shortcut {
JsonValue::String(str) => str,
unexpected_type => panic!(
@ -46,7 +50,6 @@ pub fn enable_shortcut(app: &App) {
.parse::<Shortcut>()
.expect("Stored shortcut string should be valid")
} else {
// Store and use the default shortcut
store.set(
HAYSTACK_GLOBAL_SHORTCUT,
JsonValue::String(DEFAULT_SHORTCUT.to_string()),
@ -56,8 +59,31 @@ pub fn enable_shortcut(app: &App) {
.expect("Default shortcut should be valid")
};
// Register the determined shortcut
register_shortcut_upon_start(app, shortcut);
// Initialize screenshot shortcut
let screenshot_shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_SCREENSHOT_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
),
};
stored_shortcut_str
.parse::<Shortcut>()
.expect("Stored shortcut string should be valid")
} else {
store.set(
HAYSTACK_SCREENSHOT_SHORTCUT,
JsonValue::String(DEFAULT_SCREENSHOT_SHORTCUT.to_string()),
);
DEFAULT_SCREENSHOT_SHORTCUT
.parse::<Shortcut>()
.expect("Default screenshot shortcut should be valid")
};
// Register both shortcuts
register_shortcut_upon_start(app, toggle_shortcut, screenshot_shortcut);
}
/// Returns the currently configured shortcut as a string.
@ -152,7 +178,11 @@ fn register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
/// 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,
toggle_shortcut: Shortcut,
screenshot_shortcut: Shortcut,
) {
let window = app
.get_webview_window("main")
.expect("webview to be defined");
@ -161,16 +191,22 @@ fn register_shortcut_upon_start(app: &App, shortcut: Shortcut) {
.plugin(
tauri_plugin_global_shortcut::Builder::new()
.with_handler(move |app, scut, event| {
if scut == &shortcut {
if scut == &toggle_shortcut {
if let ShortcutState::Pressed = event.state() {
handle_window_visibility(app, &window);
}
} else if scut == &screenshot_shortcut {
if let ShortcutState::Pressed = event.state() {
// TODO: Implement screenshot functionality
println!("Screenshot shortcut pressed");
}
}
})
.build(),
)
.unwrap();
app.global_shortcut().register(shortcut).unwrap();
app.global_shortcut().register(toggle_shortcut).unwrap();
app.global_shortcut().register(screenshot_shortcut).unwrap();
}
/// Retrieves the currently stored shortcut from the persistent store.
@ -191,3 +227,72 @@ fn get_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
),
}
}
#[tauri::command]
pub fn get_current_screenshot_shortcut<R: Runtime>(app: AppHandle<R>) -> Result<String, String> {
Ok(get_screenshot_shortcut_from_store(&app))
}
#[tauri::command]
pub fn unregister_screenshot_shortcut<R: Runtime>(app: AppHandle<R>) {
let shortcut_str = get_screenshot_shortcut_from_store(&app);
let shortcut = shortcut_str
.parse::<Shortcut>()
.expect("Stored shortcut string should be valid");
app.global_shortcut()
.unregister(shortcut)
.expect("Failed to unregister screenshot shortcut")
}
#[tauri::command]
pub fn change_screenshot_shortcut<R: Runtime>(
app: AppHandle<R>,
_window: tauri::Window<R>,
key: String,
) -> Result<(), String> {
let shortcut = match key.parse::<Shortcut>() {
Ok(shortcut) => shortcut,
Err(_) => return Err(format!("Invalid screenshot shortcut {}", key)),
};
let store = app
.get_store(HAYSTACK_TAURI_STORE)
.expect("Store should already be loaded or created");
store.set(HAYSTACK_SCREENSHOT_SHORTCUT, JsonValue::String(key));
register_screenshot_shortcut(&app, shortcut);
Ok(())
}
fn register_screenshot_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
app.global_shortcut()
.on_shortcut(shortcut, move |_app, scut, event| {
if scut == &shortcut {
if let ShortcutState::Pressed = event.state() {
// TODO: Implement screenshot functionality
println!("Screenshot shortcut pressed");
}
}
})
.map_err(|err| format!("Failed to register new screenshot shortcut '{}'", err))
.unwrap();
}
fn get_screenshot_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
let store = app
.get_store(HAYSTACK_TAURI_STORE)
.expect("Store should already be loaded or created");
match store
.get(HAYSTACK_SCREENSHOT_SHORTCUT)
.expect("Screenshot shortcut should already be stored")
{
JsonValue::String(str) => str,
unexpected_type => panic!(
"Haystack shortcuts should be stored as strings, found type: {} ",
unexpected_type
),
}
}