feat: SIGUSR2 handling for toggles (#281)
This commit is contained in:
parent
f6e315786c
commit
8768ebad84
4 changed files with 119 additions and 5 deletions
28
src-tauri/Cargo.lock
generated
28
src-tauri/Cargo.lock
generated
|
|
@ -1425,6 +1425,10 @@ dependencies = [
|
||||||
"objc2 0.6.3",
|
"objc2 0.6.3",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
|
"tempfile",
|
||||||
|
"wayland-client",
|
||||||
|
"wayland-protocols-misc",
|
||||||
|
"wayland-protocols-wlr",
|
||||||
"windows 0.61.3",
|
"windows 0.61.3",
|
||||||
"x11rb",
|
"x11rb",
|
||||||
"xkbcommon",
|
"xkbcommon",
|
||||||
|
|
@ -2296,6 +2300,7 @@ dependencies = [
|
||||||
"rustfft",
|
"rustfft",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"signal-hook",
|
||||||
"strsim",
|
"strsim",
|
||||||
"tar",
|
"tar",
|
||||||
"tauri",
|
"tauri",
|
||||||
|
|
@ -5561,6 +5566,16 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook"
|
||||||
|
version = "0.3.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"signal-hook-registry",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.6"
|
version = "1.4.6"
|
||||||
|
|
@ -7625,6 +7640,19 @@ dependencies = [
|
||||||
"wayland-scanner",
|
"wayland-scanner",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wayland-protocols-misc"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dfe33d551eb8bffd03ff067a8b44bb963919157841a99957151299a6307d19c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"wayland-backend",
|
||||||
|
"wayland-client",
|
||||||
|
"wayland-protocols",
|
||||||
|
"wayland-scanner",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols-wlr"
|
name = "wayland-protocols-wlr"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,10 @@ tauri-build = { version = "2", features = [] }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
tauri = { version = "2.9.1", features = [
|
tauri = { version = "2.9.1", features = [
|
||||||
"protocol-asset",
|
"protocol-asset",
|
||||||
"macos-private-api",
|
"macos-private-api",
|
||||||
"tray-icon",
|
"tray-icon",
|
||||||
'image-png',
|
'image-png',
|
||||||
] }
|
] }
|
||||||
tauri-plugin-opener = "2.5.2"
|
tauri-plugin-opener = "2.5.2"
|
||||||
tauri-plugin-store = "2.4.1"
|
tauri-plugin-store = "2.4.1"
|
||||||
|
|
@ -53,7 +53,7 @@ env_logger = "0.11.6"
|
||||||
log = "0.4.25"
|
log = "0.4.25"
|
||||||
tokio = "1.43.0"
|
tokio = "1.43.0"
|
||||||
vad-rs = { git = "https://github.com/cjpais/vad-rs", default-features = false }
|
vad-rs = { git = "https://github.com/cjpais/vad-rs", default-features = false }
|
||||||
enigo = "0.6.1"
|
enigo = { version = "0.6.1", features = ["wayland"] }
|
||||||
rodio = { git = "https://github.com/cjpais/rodio.git" }
|
rodio = { git = "https://github.com/cjpais/rodio.git" }
|
||||||
reqwest = { version = "0.11.27", features = ["json", "stream"] }
|
reqwest = { version = "0.11.27", features = ["json", "stream"] }
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
|
|
@ -73,6 +73,9 @@ tauri-plugin-global-shortcut = "2.3.1"
|
||||||
tauri-plugin-single-instance = "2.3.2"
|
tauri-plugin-single-instance = "2.3.2"
|
||||||
tauri-plugin-updater = "2.9.0"
|
tauri-plugin-updater = "2.9.0"
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
signal-hook = "0.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ mod managers;
|
||||||
mod overlay;
|
mod overlay;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod shortcut;
|
mod shortcut;
|
||||||
|
mod signal_handler;
|
||||||
mod tray;
|
mod tray;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
|
@ -23,6 +24,13 @@ use tauri::Emitter;
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
use tauri_plugin_autostart::{MacosLauncher, ManagerExt};
|
use tauri_plugin_autostart::{MacosLauncher, ManagerExt};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use signal_hook::consts::SIGUSR2;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use signal_hook::iterator::Signals;
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ShortcutToggleStates {
|
struct ShortcutToggleStates {
|
||||||
// Map: shortcut_binding_id -> is_active
|
// Map: shortcut_binding_id -> is_active
|
||||||
|
|
@ -155,6 +163,10 @@ fn trigger_update_check(app: AppHandle) -> Result<(), String> {
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
|
info!("Initializing!");
|
||||||
|
#[cfg(unix)]
|
||||||
|
let signals = Signals::new(&[SIGUSR2]).unwrap();
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
||||||
show_main_window(app);
|
show_main_window(app);
|
||||||
|
|
@ -185,6 +197,13 @@ pub fn run() {
|
||||||
let settings = settings::get_settings(&app.handle());
|
let settings = settings::get_settings(&app.handle());
|
||||||
let app_handle = app.handle().clone();
|
let app_handle = app.handle().clone();
|
||||||
|
|
||||||
|
// Set up SIGUSR2 signal handler for toggling transcription
|
||||||
|
//
|
||||||
|
// Note: We register SIGUSR2 here so as to not conflict with
|
||||||
|
// WebKit's default handling of SIGUSR1 for triggering GC cleanup.
|
||||||
|
#[cfg(unix)]
|
||||||
|
signal_handler::setup_signal_handler(app_handle.clone(), signals);
|
||||||
|
|
||||||
initialize_core_logic(&app_handle);
|
initialize_core_logic(&app_handle);
|
||||||
|
|
||||||
// Show main window only if not starting hidden
|
// Show main window only if not starting hidden
|
||||||
|
|
|
||||||
64
src-tauri/src/signal_handler.rs
Normal file
64
src-tauri/src/signal_handler.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
use crate::actions::ACTION_MAP;
|
||||||
|
use crate::ManagedToggleState;
|
||||||
|
use log::{debug, info, warn};
|
||||||
|
use std::thread;
|
||||||
|
use tauri::{AppHandle, Manager};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use signal_hook::consts::SIGUSR2;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use signal_hook::iterator::Signals;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn setup_signal_handler(app_handle: AppHandle, mut signals: Signals) {
|
||||||
|
let app_handle_for_signal = app_handle.clone();
|
||||||
|
|
||||||
|
info!("SIGUSR2 signal handler registered successfully");
|
||||||
|
thread::spawn(move || {
|
||||||
|
info!("SIGUSR2 signal handler thread started");
|
||||||
|
// This blocks until a signal arrives - much more efficient than polling
|
||||||
|
for sig in signals.forever() {
|
||||||
|
match sig {
|
||||||
|
SIGUSR2 => {
|
||||||
|
debug!("Received SIGUSR2 signal (signal number: {sig})");
|
||||||
|
|
||||||
|
let binding_id = "transcribe";
|
||||||
|
let shortcut_string = "SIGUSR2";
|
||||||
|
|
||||||
|
if let Some(action) = ACTION_MAP.get(binding_id) {
|
||||||
|
let toggle_state_manager =
|
||||||
|
app_handle_for_signal.state::<ManagedToggleState>();
|
||||||
|
|
||||||
|
let mut states = match toggle_state_manager.lock() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Failed to lock toggle state manager: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_currently_active = states
|
||||||
|
.active_toggles
|
||||||
|
.entry(binding_id.to_string())
|
||||||
|
.or_insert(false);
|
||||||
|
|
||||||
|
if *is_currently_active {
|
||||||
|
debug!("SIGUSR2: Stopping transcription (currently active)");
|
||||||
|
action.stop(&app_handle_for_signal, binding_id, shortcut_string);
|
||||||
|
*is_currently_active = false; // Update state to inactive
|
||||||
|
info!("SIGUSR2: Transcription stopped");
|
||||||
|
} else {
|
||||||
|
debug!("SIGUSR2: Starting transcription (currently inactive)");
|
||||||
|
action.start(&app_handle_for_signal, binding_id, shortcut_string);
|
||||||
|
*is_currently_active = true; // Update state to active
|
||||||
|
info!("SIGUSR2: Transcription started");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("No action defined in ACTION_MAP for binding ID '{binding_id}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue