Apple - Is it possible to keystroke special characters in AppleScript?

It's possible with CoreGraphics (CGEventPost), it's a C API (it doesn't work in a Cocoa-AppleScript), but it's possible to call an executable from an AppleScript.


Here is the method to create the executable with Xcode (Version 8.3.3):

You can do it yourself (you can download Xcode from the App Store), or ask a trusted person to create the executable.

1- Open Xcode, select menu "File" --> "New" --> "Project..." enter image description here


2- Select macOS and Command Line Tool, click on the "Next" button. enter image description here


3- Name it TypeCharacters, select Objective-C as Language, click on the "Next" button. enter image description here


4- Save the project to the desired folder.


5- In the window of Xcode, select the main.m icon, clear the text in the window and paste one of these two codes:

The code need a loop because of a bug, the CGEventKeyboardSetUnicodeString() method truncates a string which exceeds twenty characters, or it's a limit (not documented).

This code use a loop to type a list of characters at each iteration, the list can contain one to twenty characters. (It's fast, 1 seconds to type 2400 characters in a TextEdit's document on my computer.)

#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;
}

This code use a loop to type one character at each iteration (It's slower than the first code).

#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;
}

Note : This code works on macOS Sierra and should work on El Capitan, but not on an older OS.

enter image description here


6- Select menu "Product" --> "Build".


7- Select the TypeCharacters icon in the Product folder, right-click and select the "Show in Finder" menu in the contextual menu.

enter image description here


8- From the Finder, move the "TypeCharacters" file to the desired folder, quit Xcode, that's all.


From an AppleScript, call the executable, like this

set myString to "ùéèà ² ³ é ½ ₭ "
do shell script "'/full path/of/TypeCharacters' " & quoted form of myString

A workaround (with the clipboard):

1 - You can use a cocoa method from a shell:

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 - Or a Cocoa-AppleScript Applet:

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

In order to keystroke a character, that character needs to be mapped to an actual key on your selected keyboard.

For instance, I can keystroke é and ² just fine, because I’m using the French — PC keyboard layout. However a standard American QWERTY keyboard does not feature those keys and will be unable to keystroke them.