¿Es posible pulsar caracteres especiales en AppleScript?

El bicho:

Para ciertos caracteres y símbolos especiales, AppleScript fallará en keystrokeel carácter real y, en su lugar, simplemente escribirá la letra a.


Un ejemplo:

El siguiente código AppleScript:

tell application "System Events" to keystroke "² ³ é ½ ₭"

escribe la siguiente cadena de texto (sin importar en qué aplicación esté):

a a a a a

Una solución:

Uno puede "escribir" el texto de manera efectiva colocando los caracteres especiales en el portapapeles y luego pegando el portapapeles, así:

set the clipboard to "² ³ é ½ ₭"
tell application "System Events" to keystroke "v" using command down

Evito usar el método anterior para poner texto en el portapapeles en AppleScript, porque necesariamente convierte el portapapeles en texto enriquecido en el proceso.

Prefiero emplear el método provisto aquí , para asegurar que el texto sin formato se coloque en el portapapeles. Pero este método convierte los caracteres especiales en mojibake.

Por ejemplo, usando la misma cadena que la anterior, este método coloca el siguiente texto en el portapapeles:

² ³ é ½ ₭

Sin embargo, puede dar cuenta manualmente de este problema agregando una replace_charsdeclaración para cada carácter especial.


La pregunta:

¿Hay alguna manera de escribir caracteres especiales a través de AppleScript, sin tener que utilizar el portapapeles?

Por ejemplo, ¿hay alguna manera de que pueda agregar los caracteres especiales deseados a un "banco" o archivo de sistema en algún lugar, para que la System Eventsaplicación los conozca?


Respuestas (5)

Es posible con CoreGraphics ( CGEventPost), es una API de C (no funciona en un Cocoa-AppleScript), pero es posible llamar a un ejecutable desde un AppleScript.


Este es el método para crear el ejecutable con Xcode (Versión 8.3.3):

Puedes hacerlo tú mismo (puedes descargar Xcode desde la App Store ), o pedirle a una persona de confianza que cree el ejecutable.

1- Abra Xcode, seleccione el menú " Archivo " --> " Nuevo " --> " Proyecto ..."ingrese la descripción de la imagen aquí


2- Seleccione macOS y Command Line Tool , haga clic en el botón " Siguiente ".ingrese la descripción de la imagen aquí


3- Nómbrelo TypeCharacters, seleccione Objective-C como Idioma, haga clic en el botón " Siguiente ".ingrese la descripción de la imagen aquí


4- Guarde el proyecto en la carpeta deseada.


5- En la ventana de Xcode, selecciona el main.micono, borra el texto de la ventana y pega uno de estos dos códigos:

El código necesita un bucle debido a un error, el CGEventKeyboardSetUnicodeString()método trunca una cadena que supera los veinte caracteres o es un límite (no documentado).

Este código usa un bucle para escribir una lista de caracteres en cada iteración, la lista puede contener de uno a veinte caracteres. (Es rápido, 1 segundo escribir 2400 caracteres en un documento de TextEdit en mi computadora).

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        if (argc > 1) {
            NSString *theString = [NSString stringWithUTF8String:argv[1]];
            NSUInteger len = [theString length];
            NSUInteger n, i = 0;
            CGEventRef keyEvent = CGEventCreateKeyboardEvent(nil, 0, true);
            unichar uChars[20];
            while (i < len) {
                n = i + 20;
                if (n>len){n=len;}
                [theString getCharacters:uChars range:NSMakeRange(i, n-i)];
                CGEventKeyboardSetUnicodeString(keyEvent, n-i, uChars);
                CGEventPost(kCGHIDEventTap, keyEvent); // key down
                CGEventSetType(keyEvent, kCGEventKeyUp);
                CGEventPost(kCGHIDEventTap, keyEvent); // key up (type 20 characters maximum)
                CGEventSetType(keyEvent, kCGEventKeyDown);
                i = n;
                [NSThread sleepForTimeInterval:0.004]; // wait 4/1000 of second, 0.002 it's OK on my computer, I use 0.004 to be safe, increase it If you still have issues
            }
            CFRelease(keyEvent);
        }
    }
    return 0;
}

