Получить выделенный текст в любом приложении на macOS

Я пытаюсь получить выделенный текст, когда пользователь нажимает глобальный ярлык. Мое приложение должно читать текст, который в данный момент выбран, независимо от того, является ли текущее приложение хромом, сафари или Microsoft Word.

Я пытаюсь сделать это с помощью AppleScript, который делает это с помощью взлома буфера обмена. Однако это работает не во всех приложениях.

func readSelectedText() {
    let script = """
    -- Back up clipboard contents:
    set savedClipboard to the clipboard

    -- Copy selected text to clipboard:
    tell application "System Events" to keystroke "c" using {command down}
    delay 1 -- Without this, the clipboard may have stale data.

    set theSelectedText to the clipboard

    delay 1 -- Without this delay, may restore clipboard before pasting.

    -- Restore clipboard:
    set the clipboard to savedClipboard

    return theSelectedText
    """

    var error: NSDictionary?
    if let appleScript = NSAppleScript(source: script), let output = appleScript.executeAndReturnError(&error).stringValue {
        print("Selected text:", output)
    } else {
        print("AppleScriptError: \(String(describing: error))")
    }

}

Есть ли надежный способ сделать это в любом приложении?

Вы говорите о NSServices?

red_menace 14.04.2023 00:00
I'm trying to get the selected text ..., вы можете использовать NSPasteboard.general.string(forType: .string), чтобы получить выделенный текст, см.: developer.apple.com/documentation/appkit/nspasteboard
workingdog support Ukraine 14.04.2023 01:44

Данные помещаются на глобальный монтажный стол, когда приложение переходит в фоновый режим, и извлекаются из глобального монтажного стола, когда приложение становится самым передним приложением. Вы можете попробовать переключить приложение в дополнение к задержке.

Willeke 14.04.2023 08:25

Является ли любое приложение каждым приложением или конкретным приложением? Вы пытались получить текст с помощью API специальных возможностей?

Willeke 14.04.2023 08:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
160
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для этого вы можете использовать API специальных возможностей:

import ApplicationServices
import Cocoa

func getSelectedText() -> String? {
    let systemWideElement = AXUIElementCreateSystemWide()

    var selectedTextValue: AnyObject?
    let errorCode = AXUIElementCopyAttributeValue(systemWideElement, kAXFocusedUIElementAttribute as CFString, &selectedTextValue)
    
    if errorCode == .success {
        let selectedTextElement = selectedTextValue as! AXUIElement
        var selectedText: AnyObject?
        let textErrorCode = AXUIElementCopyAttributeValue(selectedTextElement, kAXSelectedTextAttribute as CFString, &selectedText)
        
        if textErrorCode == .success, let selectedTextString = selectedText as? String {
            return selectedTextString
        } else {
            return nil
        }
    } else {
        return nil
    }
}

Для этого необходимо установить Privacy - AppleEvents Sending Usage Description в Info.plist и установить com.apple.security.temporary-exception.apple-events, чтобы иметь com.apple.systemevents.

Другие вопросы по теме