3 điểm bởi woojinim64 2026-04-22 | 4 bình luận | Chia sẻ qua WhatsApp

Xin chào! Tôi xin giới thiệu dự án mini DualClip mà tôi làm ra trong lần đầu tiên dùng macOS.

Đây là lần đầu tôi viết một bài như thế này nên cũng hơi run. Câu chữ có vụng về thì mong mọi người rộng lượng bỏ qua 🙇


Nó là gì?

Chỉ là một ứng dụng nhỏ trên thanh menu, nhưng nó cung cấp 3 "ngăn" clipboard.

Slot A → giữ nguyên clipboard mặc định (⌘C / ⌘V)
Slot B → ⌥⌘C / ⌥⌘V
Slot C → ⌃⌘C / ⌃⌘V

Đây không phải kiểu "lịch sử" như Paste hay Maccy, mà là kiểu "slot".
Bạn có thể ghim những thứ hay dùng như email hoặc tên biến vào B, còn việc copy/paste hằng ngày thì vẫn dùng ⌘C/⌘V như bình thường.


Tại sao tôi lại làm nó

Khi refactor hoặc làm việc dịch thuật, chỉ cần nhấn ⌘C thêm một lần là thứ đã copy trước đó bay mất ngay.
Cộng dồn cả ngày thì chuyện đó gây stress âm ỉ hơn tôi tưởng.
Tôi cũng đã thử các ứng dụng lịch sử clipboard, nhưng với tôi vẫn có vài điểm chưa đã.

  • Chậm hơn một nhịp vì phải mở popup rồi chọn
  • Muốn tìm "không phải cái vừa nãy mà là cái trước đó" thì rốt cuộc vẫn phải nhìn bằng mắt
  • Tôi chỉ muốn nhấn ⌥⌘V là dán ra đúng thứ đó ngay lập tức

Vì vậy thay vì gắn thêm đủ loại tính năng, tôi chỉ giữ lại đúng một ý tưởng ngắn gọn: "ghim vào slot rồi gọi ra bằng phím tắt".


Phần vui nhất khi làm (Atomic Paste)

Phần này rắc rối hơn tôi nghĩ, vì trên macOS thì ⌘V luôn chỉ đọc system pasteboard.
Thế nên để dán Slot B, tôi phải tạm thời ghi đè system clipboard, nhưng làm vậy thì nội dung gốc đã ⌘C lại bị mất.
Tôi đã suy nghĩ rất lâu về cách giải quyết chuyện này.
Cuối cùng tôi để nó hoạt động theo thứ tự như sau.

  1. Trước hết sao lưu system clipboard hiện tại (deep copy toàn bộ type)
  2. Ghi đè bằng nội dung của Slot B
  3. Mô phỏng ⌘V bằng CGEvent
  4. Sau 150ms thì khôi phục lại bản gốc đã sao lưu

Toàn bộ chu trình này kết thúc trong vòng 150ms, nên người dùng gần như không thể cảm nhận được chuyện "thứ đã ⌘C biến mất trong chốc lát".
Tôi tự gọi nó là "Atomic Paste"...(đặt tên xong tự thấy mãn nguyện một mình 😅).
Phần canh thời điểm để tạm dừng polling và bỏ qua changeCount thực sự ngốn rất nhiều thời gian.
Tôi đã loay hoay khá lâu với kiểu: "Sao Slot A lại biến thành nội dung của Slot B nhỉ...?"

Một vài chi tiết nhỏ khác:

  • Hỗ trợ đầy đủ text/image/file/RTF (deep copy bằng NSPasteboardItem)
  • Hoàn toàn không hoạt động trong ô mật khẩu (kiểm tra IsSecureEventInputEnabled)
  • Zero-fill bộ nhớ slot khi thoát ứng dụng (memset_s)
  • Có thể đổi toàn bộ phím tắt (nhờ sindresorhus/KeyboardShortcuts)

Về mặt quyền riêng tư

Vì ứng dụng clipboard xử lý dữ liệu nhạy cảm nên riêng phần này tôi đã chú ý rất kỹ.

  • Không ghi gì xuống đĩa. Tất cả chỉ ở trong RAM.
  • Hoàn toàn không có code mạng. Không kiểm tra cập nhật, cũng không telemetry.
  • Mã nguồn mở MIT nên bạn có thể tự xem trực tiếp.

Nếu muốn dùng thử

Có lẽ Homebrew sẽ là cách tiện nhất.
brew install RAKKUNN/tap/dualclip

Hoặc bạn có thể tải file zip từ GitHub Releases rồi đưa vào /Applications.
Đây là bản build đã được Apple công chứng (notarization), nên khi chạy lần đầu sẽ không hiện cảnh báo.

GitHub: https://github.com/RAKKUNN/DualClip
Yêu cầu: macOS 13+ (Apple Silicon), quyền Trợ năng


Đây là ứng dụng macOS đầu tiên tôi làm nên chắc chắn vẫn còn nhiều chỗ vụng về.
Nếu mọi người góp ý kiểu "cái này làm thế này sẽ tốt hơn", hoặc "ở chỗ này phát sinh lỗi" thì tôi sẽ thực sự rất biết ơn và học hỏi được nhiều.
Cứ thoải mái để lại bình luận nhé!
Chúc mọi người một ngày thật tốt!!

4 bình luận

 
vwjdalsgkv 2026-04-23

Chương trình quản lý clipboard Ditto dành cho Windows cũng hoạt động tương tự với những gì bạn đã triển khai.
Nếu tham khảo thử thì có lẽ sẽ hữu ích để định hướng cải thiện~

 
woojinim64 2026-04-23

Cảm ơn vì thông tin!🙇🙇
Tôi sẽ xem qua một lần và cân nhắc chọn lọc áp dụng từng phần!

 
greekr4 2026-04-23

Sẽ rất hay nếu cũng làm thêm tính năng lưu trữ như Clipy.

 
woojinim64 2026-04-23

Bạn có nhu cầu về lịch sử hay snippet không?
Tuy nhiên, lịch sử không phù hợp với định hướng của DualClip.
Tôi đang cố gắng làm nó nhẹ và tiện nhất có thể.
Cảm ơn bạn đã phản hồi.