Handy/src-tauri/src/shortcut/handler.rs
johnpyp 7fdde63460
fix: transcription lock-up race condition & add small debounce (#824)
* fix: add TranscriptionState to prevent race conditions & add debounce

* refactor(transcription): replace state machine with actor coordinator

* some cleanup

* format

* minor cleanup

* format

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-16 22:18:50 +08:00

70 lines
2.4 KiB
Rust

//! Shared shortcut event handling logic
//!
//! This module contains the common logic for handling shortcut events,
//! used by both the Tauri and handy-keys implementations.
use log::warn;
use std::sync::Arc;
use tauri::{AppHandle, Manager};
use crate::actions::ACTION_MAP;
use crate::managers::audio::AudioRecordingManager;
use crate::settings::get_settings;
use crate::transcription_coordinator::is_transcribe_binding;
use crate::TranscriptionCoordinator;
/// Handle a shortcut event from either implementation.
///
/// This function contains the shared logic for:
/// - Looking up the action in ACTION_MAP
/// - Handling the cancel binding (only fires when recording)
/// - Handling push-to-talk mode (start on press, stop on release)
/// - Handling toggle mode (toggle state on press only)
///
/// # Arguments
/// * `app` - The Tauri app handle
/// * `binding_id` - The ID of the binding (e.g., "transcribe", "cancel")
/// * `hotkey_string` - The string representation of the hotkey
/// * `is_pressed` - Whether this is a key press (true) or release (false)
pub fn handle_shortcut_event(
app: &AppHandle,
binding_id: &str,
hotkey_string: &str,
is_pressed: bool,
) {
let settings = get_settings(app);
// Transcribe bindings are handled by the coordinator.
if is_transcribe_binding(binding_id) {
if let Some(coordinator) = app.try_state::<TranscriptionCoordinator>() {
coordinator.send_input(binding_id, hotkey_string, is_pressed, settings.push_to_talk);
} else {
warn!("TranscriptionCoordinator is not initialized");
}
return;
}
let Some(action) = ACTION_MAP.get(binding_id) else {
warn!(
"No action defined in ACTION_MAP for shortcut ID '{}'. Shortcut: '{}', Pressed: {}",
binding_id, hotkey_string, is_pressed
);
return;
};
// Cancel binding: only fires when recording and key is pressed
if binding_id == "cancel" {
let audio_manager = app.state::<Arc<AudioRecordingManager>>();
if audio_manager.is_recording() && is_pressed {
action.start(app, binding_id, hotkey_string);
}
return;
}
// Remaining bindings (e.g. "test") use simple start/stop on press/release.
if is_pressed {
action.start(app, binding_id, hotkey_string);
} else {
action.stop(app, binding_id, hotkey_string);
}
}