diff --git a/apps/desktop/src/main/managers/recording-manager.ts b/apps/desktop/src/main/managers/recording-manager.ts index e1e4bd19..7583b9e3 100644 --- a/apps/desktop/src/main/managers/recording-manager.ts +++ b/apps/desktop/src/main/managers/recording-manager.ts @@ -16,6 +16,7 @@ export type RecordingMode = "idle" | "ptt" | "hands-free"; export type TerminationCode = | "dismissed" | "quick_release" + | "escape" | "no_audio" | "error"; @@ -110,6 +111,10 @@ export class RecordingManager extends EventEmitter { shortcutManager.on("paste-last-transcript-triggered", async () => { await this.pasteLatestTranscription(); }); + + shortcutManager.on("escape-triggered", async () => { + await this.cancelHandsFreeRecording(); + }); } private setState(newState: RecordingState): void { @@ -202,6 +207,16 @@ export class RecordingManager extends EventEmitter { } } + public async cancelHandsFreeRecording() { + if ( + this.recordingState === "recording" && + this.recordingMode === "hands-free" + ) { + logger.audio.info("Escape pressed in hands-free mode, cancelling"); + await this.endRecording("escape"); + } + } + // Toggle shortcut pressed public async toggleHandsFree() { // Double-tap detection: timer pending means quick release happened diff --git a/apps/desktop/src/main/managers/shortcut-manager.ts b/apps/desktop/src/main/managers/shortcut-manager.ts index 4a7f8d47..b9f5bcab 100644 --- a/apps/desktop/src/main/managers/shortcut-manager.ts +++ b/apps/desktop/src/main/managers/shortcut-manager.ts @@ -40,6 +40,7 @@ export class ShortcutManager extends EventEmitter { private recheckInFlight = false; private recheckInterval: NodeJS.Timeout | null = null; private exactMatchState = { + escape: false, toggleRecording: false, pasteLastTranscript: false, newNote: false, @@ -183,6 +184,7 @@ export class ShortcutManager extends EventEmitter { setIsRecordingShortcut(isRecording: boolean) { this.isRecordingShortcut = isRecording; if (isRecording) { + this.exactMatchState.escape = false; this.exactMatchState.toggleRecording = false; this.exactMatchState.pasteLastTranscript = false; this.exactMatchState.newNote = false; @@ -276,6 +278,12 @@ export class ShortcutManager extends EventEmitter { return; } + const escapeMatch = this.isEscapePressed(); + if (escapeMatch && !this.exactMatchState.escape) { + this.emit("escape-triggered"); + } + this.exactMatchState.escape = escapeMatch; + // Check PTT shortcut const isPTTPressed = this.isPTTShortcutPressed(); this.emit("ptt-state-changed", isPTTPressed); @@ -302,6 +310,14 @@ export class ShortcutManager extends EventEmitter { this.exactMatchState.newNote = newNoteMatch; } + private isEscapePressed(): boolean { + const activeKeysList = this.getActiveKeys(); + return ( + activeKeysList.length === 1 && + getKeyFromKeycode(activeKeysList[0]!) === "Escape" + ); + } + private isPTTShortcutPressed(): boolean { const pttKeys = this.shortcuts.pushToTalk; if (!pttKeys || pttKeys.length === 0) {