73 lines
3.0 KiB
Swift
73 lines
3.0 KiB
Swift
import Foundation
|
|
import AppKit
|
|
class SelectedTextService {
|
|
// Private pasteboard type to avoid clipboard history pollution
|
|
private static let privatePasteboardType = NSPasteboard.PasteboardType("com.prakashjoshipax.VoiceInk.transient")
|
|
|
|
static func fetchSelectedText() -> String? {
|
|
// Don't check for selected text within VoiceInk itself
|
|
guard let frontmostApp = NSWorkspace.shared.frontmostApplication,
|
|
frontmostApp.bundleIdentifier != "com.prakashjoshipax.VoiceInk" else {
|
|
return nil
|
|
}
|
|
|
|
let pasteboard = NSPasteboard.general
|
|
let originalClipboardText = pasteboard.string(forType: .string)
|
|
|
|
// Save original clipboard content (all UTIs with their data)
|
|
let originalPasteboardItems = pasteboard.pasteboardItems?.map { item in
|
|
item.types.reduce(into: [NSPasteboard.PasteboardType: Data]()) { acc, type in
|
|
if let data = item.data(forType: type) {
|
|
acc[type] = data
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clear clipboard to prepare for selection detection
|
|
pasteboard.clearContents()
|
|
|
|
// Simulate Cmd+C to copy any selected text
|
|
let source = CGEventSource(stateID: .hidSystemState)
|
|
let cmdDown = CGEvent(keyboardEventSource: source, virtualKey: 0x37, keyDown: true)
|
|
cmdDown?.flags = .maskCommand
|
|
let cDown = CGEvent(keyboardEventSource: source, virtualKey: 0x08, keyDown: true)
|
|
cDown?.flags = .maskCommand
|
|
let cUp = CGEvent(keyboardEventSource: source, virtualKey: 0x08, keyDown: false)
|
|
cUp?.flags = .maskCommand
|
|
let cmdUp = CGEvent(keyboardEventSource: source, virtualKey: 0x37, keyDown: false)
|
|
|
|
cmdDown?.post(tap: .cghidEventTap)
|
|
cDown?.post(tap: .cghidEventTap)
|
|
cUp?.post(tap: .cghidEventTap)
|
|
cmdUp?.post(tap: .cghidEventTap)
|
|
|
|
// Wait for copy operation to complete
|
|
Thread.sleep(forTimeInterval: 0.1)
|
|
|
|
// Read the copied text
|
|
let selectedText = pasteboard.string(forType: .string)
|
|
|
|
// Restore original clipboard content
|
|
pasteboard.clearContents()
|
|
if let originalItems = originalPasteboardItems, !originalItems.isEmpty {
|
|
let restoredItems: [NSPasteboardItem] = originalItems.compactMap { dataMap in
|
|
guard !dataMap.isEmpty else { return nil }
|
|
let item = NSPasteboardItem()
|
|
for (type, data) in dataMap {
|
|
item.setData(data, forType: type)
|
|
}
|
|
return item
|
|
}
|
|
if !restoredItems.isEmpty {
|
|
pasteboard.writeObjects(restoredItems)
|
|
} else if let originalClipboardText {
|
|
_ = pasteboard.setString(originalClipboardText, forType: .string)
|
|
}
|
|
} else if let originalClipboardText {
|
|
_ = pasteboard.setString(originalClipboardText, forType: .string)
|
|
}
|
|
|
|
return selectedText
|
|
}
|
|
}
|