mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-26 13:45:16 -07:00
feat(capture): gate global hotkey on dictation readiness checklist
Stops the "stuck pill" failure where pressing the chord with missing STT/LLM models triggers a recording that has nowhere to land. The hotkey now stays disarmed until every gate (models downloaded, Input Monitoring + Accessibility granted) is green; the empty-state checklist in CapturesTab surfaces each unmet gate with a one-click action and auto-arms the chord once everything turns green. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
868a40fb7e
commit
85a3e1363f
@@ -1,27 +1,34 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { useEffect } from 'react';
|
||||
import { useDictationReadiness } from '@/lib/hooks/useDictationReadiness';
|
||||
import { useCaptureSettings } from '@/lib/hooks/useSettings';
|
||||
import { usePlatform } from '@/platform/PlatformContext';
|
||||
|
||||
/**
|
||||
* Spawn (or quiet) the global hotkey monitor based on the saved
|
||||
* `capture_settings.hotkey_enabled` flag, and keep its bindings in sync with
|
||||
* the user's chord choices.
|
||||
* `capture_settings.hotkey_enabled` flag AND the dictation readiness gates,
|
||||
* and keep its bindings in sync with the user's chord choices.
|
||||
*
|
||||
* Boot sequence:
|
||||
* - hotkey_enabled = false → call `disable_hotkey` (no-op if monitor was
|
||||
* never spawned). Crucially, we do *not* call `enable_hotkey`, so the
|
||||
* macOS Input Monitoring TCC prompt is never triggered for users who
|
||||
* haven't opted in.
|
||||
* - hotkey_enabled = true → call `enable_hotkey` with the saved chords.
|
||||
* This is the call that creates the CGEventTap and triggers the TCC
|
||||
* prompt on first opt-in.
|
||||
* - hotkey_enabled = false OR any readiness gate missing → call
|
||||
* `disable_hotkey` (no-op if monitor was never spawned). Crucially, we do
|
||||
* *not* call `enable_hotkey` in this state, so the macOS Input Monitoring
|
||||
* TCC prompt is never triggered for users who haven't opted in, AND the
|
||||
* chord physically can't fire when models aren't downloaded — preventing
|
||||
* the "stuck pill" failure mode where dictation triggers but has nowhere
|
||||
* to land.
|
||||
* - hotkey_enabled = true AND all gates green → call `enable_hotkey` with
|
||||
* the saved chords. This creates the CGEventTap and triggers the TCC
|
||||
* prompt on first opt-in. Re-runs whenever a gate flips green (e.g. the
|
||||
* user finishes downloading Whisper in another tab) so the chord
|
||||
* auto-arms without making the user toggle off/on.
|
||||
*
|
||||
* Call once from the main app shell.
|
||||
*/
|
||||
export function useChordSync() {
|
||||
const platform = usePlatform();
|
||||
const { settings } = useCaptureSettings();
|
||||
const { allReady } = useDictationReadiness();
|
||||
const enabled = settings?.hotkey_enabled;
|
||||
const pushKeys = settings?.chord_push_to_talk_keys;
|
||||
const toggleKeys = settings?.chord_toggle_to_talk_keys;
|
||||
@@ -29,16 +36,16 @@ export function useChordSync() {
|
||||
useEffect(() => {
|
||||
if (!platform.metadata.isTauri) return;
|
||||
if (enabled === undefined || !pushKeys || !toggleKeys) return;
|
||||
const command = enabled ? 'enable_hotkey' : 'disable_hotkey';
|
||||
const args = enabled
|
||||
? { pushToTalk: pushKeys, toggleToTalk: toggleKeys }
|
||||
: {};
|
||||
const shouldArm = enabled && allReady;
|
||||
const command = shouldArm ? 'enable_hotkey' : 'disable_hotkey';
|
||||
const args = shouldArm ? { pushToTalk: pushKeys, toggleToTalk: toggleKeys } : {};
|
||||
invoke(command, args).catch((err) => {
|
||||
console.warn(`[chord-sync] ${command} failed:`, err);
|
||||
});
|
||||
}, [
|
||||
platform.metadata.isTauri,
|
||||
enabled,
|
||||
allReady,
|
||||
// Stringify so a referentially-new array with the same content
|
||||
// doesn't fire a redundant invoke on every settings refetch.
|
||||
pushKeys?.join(','),
|
||||
|
||||
Reference in New Issue
Block a user