~10 min · pasteboard, clipboard, etiquette, privacy
Level 0불씨 없음
0 XP0/48 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"클립보드는 유저 거지 네 거 아냐. 붙여넣으려고 빌렸으면, 발견한 그대로 돌려놔."
붙여넣기 발판엔 빚이 있어
클립보드 + Cmd+V 발판은 삽입의 일꾼이지만 남의 것을 써. 유저의 클립보드 말이야. Firekeeper 가 받아쓰기를 붙여넣으려고 클립보드에 쓰는 순간, 유저가 복사해 뒀던 게 뭐든 짓밟히는 거야. URL 이든 문단이든 이미지든. 무례하고 당황스럽지. 그래서 붙여넣기 발판은 예의를 빚져. 지금 클립보드를 먼저 챙겨 두고, 전사를 쓰고, 붙여넣고, 붙여넣기가 자리 잡으면 원래 있던 걸 되돌려 놓는 거야.
챙기고, 붙여넣고, 되돌리고
1. 저장 = 현재 클립보드 내용 읽기 + 챙기기
2. 쓰기 = 전사를 클립보드에 넣기 (transient 표시)
3. 붙여넣기 = Cmd+V 합성
4. 정착 = 붙여넣기가 떨어지길 잠깐 기다리기
5. 복원 = 원본 내용 되돌리기
(그 사이 딴 게 썼으면 복원 건너뜀)
이걸 안전하게 만드는 미묘한 장치가 둘 있어. 가능한 데서는 Firekeeper 가 클립보드에 쓰는 걸 transient 로 표시해. 그래야 클립보드 히스토리 도구가 네 받아쓰기를 마치 네가 복사한 것처럼 기록하지 않아. 그리고 되돌리기 전에, 그 잠깐 사이에 딴 게 클립보드에 쓰지 않았는지 확인해. 썼으면 더 새 내용을 짓밟으면 안 되니까. 방금 복사한 걸 덮어쓰는 예의는 예의 없는 것보다 나빠.
보안 필드라는 선
이 절차가 통째로 꺼지는 자리가 하나 있어. 보안 필드야. 타깃이 비밀번호 필드면 Firekeeper 는 그 근처에서 클립보드를 읽지도 되돌리지도 않고, 삽입 자체를 거부해. 보안 맥락 근처에서 클립보드를 읽거나 전사를 거기 얹어 두는 건, 보이스 도구가 절대 하면 안 되는 딱 그런 짓이거든. 타깃 캡처에서 했던 보안 필드 확인이 여기까지 쭉 흘러 내려와. 삽입만 막는 게 아니라 클립보드 처리까지 막는 거야.
같이 쓰는 건 발견한 그대로 남겨. 어떤 기능이 유저도 쓰는 자원을 빌려야 한다면, 그러니까 클립보드든 최전면 창이든 오디오 기기든, 챙겨 뒀다 되돌리는 걸 빚지는 거야. 잘 만든 도구인지는 이걸로 판가름 나. 일이 끝난 뒤에 빌려 썼던 자리가 손 안 댄 것과 구별이 안 되느냐.
Code
저장하고, 붙여넣고, 복원하고. 보안 필드 근처엔 절대 안 함·swift
func pasteInsert(_ text: String, restoreClipboard: Bool) async -> InsertResult {
// 보안 필드 거부는 이미 앞에서 끝났어: 거기선 클립보드에 아무것도 안 감.
let pb = NSPasteboard.general
// 1. 저장: 항목 전부와 표현 전부, 아니면 아무것도
let saved = restoreClipboard ? PasteboardSnapshot.capture(from: pb) : nil
let acceptsPaste = focusedTargetAcceptsPaste() // 시작 때 말고 지금 물음
let frontBefore = NSWorkspace.shared.frontmostApplication?.processIdentifier
pb.clearContents() // 2. 쓰기, transient 표시
pb.setString("", forType: .init("org.nspasteboard.TransientType"))
pb.setString(text, forType: .string)
let ourChange = pb.changeCount
synthesizeCmdV() // 3. 붙여넣기
try? await Task.sleep(for: .milliseconds(350)) // 4. 정착 (Electron 은 늦게 읽어)
// 5. 다 괜찮을 때만 복원 (FirekeeperKit PasteTargetRole)
let landed = PasteTargetRole.mayRestoreClipboard(
frontAppUnchanged: NSWorkspace.shared.frontmostApplication?.processIdentifier == frontBefore,
pasteboardUntouchedSinceOurWrite: pb.changeCount == ourChange,
targetAcceptsPaste: acceptsPaste)
if let saved, landed { saved.restore(to: pb) }
// 붙여넣기를 확인해 줄 API 는 없어: 바란 게 아니라 아는 걸 보고해.
if saved != nil, !landed { return .copiedToClipboard("could not confirm the paste") }
// 스냅샷이 없으면(복원 꺼짐, 덜 잡힌 캡처) 되돌린 게 없어서 전사는
// 클립보드에 그대로 있고, 그래도 여기선 .pasted 로 보고해.
return .pasted
}
앱에서 시스템 자원을 같이 빌려 쓰는 기능을 찾아봐. 클립보드나 카메라, 최전면 창, 키보드 포커스 같은 거. 그 기능이 자원을 원래 상태로 돌려놔, 아니면 흔적을 남겨? 챙겼다가 붙여넣고 되돌리는 절차를 적어보고, 더 새 걸 짓밟지 않게 막는 확인도 같이 넣어봐.
Hint
제대로 된 절차는 늘 같은 모양이야. 이전 상태를 챙기고, 자원을 쓰고, 되돌려. 대신 쥐고 있는 사이에 세상이 바뀌었는지 알아채는 가드를 같이 달아야 해. 그 가드가 없으면 '되돌리기' 가 '그사이 벌어진 걸 전부 덮어쓰기' 가 되면서, 예의가 데이터 날리는 버그로 뒤집혀. 빌리는 걸 안전하게 만드는 게 바로 그 change count 확인이야.
Progress
Progress is local-only — sign in to sync across devices.