DualClip Update — Beyond Text, and a 150ms Correction
A few hours ago, I shared DualClip, a slot-based clipboard manager for macOS. Thank you to everyone who checked it out!
Since then, I've shipped a few meaningful updates that I didn't cover in the original post. I also owe you a small correction. Let me walk through both.
🔧 First, a correction: 50ms → 150ms
In my first post, I wrote that the Atomic Paste operation completes "in less than 50ms." That was wrong. The actual restore delay is 150ms.
/// 150ms is an empirically safe value to prevent race conditions.
private let restoreDelayMs: Int = 150
150ms was chosen empirically to avoid a race condition — if the clipboard is restored before the target application finishes reading it, the paste silently fails. 50ms sounded cooler, but 150ms is what actually works reliably. Sorry about that.
⚡ How Atomic Paste actually works
Since this is the core mechanic of DualClip, I figured it deserves a proper breakdown. When you press the hotkey to paste from Slot B, here's what happens under the hood:
1. Backup — The entire system clipboard (Slot A) is deep-copied into a temporary buffer. Not just text — all NSPasteboardItem types and their raw data.
2. Swap — Slot B's content is written to the system clipboard, replacing whatever was there.
3. Simulate — A CGEvent-based ⌘V keystroke is posted to the HID system. This is why DualClip requires Accessibility permission — it's literally pressing keys on your behalf.
4. Restore — After 150ms, the backup is written back to the system clipboard. Your original ⌘C content is untouched.
The entire flow is invisible to the user. You press a hotkey, text appears, and your clipboard stays exactly as it was.
🖼 Multi-content type support
The first post only showed text workflows, which gave the impression that DualClip is text-only. It's not — it now supports four content types:
| Type | Example |
|---|---|
| Plain text | Code snippets, URLs, API keys |
| Rich text (RTF) | Formatted text with bold, colors, etc. |
| Images | Screenshots, design assets from Figma |
| File URLs | File paths copied from Finder |
Each slot stores the raw NSPasteboardItem data faithfully, so what you copy is exactly what you get back — formatting, metadata, and all.
This means you can now keep a screenshot in Slot B and a HEX code in Slot C, then paste them alternately into your editor without touching the mouse.
🔐 RAM Zeroing on termination
In the first post, I mentioned that all data lives in RAM only. That's still true, but I've taken it a step further.
When DualClip quits, it doesn't just release memory — it overwrites every byte with zeros before deallocation:
func secureWipe() {
if let items = pasteboardItems {
for item in items {
for type in item.types {
if let data = item.data(forType: type) {
data.withUnsafeBytes { rawBuffer in
guard let baseAddress = rawBuffer.baseAddress else { return }
let mutable = UnsafeMutableRawPointer(mutating: baseAddress)
memset(mutable, 0, rawBuffer.count)
}
}
}
}
}
clear()
}
This is called on applicationWillTerminate for all three slots. If you temporarily stored an API key or password in a slot, it won't linger in physical memory after the app closes.
To summarize the privacy model:
- No disk writes. Nothing is persisted.
- No network. Zero external communication.
- RAM zeroing. Memory is scrubbed on exit.
- Open source. You can verify all of the above yourself.
🏗 CI pipeline
I've added a GitHub Actions workflow that runs on every push and PR to main. It builds the project in both Debug and Release configurations on macOS 14 with Swift 5.9.
It's a simple setup — no notarization or automatic releases yet — but it catches build regressions before they land.
🛠 Building from source
There's no prebuilt binary yet, but building is straightforward if you have Xcode:
git clone https://github.com/RAKKUNN/DualClip.git
cd DualClip
open Package.swift
Hit ▶ Run in Xcode. On first launch, macOS will ask for Accessibility permission — this is required for the CGEvent keystroke simulation that powers Atomic Paste.
What's next
- Secure input field detection (auto-disable in password fields)
- Homebrew Cask distribution
- Sparkle auto-update
This is still a small, single-purpose tool, but I'm trying to get the details right. If you have feedback or want to contribute, the repo is open.
🔗 GitHub: https://github.com/RAKKUNN/DualClip
Thanks for reading!
Top comments (0)