본문 바로가기
C.W.K.
Stream
Lesson 05 of 05 · published

글자만 말고 클립보드를 통째로 돌려놔

~11 min · pasteboard, preservation, fidelity, etiquette

Level 0식은 부싯돌
0 XP0/34 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"사용자가 갖고 있던 게 이미지일 수도, 파일일 수도, 서식 있는 글일 수도 있어. 통째로 빌렸으면 통째로 돌려줘."

클립보드는 글자 한 덩이가 아니야

찔러보기가 클립보드를 빌리니까 되돌려놓기도 제대로 해야 하는데, 여기 함정이 있어. 클립보드에 들어 있는 게 평범한 글자만이 아니거든. 어느 순간이든 이미지일 수도, 파일 여러 개일 수도, 서식 있는 글이나 HTML 일 수도, 어떤 앱만 아는 형식일 수도 있어. 게다가 같은 내용을 여러 형식으로 동시에 담고 있기도 하고. 되돌려놓기가 평범한 글자만 떠뒀다가 도로 쓰면, 이미지나 파일을 복사해뒀던 사용자는 그걸 찔러보기 한 번에 잃어버려. '되돌려놓는다' 는 글자만이 아니라 그 사람이 실제로 갖고 있던 게 뭐든 그대로 돌아온다는 뜻이어야 해.

항목도 형식도 전부 떠두기

제대로 뜨려면 페이스트보드의 항목들을 하나씩 훑어야 해. 여러 개일 수 있거든. 그리고 항목마다 그게 내놓는 형식 전부를 그 데이터랑 같이 적어둬야 하고. 그 항목-형식-데이터 지도가 진짜 사진이야. 되돌려놓기는 그 거울상이고. 페이스트보드를 비우고 그 항목들을 형식까지 그대로 다시 써넣는 거지. 이렇게 하면 이미지는 이미지로, 파일은 파일로, 서식 있는 글은 서식까지 살아남아. 글자 한 덩이로 납작해지지 않고 원래 모습 그대로 돌아와.

대충 하면 (글자 빼고 다 잃는다):
  저장   pb.string(forType: .string)
  ...찔러보기...
  복원   pb.setString(saved, forType: .string)   // 이미지도 파일도 사라짐

제대로 하면:
  저장   항목마다 -> 형식마다 -> 그 데이터
  ...찔러보기...
  복원   항목을 형식까지 그대로 다시 만들어 써넣기

통째로 못 뜰 때

솔직하게 말할 게 하나 있어. 클립보드 내용 중엔 통째로 못 뜨는 것도 있어. 실제 붙여넣기가 일어날 때만 원본 앱이 내용을 넘겨주는 종류가 그래. 그런 건 미리 떠둘 수가 없거든. 이럴 땐 보수적으로 가는 게 규칙이야. 페이스트보드를 온전히 못 뜨겠으면 클립보드를 건드리는 찔러보기를 아예 하지 마. 다른 방법으로 읽은 게 있으면 그걸 쓰고, 클립보드는 그냥 놔둬. 긁어놓은 걸 못 읽는 게, 사용자가 복사해둔 파일을 삼켜버리는 것보다 나아. 되돌려놓기는 전부 아니면 전무야. 온전히 되돌리든지, 아예 안 건드리든지.

온전히 되돌리든지 아예 안 건드리든지. 절반만 돌려놓는 건 없어. 공유된 걸 빌렸을 때 80% 만 돌려놓는 건 안 빌린 것보다 나빠. 사용자는 클립보드가 멀쩡하다고 믿고 있다가, 빠진 20% 를 정작 필요한 순간에야 발견하거든. 전부 떠서 전부 돌려놓든지, 아니면 망가뜨릴 그 작업을 아예 안 하든지. 절반만 되돌려놓는 건 안전한 척하는 조용한 데이터 손실이야.
같은 규율이 넣을 때 또 나와. 매크로 결과를 클립보드에 올려 붙여넣는 방식으로 넣는다면, 그 삽입도 클립보드를 빌리는 거야. 똑같이 통째로 떠뒀다 돌려놔야 하고. 그러니 페이스트보드 뜨기를 재사용할 수 있게 만들어둬. 읽을 때 찔러보기(이 트랙)랑 붙여넣어 넣기(Track 6)가 둘 다 그걸 쓰거든. 공들인 구현 하나에 쓰는 곳 둘.

Code

페이스트보드를 항목과 형식까지 통째로 뜨고 되돌리기·swift
struct PasteboardSnapshot {
    let items: [[NSPasteboard.PasteboardType: Data]]
}

func capturePasteboard(_ pb: NSPasteboard) -> PasteboardSnapshot {
    let items = (pb.pasteboardItems ?? []).map { item in
        var byType: [NSPasteboard.PasteboardType: Data] = [:]
        for type in item.types {
            if let data = item.data(forType: type) { byType[type] = data }
        }
        return byType
    }
    return PasteboardSnapshot(items: items)
}

func restorePasteboard(_ pb: NSPasteboard, from snap: PasteboardSnapshot) {
    pb.clearContents()
    let rebuilt = snap.items.map { byType -> NSPasteboardItem in
        let item = NSPasteboardItem()
        for (type, data) in byType { item.setData(data, forType: type) }
        return item
    }
    if !rebuilt.isEmpty { pb.writeObjects(rebuilt) }
}

External links

Exercise

사용자가 파일 세 개를 클립보드에 복사해뒀어. 그 상태에서 Electron 앱에서 매크로를 쳤고, Flint 가 복사로 찔러보기를 해. 가짜 Cmd+C 전에 뭘 떠둬야 하고 뒤에 뭘 되돌려놔야 그 파일 셋이 끝나고도 클립보드에 그대로 남아 있을까? 그리고 통째로는 못 뜨는 종류가 클립보드에 들어 있다는 걸 알게 됐을 때 Flint 가 뭘 해야 하는지도 말해봐.
Hint
페이스트보드의 항목 전부를, 항목마다 내놓는 형식 전부를 데이터까지 떠둬야 해. 파일 참조도 포함해서. 그다음 찔러본 결과를 읽고 그 항목들을 그대로 다시 만들어 써넣고. 통째로 못 뜨는 종류가 들어 있으면 규칙은 전부 아니면 전무야. 클립보드를 건드리는 찔러보기를 하지 마. 절반만 돌려놓으면 사용자 파일이 조용히 사라지거든.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.