uttrflow / uttrflow/uttrflow-swift
⇧⌘V pastes instead of opening the clipboard when the hotkey registration is refused, and nothing says so
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
**P0 — ⇧⌘V does not open the clipboard. It pastes into whatever you were typing in.**
### What happens
Users press ⇧⌘V expecting the clipboard panel. The panel does not appear, and **text gets
pasted instead** — plain, unformatted. Reported by more than one person.
That second half is the tell, and it identifies the bug precisely.
### Why
⇧⌘V is claimed through Carbon, not through the event tap, and deliberately so
(`Docs/shortcuts.md`):
> `RegisterEventHotKey` **consumes** the combination, which a listen-only tap cannot do, and
> without that the clipboard panel would open *and* the app underneath would paste without
> formatting.
So the design depends on the registration succeeding. When it fails, the key is not consumed
and falls straight through to the frontmost application — where **⇧⌘V is "Paste and Match
Style"** in essentially every macOS text app. The user gets exactly half of the failure the doc
warned about: no panel, and an unformatted paste.
`CarbonHotkeyMonitor.start` throws when the combination is taken (`CarbonHotkeyMonitor.swift:101`):
```swift
guard status == noErr, let hotKey else {
// Fails when another app owns the combination; the shared handler stays.
hotkeySinks.withLock { $0[identifier] = nil }
throw .shortcutUnavailable
}
```
And `AppDelegate.startWatchingForClaimedShortcuts` swallows it
(`AppDelegate.swift:499`):
```swift
do {
try monitor.start(binding: binding)
} catch {
Self.log.error("\(action.rawValue) shortcut refused: \(error.userMessage)")
continue // <- silently gives up on this shortcut
}
```
An `os_log` line. Nothing in the interface. The Settings screen still shows ⇧⌘V as the
clipboard shortcut, so the app is displaying a binding it knows is not armed.
Contrast the dictation shortcut, which stores `shortcutFailure`, renders it, and retries when
the app is next activated (`AppDelegate.startWatchingForTheShortcut`). The claimed shortcuts get
none of that — the comment on the function even says so: *"a refusal is logged rather than shown
as a dictation failure."*
### Why registration fails for these users, and not on every machine
`RegisterEventHotKey` refuses a combination another process already owns. ⇧⌘V is heavily
contested — other clipboard managers, launchers, and text expanders all reach for it. Anybody
running one of those loses Uttrflow's clipboard silently.
Worth also checking self-collision: `startWatchingForClaimedShortcuts` runs again on every
shortcut change, stopping the old monitors and registering new ones. If a `stop()` does not
fully unregister before the re-registration runs, the app can lose the combination **to
itself**. That is a second, separate path to the same symptom and should be ruled in or out.
### Fix directions
Three things, roughly independent:
1. **Say it.** A refused shortcut must reach the user. The Settings row for that shortcut
should show it is not armed and why ("Another app is using ⇧⌘V"), the same way an
unavailable toggle already carries its reason. Displaying a binding that does nothing is the
worst of the three states.
2. **Retry.** The dictation shortcut re-arms on `applicationDidBecomeActive`. Claimed shortcuts
should too — the conflicting app may have quit.
3. **Investigate the self-collision** above before assuming every report is a third-party
conflict.
Not proposed: falling back to the event tap. The tap is listen-only and cannot consume the key,
so a fallback would produce the panel *and* the stray paste — which the doc already identifies
as the thing to avoid.
Contributor guide
Assessment
This issue has not been assessed yet.