From 49d09e44472d700ab30d75a01f8ae0f289899d05 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Mon, 13 Apr 2026 05:55:52 -0700 Subject: [PATCH 1/3] Add Ctrl+Shift+M hotkey for speech-to-text toggle Lifts useSTT hook from SttButton into TerminalView so both the hotkey and the button share the same recording state. The hotkey keeps terminal focus so after transcription the user just presses Enter. The button also no longer steals focus via onMouseDown preventDefault. Co-Authored-By: Claude Opus 4.6 (1M context) --- app/src/components/terminal/SttButton.tsx | 24 +++++++++++--------- app/src/components/terminal/TerminalView.tsx | 11 ++++++++- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/app/src/components/terminal/SttButton.tsx b/app/src/components/terminal/SttButton.tsx index 4e83e02..3997cdc 100644 --- a/app/src/components/terminal/SttButton.tsx +++ b/app/src/components/terminal/SttButton.tsx @@ -1,14 +1,15 @@ import { useCallback, useEffect, useRef, useState } from "react"; -import { useSTT } from "../../hooks/useSTT"; +import type { SttState } from "../../hooks/useSTT"; import * as commands from "../../lib/tauri-commands"; interface Props { - sessionId: string; - sendInput: (sessionId: string, data: string) => Promise; + state: SttState; + error: string | null; + onToggle: () => Promise; + onCancel: () => Promise; } -export default function SttButton({ sessionId, sendInput }: Props) { - const { state, error, toggle, cancelRecording } = useSTT(sessionId, sendInput); +export default function SttButton({ state, error, onToggle, onCancel }: Props) { const [elapsed, setElapsed] = useState(0); const timerRef = useRef | null>(null); @@ -40,17 +41,17 @@ export default function SttButton({ sessionId, sendInput }: Props) { // Container start failed, toggle will still attempt transcription } } - await toggle(); - }, [state, toggle]); + await onToggle(); + }, [state, onToggle]); const handleContextMenu = useCallback( (e: React.MouseEvent) => { e.preventDefault(); if (state === "recording") { - cancelRecording(); + onCancel(); } }, - [state, cancelRecording], + [state, onCancel], ); const formatTime = (seconds: number) => { @@ -64,6 +65,7 @@ export default function SttButton({ sessionId, sendInput }: Props) { {/* STT mic button - bottom left */} - {sttEnabled && } + {sttEnabled && } {/* Jump to Current - bottom right, when scrolled up */} {!isAtBottom && ( + {hovered && state !== "recording" && ( +
+ {state === "transcribing" ? "Transcribing..." : ( + <>Speech to text Ctrl+Shift+M + )} +
)} - + {state === "recording" && ( {formatTime(elapsed)} -- 2.47.3