diff --git a/Easydict/Swift/Utility/GetSelectedText/AXSwift+Extension.swift b/Easydict/Swift/Utility/GetSelectedText/AXSwift+Extension.swift index a49dc607f..68148d8e3 100644 --- a/Easydict/Swift/Utility/GetSelectedText/AXSwift+Extension.swift +++ b/Easydict/Swift/Utility/GetSelectedText/AXSwift+Extension.swift @@ -45,14 +45,14 @@ extension UIElement { // Try to get the 4th menu item, which usually is the Edit menu. if menuChildren.count >= 4 { let editMenu = menuChildren[3] - logInfo("Checking Edit menu (4th menu item)") + logInfo("Checking the Edit(4th) menu") if let copyElement = findCopyMenuItemIn(editMenu) { return copyElement } } // If not found in Edit menu, search the entire menu. - logInfo("Copy not found in Edit menu, searching entire menu") + logInfo("Copy not found in Edit(4th) menu, searching entire menu") return findCopyMenuItemIn(menu) } diff --git a/Easydict/Swift/Utility/GetSelectedText/SystemUtility+GetSelectedText.swift b/Easydict/Swift/Utility/GetSelectedText/SystemUtility+GetSelectedText.swift index 5387d4df6..d9d54e97b 100644 --- a/Easydict/Swift/Utility/GetSelectedText/SystemUtility+GetSelectedText.swift +++ b/Easydict/Swift/Utility/GetSelectedText/SystemUtility+GetSelectedText.swift @@ -105,30 +105,20 @@ extension SystemUtility { pasteboard.onPrivateMode { do { - try copyItem.performAction(.press) logInfo("Performed action copy") + try copyItem.performAction(.press) } catch { logError("Failed to perform action copy: \(error)") } - let semaphore = DispatchSemaphore(value: 0) - - DispatchQueue.global().async { - pollTask(every: 0.005, timeout: 0.1) { - if hasPasteboardChanged(initialCount: initialChangeCount) { - result = getPasteboardString() - semaphore.signal() - return true - } - return false - } timeoutCallback: { - logInfo("pollTask timeout call back") - semaphore.signal() + pollTask { + if hasPasteboardChanged(initialCount: initialChangeCount) { + result = getPasteboardString() + return true } + return false } - semaphore.wait() - logInfo("Menu bar action copy getSelectedText: \(result ?? "nil")") } @@ -146,21 +136,13 @@ extension SystemUtility { pasteboard.onPrivateMode { callSystemCopy() - let semaphore = DispatchSemaphore(value: 0) - DispatchQueue.global().async { - pollTask(every: 0.005, timeout: 0.1) { - if hasPasteboardChanged(initialCount: initialChangeCount) { - result = getPasteboardString() - semaphore.signal() - return true - } - return false - } timeoutCallback: { - print("timeout") - semaphore.signal() + pollTask { + if hasPasteboardChanged(initialCount: initialChangeCount) { + result = getPasteboardString() + return true } + return false } - semaphore.wait() } logInfo("Shortcut copy getSelectedText: \(result ?? "nil")") diff --git a/Easydict/Swift/Utility/GetSelectedText/SystemUtility.swift b/Easydict/Swift/Utility/GetSelectedText/SystemUtility.swift index 05b8e41d5..2e8db02a5 100644 --- a/Easydict/Swift/Utility/GetSelectedText/SystemUtility.swift +++ b/Easydict/Swift/Utility/GetSelectedText/SystemUtility.swift @@ -77,9 +77,34 @@ func copyToClipboard(_ text: String) { pasteboard.setString(text, forType: .string) } +/// Sync poll task, if task is true, return true, else continue polling. +/// +/// - Warning: ⚠️ This method will block the current thread, only use when necessary. +/// - Returns: true if the task succeeded, false if it timed out. +@discardableResult func pollTask( - every interval: TimeInterval, - timeout: TimeInterval = 2, + every interval: TimeInterval = 0.005, + timeout: TimeInterval = 0.1, + task: () -> Bool, + timeoutCallback: () -> () = {} +) + -> Bool { + let startTime = Date() + while Date().timeIntervalSince(startTime) < timeout { + if task() { + return true + } + Thread.sleep(forTimeInterval: interval) + } + timeoutCallback() + logInfo("pollTask timeout call back") + return false +} + +/// Async poll task, if task is true, call timeoutCallback. +func asyncPollTask( + every interval: TimeInterval = 0.005, + timeout: TimeInterval = 0.1, task: @escaping () -> Bool, timeoutCallback: @escaping () -> () = {} ) { @@ -92,12 +117,13 @@ func pollTask( if elapsedTime >= timeout { timer.invalidate() timeoutCallback() + logInfo("pollTask timeout call back") } else { logInfo("Still polling...") } } } - + // For non-main thread, run loop must be run. RunLoop.current.run() }