Como obter o texto selecionado em um AppleScript, sem copiar o texto para a área de transferência?

6

Eu pesquisei métodos sobre como obter a seleção como uma variável de texto em um AppleScript. Mas esses métodos dependem da cópia da seleção para a área de transferência (por exemplo, ao pressionar o comando copy na parte superior do script) para introduzir esse texto ao AppleScript (usando the clipboard ).

Isso é menos que ideal, é claro, porque o texto real da área de transferência é sobrescrito.

Existe outra maneira de obter o texto selecionado, em todo o sistema, no AppleScript, sem perturbar a área de transferência?

Obviamente, pode-se obter facilmente o texto selecionado sem tocar na área de transferência no Automator. No entanto, neste caso, não quero usar o Automator; Eu preciso de uma solução AppleScript pura.

rubik's sphere
fonte
Você poderia esclarecer o que você está tentando fazer, fornecendo alguns exemplos práticos. O texto selecionado é editável, sim, não, ambos?
user3439894
@ user3439894 O texto selecionado será necessariamente editável. Eu gostaria que o código pegasse o texto selecionado, realizasse alguma operação nele e depois substituísse o texto selecionado. Um exemplo seria converter o caso de letra do texto selecionado para o caso do título. (Eu já tenho o código que converte maiúsculas e minúsculas, então não preciso de ajuda com isso. E digitar o novo texto é bastante simples. Eu simplesmente não sei como obter a seleção para o AppleScript, fora da área de transferência.)
rubik's sphere
Desculpe, mas isso não esclarece as coisas. Espero que alguém consiga e possa oferecer alguma ajuda.
user3439894
@ user3439894 Você pode explicar o que não está claro? Suponha que o texto selecionado seja: "Esta é uma frase composta de palavras." Eu quero o meu AppleScript para substituir o texto selecionado com uma nova seqüência: "Esta é uma frase composta de palavras." O texto selecionado será sempre editável. O AppleScript será acionado por FastScripts, portanto, não posso usar o recurso "O serviço recebe o texto selecionado" do Automator.
rubik's sphere
Eu nunca usei FastScripts antes, então vou ter que olhar para isso amanhã.
user3439894

Respostas:

4

Aqui está uma postagem recente no blog que foca nessa missão:

Michael Tsai - Blog - Processando o texto selecionado via script

Uma maneira de obter o texto atualmente selecionado em um AppleScript, sem sobrescrever o conteúdo da área de transferência, é simplesmente salvar the clipboard conteúdo para uma nova variável antes o texto selecionado é copiado. Então, no final do script, coloque o conteúdo original da área de transferência de volta the clipboard.

Aqui está o que isso pode parecer:

-- 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

-- Makes the selected text all uppercase:
-- From: http://apple.stackexchange.com/a/171196/184907
set theModifiedSelectedText to (do shell script ("echo " & theSelectedText & " | tr a-z A-Z;"))

-- Overwrite the old selection with the desired text:
set the clipboard to theModifiedSelectedText
tell application "System Events" to keystroke "v" using {command down}
delay 0.1 -- Without this delay, may restore clipboard before pasting.

-- Instead of the above three lines, you could instead use:
--      tell application "System Events" to keystroke theModifiedSelectedText
-- But this way is a little slower.

-- Restore clipboard:
set the clipboard to savedClipboard

Mas esse método é imperfeito, como Michael observa:

Isso é feio e tem algumas desvantagens: há atrasos exigidos pelo script da GUI e certos tipos de dados da área de transferência não são preservados.


Contudo, Shane Stanley deixou um comentário na postagem do blog com um método para manter a formatação original do conteúdo da área de transferência.

Se estiver usando o exemplo anterior, substitua a primeira linha por:

set savedClipboard to my fetchStorableClipboard()

Substitua a última linha por:

my putOnClipboard:savedClipboard

E adicione o seguinte código ao final:

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"


on fetchStorableClipboard()
    set aMutableArray to current application's NSMutableArray's array() -- used to store contents
    -- get the pasteboard and then its pasteboard items
    set thePasteboard to current application's NSPasteboard's generalPasteboard()
    -- loop through pasteboard items
    repeat with anItem in thePasteboard's pasteboardItems()
        -- make a new pasteboard item to store existing item's stuff
        set newPBItem to current application's NSPasteboardItem's alloc()'s init()
        -- get the types of data stored on the pasteboard item
        set theTypes to anItem's types()
        -- for each type, get the corresponding data and store it all in the new pasteboard item
        repeat with aType in theTypes
            set theData to (anItem's dataForType:aType)'s mutableCopy()
            if theData is not missing value then
                (newPBItem's setData:theData forType:aType)
            end if
        end repeat
        -- add new pasteboard item to array
        (aMutableArray's addObject:newPBItem)
    end repeat
    return aMutableArray
end fetchStorableClipboard


on putOnClipboard:theArray
    -- get pasteboard
    set thePasteboard to current application's NSPasteboard's generalPasteboard()
    -- clear it, then write new contents
    thePasteboard's clearContents()
    thePasteboard's writeObjects:theArray
end putOnClipboard:

Eu testei essa solução fornecida por Shane, e ela realmente retém toda a formatação original do conteúdo da área de transferência se você tiver rich text na área de transferência.


Shane depois deixou um segundo comentário , desta vez com a intenção de minimizar o tempo de execução do script.

Substitua este código:

-- 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.

com este código:

set thePasteboard to current application's NSPasteboard's generalPasteboard()
set theCount to thePasteboard's changeCount()
-- Copy selected text to clipboard:
tell application "System Events" to keystroke "c" using {command down}
-- Check for changed clipboard:
repeat 20 times
    if thePasteboard's changeCount() is not theCount then exit repeat
    delay 0.1
end repeat

Eu testei esse novo código e descobri que o roteiro era de fato notavelmente mais rápido, apenas por um fio de cabelo.


No geral, isso não é uma solução ruim. O conteúdo da área de transferência é preservado e o atraso é muito menos perceptível se você empregar o código fornecido no segundo comentário de Shane.

Eu testei a solução contra um serviço criado no Automator.app que recebe o texto selecionado como o input. O Serviço e a solução AppleScript pura levaram praticamente o mesmo tempo para serem concluídos (ou seja, cerca de um segundo).


Se alguém quiser um método para obter e substituir o texto selecionado sem ter que tocar na área de transferência, Michael sugere em seu blog que alguém pode utilizar um software de terceiros chamado Barra de Lançamento . No entanto, isso é "trapaça", porque, nesse ponto, fomos além do escopo da minha pergunta original, que é estritamente relacionada ao AppleScript.

rubik's sphere
fonte