macOS: keep the transcription when there is no insertion target #443
Replies: 4 comments
|
Thanks a lot for opening a discussion before the PR, that's exactly the right process and I appreciate the detailed write-up.
The transcription is not lost. Every dictation is saved in the History page, whatever happens with the paste. And there is already a "Copy last transcript" action for this exact case: it's in the tray menu, and also available as a configurable shortcut in Settings > Shortcuts and you can even click on the history item to copy it. So if you dictated with no field focused, the text is one click (or one shortcut) away. Given that, I'd rather not add focus detection on the paste path. It runs on every dictation and the case is already covered. If you didn't find "Copy last transcript", maybe the real issue is discoverability. Happy to hear your thoughts on that. |
|
You are right, and my opening line was wrong. I checked the code: What I was actually reproducing is the Wispr Flow behaviour: when the text lands nowhere, it is shown to you right there with a way to copy it, without you having to know anything. That is what I was after — not recovery, which as you point out already exists. And the discoverability point is stronger than you know: So the gap is narrower than I described. It is not "the text is lost", it is "you do not know the paste went nowhere, so you do not know there is anything to recover". Whether that is worth code on the paste path is your call, and your objection stands: it would run on every dictation for a case that already has an answer. I am dropping the focus-detection proposal. If you ever want to look at the discoverability angle instead, I am happy to help, but I will leave the direction to you. |
|
Now that I get the real problem, the idea is not bad at all. I do not want the focus detection though. It works on macOS and there is an equivalent on Windows, but there is nothing reliable on Linux, so the feature would exist on two platforms out of three. The way around it is to detect nothing: after every dictation, keep the overlay up for a few seconds with the transcription, a copy button and a thin bar showing the time left. Same behaviour everywhere. It also solves something I want for command mode, when you select an English sentence on a website and ask for a translation there is often nowhere to write the result. It is on the roadmap now. I will take this one myself, the UX side has a real impact on the app. I will look at #442 at the same time, it makes more sense to decide on it when I am in that code. |
|
Update from the macOS side, since I kept digging after your reply. Two findings you cannot get without a Mac, and one of them affects the panel you just put on the roadmap. 1. Your panel with a copy button will pull macOS users out of full-screen appsI built the detection version locally and used it for a few days, so I hit this in real use. On macOS, clicking any window activates its owning application — the window's It is quite jarring in practice. I ended up removing the button entirely: the transcription is already written to the clipboard before the panel appears, so the button only rewrote what was there, and it cost a Space switch for nothing. A panel that says "already copied, ⌘V to paste" does the same job with nothing to click. Worth knowing before you build the interactive version. If you do want a clickable panel on macOS, 2. Focus detection is not viable without forcing accessibility on — which confirms your callYou were right to refuse it, and for a stronger reason than platform parity. Chromium-based applications — Chrome itself, and any Electron app — do not expose their accessibility tree unless an assistive technology asks for it. Measured over several days of real dictation: That last answer is the problem: The way out exists: But that means a dictation tool forcing another application to enable accessibility, which is a real intrusion. Your "detect nothing, show it every time" approach avoids the whole problem and works identically on all three platforms. It is the better design. 3. On #437I would like to take the PR you offered. I have the I am holding off for a few days: my local build is still moving while I settle the above, and I would rather send you something stable than something I am still changing. Say the word if you would rather do it yourself in the meantime — no hard feelings either way, and the ordering point above is the only thing that is not obvious. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
The problem
When you dictate with no text field focused — you forgot to click into the input, or the front app simply has nothing editable —
write_transcriptionstill runs the normal paste path: it writes the clipboard, sends the paste shortcut into the void, then restores the previous clipboard becausecopy_to_clipboardis off by default. The transcription is gone, and nothing tells you it was lost. You only find out when you look at the target app and it is empty.It happens more often than I expected in daily use, and losing a long dictation that way is genuinely annoying.
What I built
I have been running this on my own macOS build for a day. When no insertion target is detected, Murmure keeps the transcription in the clipboard instead of restoring the previous content, and the overlay stays up showing the text with a copy button, for a configurable delay (15 s by default). A new dictation clears it immediately. In every other case nothing changes at all.
How the detection works
A small module answers one question — is the focused element editable? — with three states, via the Accessibility API (which Murmure already has permission for, since shortcuts depend on it):
Editable— the focused element's role is one ofAXTextField,AXTextArea,AXComboBox,AXSearchField, or itsAXValueattribute is settable, which catches the custom roles Chrome and Electron apps expose.NotEditable— either the API reportskAXErrorNoValue(nothing focused at all), or a role was read that is neither in the list nor settable.Unknown— anything else: an API error, an unreadable role, a missing attribute.EditableandUnknownboth take the current paste path, unchanged. That is the design constraint: this code runs on every single dictation, so it only deviates from today's behaviour on a certainty. The worst case stays exactly what happens now.The system-wide element also gets a 250 ms messaging timeout, so a hung target app cannot stall the end of a dictation.
Roles I actually observed over a day of use:
AXTextAreaAXTextFieldAXGroupAXListAXWebAreaAXWindowNo
Unknownon my machine, but the state is what makes the whole thing safe to ship.Honest limitations
Unknowneverywhere else, so Linux and Windows are untouched by construction.Editablestill loses the text, exactly like today. This reduces the problem, it does not eliminate it.AXWebAreais a page container, not a field. ReportingNotEditableis right when no input is focused, but a web app that exposes its focused field poorly could trigger the panel unnecessarily. The consequence is bounded: the text is in the clipboard and on screen, one paste away.Before I go further
Is this something you would want in Murmure? I did not open a PR because CONTRIBUTING asks for a conversation first on features, and because there are real design questions I would rather not decide alone — whether the clipboard should be overwritten in this case, how long the panel should stay, and whether it belongs behind a setting.
Happy to prepare a PR if you are interested, and equally happy to keep it on my own build if it does not fit the project's direction.
Environment: macOS 26.6.2 (Apple Silicon), built from 1.11.3. I used Claude Code while building and debugging this; I understand the code and can discuss any part of it.
All reactions