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..."
2- Select macOS and Command Line Tool, click on the "Next" button.
3- Name it TypeCharacters
, select Objective-C as Language, click on the "Next" button.
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.
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.
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.