¿Cómo obtener el texto seleccionado en un AppleScript, sin copiar el texto al portapapeles?

6

He investigado métodos sobre cómo obtener la selección como una variable de texto en un AppleScript. Pero estos métodos se basan en copiar la selección en el portapapeles (por ejemplo, presionando el comando de copiar en la parte superior de la secuencia de comandos) para introducir este texto en el AppleScript (usando the clipboard ).

Esto no es ideal, por supuesto, porque el texto real del portapapeles se sobrescribe.

¿Hay otra forma de obtener el texto seleccionado, en todo el sistema, en AppleScript, sin molestar al portapapeles?

Obviamente, uno puede obtener fácilmente el texto seleccionado sin tocar el portapapeles en Automator. Sin embargo, en este caso, no quiero usar Automator; Necesito una solución pura de AppleScript.

    
pregunta rubik's sphere 01.02.2017 - 03:14

1 respuesta

4

Aquí hay una publicación reciente en el blog que se centra en esta misma misión:

Michael Tsai - Blog - Procesando el texto seleccionado a través de Script

Una forma de obtener el texto seleccionado actualmente en un AppleScript, sin sobrescribir el contenido del portapapeles, es simplemente guardar el contenido de the clipboard en una nueva variable antes que se copia el texto seleccionado. Luego, al final de la secuencia de comandos, vuelva a colocar el contenido original del portapapeles en the clipboard .

Esto es lo que podría 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

Pero, este método es imperfecto, como señala Michael:

  

Esto es feo y tiene algunas desventajas: la secuencia de comandos GUI requiere retrasos y no se conservan ciertos tipos de datos del portapapeles.

Sin embargo, Shane Stanley dejó un comentario en la publicación del blog con un método para conservar el formato original del contenido del portapapeles.

Si usa el ejemplo anterior, reemplace la primera línea con:

set savedClipboard to my fetchStorableClipboard()

Reemplaza la última línea con:

my putOnClipboard:savedClipboard

Y agrega el siguiente código al 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:

He probado esta solución provista por Shane y, de hecho, conserva todo el formato original del contenido del portapapeles si tiene texto enriquecido en el portapapeles.

Shane más tarde dejó un segundo comentario , esta vez con la intención de minimizar el tiempo de ejecución del script.

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

con 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

Probé este nuevo código y encontré que el script era, de hecho, notablemente más rápido, solo por un pelo.

En general, esto no es una mala solución. El contenido del portapapeles se conserva y el retraso es mucho menos notable si emplea el código proporcionado en el segundo comentario de Shane.

Probé la solución con un servicio creado en Automator.app que recibe el texto seleccionado como input . El Servicio y la solución pura de AppleScript tardaron bastante tiempo en completarse (es decir, aproximadamente un segundo).

Si uno quiere un método para obtener y reemplazar el texto seleccionado sin tener que tocar el portapapeles, Michael sugiere en su publicación del blog que puede utilizar un software de terceros denominado LaunchBar . Sin embargo, esto es "hacer trampa" porque, en ese momento, hemos superado el alcance de mi pregunta original, que está estrictamente preocupada por AppleScript.

    
respondido por el rubik's sphere 06.02.2017 - 03:54

Lea otras preguntas en las etiquetas