对剪贴板的支持是提高用户使用体验的一个重要因素。经常,我们的应用需要监听剪贴板的内容变化,并做出相应的反应。

在iOS上这个目的可以直接通过订阅 UIPasteboardChangedNotification 来完成,而在macOS上,苹果没有提供现成的 API。

不过,实现起来也不是很麻烦。我们可以写一个剪切板的监听器,实现这个目标。

监听器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import AppKit

class Clipboard {
typealias Hook = (String) -> Void

private let pasteboard = NSPasteboard.general
private let timerInterval = 1.0

private var changeCount: Int
private var hooks: [Hook]

init() {
changeCount = pasteboard.changeCount
hooks = []
}

func onNewCopy(_ hook: @escaping Hook) {
hooks.append(hook)
}

func startListening() {
Timer.scheduledTimer(timeInterval: timerInterval,
target: self,
selector: #selector(checkForChangesInPasteboard),
userInfo: nil,
repeats: true)
}

func copy(_ string: String) {
pasteboard.declareTypes([NSPasteboard.PasteboardType.string], owner: nil)
pasteboard.setString(string, forType: NSPasteboard.PasteboardType.string)
}

@objc
func checkForChangesInPasteboard() {
guard pasteboard.changeCount != changeCount else {
return
}

if let lastItem = pasteboard.string(forType: NSPasteboard.PasteboardType.string) {
for hook in hooks {
hook(lastItem)
}
}

changeCount = pasteboard.changeCount
}
}

使用

需要在应用启动的时候创建监听器,并启动之。可以在appdelegate中完成:

1
2
3
4
5
6
7
8
9
10
class AppDelegate: NSObject, NSApplicationDelegate {

let clipboard = Clipboard()

func applicationDidFinishLaunching(_ aNotification: Notification) {
clipboard.startListening()
clipboard.onNewCopy { (content) in
print(content)
}
}

这样只要用户复制了文本到剪切板中, onNewCopy 就会自动触发,打印出复制的内容了。

以上的实现只监听了String 类型,如果需要监听其他类型也可以简单改造之。