Este código usa un bucle para escribir un carácter en cada iteración (es más lento que el primer código).

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        if (argc > 1) {
            NSString *theString = [NSString stringWithUTF8String:argv[1]];
            UniChar uChar;
            CGEventRef keyEvent = CGEventCreateKeyboardEvent(nil, 0, true);
            for (int i = 0; i < [theString length]; i++)
            {
                uChar = [theString characterAtIndex:i];
                CGEventKeyboardSetUnicodeString(keyEvent, 1, &uChar);
                CGEventPost(kCGHIDEventTap, keyEvent); // key down
                CGEventSetType(keyEvent, kCGEventKeyUp);
                CGEventPost(kCGHIDEventTap, keyEvent); // key up (type the character)
                CGEventSetType(keyEvent, kCGEventKeyDown);
                [NSThread sleepForTimeInterval:0.001]; // wait 1/1000 of second, no need of this line on my computer, I use 0.001 to be safe, increase it If you still have issues
            }
            CFRelease(keyEvent);
        }
    }
    return 0;
}

Nota : este código funciona en macOS Sierra y debería funcionar en El Capitan , pero no en un sistema operativo anterior .

ingrese la descripción de la imagen aquí


6- Seleccione el menú " Producto " --> " Construir ".


7- Seleccione el TypeCharactersicono en la carpeta Producto , haga clic derecho y seleccione el menú " Mostrar en Finder " en el menú contextual.

ingrese la descripción de la imagen aquí


8- Desde el Finder, mueve el archivo " TypeCharacters " a la carpeta deseada, sal de Xcode , eso es todo.


Desde un AppleScript , llame al ejecutable, así

set myString to "ùéèà ² ³ é ½ ₭ "
do shell script "'/full path/of/TypeCharacters' " & quoted form of myString
Increíble respuesta. Esta solución también funciona perfectamente en OS X 10.11.6. No podría soñar con una solución mejor. También aprecio las capturas de pantalla detalladas. ¡¡¡Muchas muchas gracias!!!
He descubierto un error: si la longitud de myStringsupera los 20 caracteres, la cadena se truncará. Es decir, cualquier texto que siga al vigésimo carácter no se escribirá. ¿Sabes cómo arreglar ésto?
Ahora, uso un bucle para escribir cada carácter (probado con una cadena de 2000 o más caracteres), actualicé el código en mi respuesta.
Su nueva solución ha resuelto el problema. ¡Gracias! Nota al margen, eliminó la #import <Foundation/Foundation.h>línea de su código en su edición, pero esta línea aún es necesaria para una compilación exitosa. Sé que esta línea de código está ahí de forma predeterminada, pero existe cierta ambigüedad porque sus instrucciones dicen "borrar el texto de la ventana".
Creo que la nueva solución tiene un nuevo error. De vez en cuando, al texto escrito le faltará un carácter o cambiará el orden del texto. Esto ocurre sin importar la longitud de la cadena. Aquí hay un ejemplo real: la cadena que se le dio al archivo TypeCharacters fue = 278,932pero se escribió la siguiente cadena: =2 78,93.
No hay errores aquí. Tal vez una (sustitución, una transformación o la ortografía correcta automáticamente) en la aplicación de primer plano. Verifique el reemplazo de texto en las "Preferencias del Sistema". De lo contrario, use el código de depuración (en mi respuesta).
Tal vez ( durante una gran carga de CPU ) el código necesite un pequeño retraso entre cada KeyDown . Intente eso: agregue esta línea al final del bucle [NSThread sleepForTimeInterval:0.02]; // wait 2/100 of second, increase it If you still have issues.. Actualicé el código en mi respuesta. Adjunto otro código en mi respuesta (este código puede escribir 20 caracteres en cada iteración en lugar de un carácter, pruébalo.
Mmm. Definitivamente no es un problema de sustitución/transformación de texto. Además, el problema ocurre incluso cuando no hay otra aplicación abierta, por lo que no depende de la carga de la CPU (y ocurre en cualquier aplicación, desde TextEdit hasta Google Chrome). Restablecí mi NVRAM y SMC; el problema persiste. ¿Quizás es un problema de El Capitán? Por cierto, uso un Retina MacBook Pro de principios de 2013, así que tal vez mi computadora simplemente se esté volviendo vieja y lenta.
Cualquiera que sea el responsable de causar el problema, cualquiera de sus dos nuevas soluciones parece haber detenido por completo el problema. Aquí hay GIF que muestran los resultados en mi computadora: Si uso el primer bloque de código en su respuesta actual. Si uso el código de depuración . Si uso el tercer bloque de código (que modifiqué con un retraso más corto).
Me alegro de que tu problema se haya resuelto. En mi computadora: escribir un carácter en cada iteración no necesita el sleepForTimeInterval:método, pero esto es necesario para escribir una lista de caracteres en cada iteración (si la cadena contiene más de veinte caracteres, por supuesto). Actualicé mi respuesta (limpieza).
Me di cuenta de que este TypeCharactersscript no puede escribir caracteres de nueva línea. Además, si la cadena contiene una nueva línea, entonces no escribirá la cadena en absoluto. ¿Sabe cómo conservar las líneas nuevas en el texto escrito? Gracias.
Dado que esto en realidad simula presionar teclas, si presiona una tecla modificadora durante esto, ¿pueden suceder cosas malas?

Una solución (con el portapapeles):

1 - Puedes usar un método de cacao desde una cáscara:

set tString to "² ³ é ½ ₭"
my stringToClipboard(tString)
tell application "System Events" to keystroke "v" using command down

on stringToClipboard(t1)
    do shell script "/usr/bin/python -c 'import sys;from AppKit import NSPasteboard, NSPasteboardTypeString; cb=NSPasteboard.generalPasteboard();cb.declareTypes_owner_([NSPasteboardTypeString], None);cb.setString_forType_(sys.argv[1].decode(\"utf8\"), NSPasteboardTypeString)' " & quoted form of t1
end stringToClipboard

2 - O un subprograma Cocoa-AppleScript:

use framework "AppKit"
use scripting additions
set tString to "² ³ é ½ ₭"
my stringToClipboard(tString)
tell application "System Events" to keystroke "v" using command down

on stringToClipboard(t1)
    set ca to current application
    set cb to ca's NSPasteboard's generalPasteboard()
    cb's declareTypes:{ca's NSPasteboardTypeString} owner:(missing value)
    cb's setString:t1 forType:(ca's NSPasteboardTypeString)
end stringToClipboard

Para keystrokeun carácter, ese carácter debe asignarse a una tecla real en su teclado seleccionado.

Por ejemplo, puedo usar keystroke é y ² perfectamente, porque estoy usando la distribución de teclado de PC en francés . Sin embargo, un teclado QWERTY estadounidense estándar no incluye esas teclas y no podrá keystrokeusarlas.

Puede definir todos sus juegos de caracteres especiales como variables, así

on specialKeys(input)
    tell application "System Events"
        keystroke input
    end tell
end specialKeys


set characterSet1 to "²³é½₭ "
set characterSet2 to "³ "
set characterSet3 to "é "
set characterSet4 to "¬Ω "
set characterSet5 to "₭ "
set characterSet6 to characterSet1 & characterSet2 & characterSet3 & characterSet4 & characterSet5

specialKeys(characterSet1)
-- ² ³ é ½ ₭ is the result from calling specialKeys(characterSet1) After adding the text replacement for “a a a a a” in my keyboard preferences

Algunos caracteres especiales se pulsan correctamente cuando los establece como variables. Cualquiera de los caracteres especiales que configura como variables que no se pulsan correctamente, puede agregar "reemplazos de texto" en las preferencias del sistema para su teclado.

Asegúrese de seleccionar todos los elementos y arrastrarlos a su escritorio o donde sea. Esto creará un archivo .plist que será una copia de seguridad de su configuración original. Puede arrastrar este archivo en cualquier momento.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Luego, en ScriptEditor, asegúrese de tener habilitados los reemplazos de texto en el submenú "sustituciones" del menú de edición.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

La solución alternativa "Reemplazo de texto" funciona como se desea en la mayoría de las aplicaciones de OS X (por ejemplo, TextEdit, Notes, Script Editor, etc.), pero esperaba una solución que funcionara en todos los campos de texto de cualquier aplicación. Pido mucho, lo sé! Sigo pensando que esta es una solución muy inteligente, así que +1. Gracias por la respuesta.

Podemos ingresar caracteres que no sean ASCII con el portapapeles:

tell application "System Events"
    set textBuffer to "² ³ é ½ ₭"
    repeat with i from 1 to count characters of textBuffer
        set the clipboard to (character i of textBuffer)
        delay 0.05
        keystroke "v" using command down
    end repeat
end tell