A few keyboard helpers for AppleScript
I use a bit of UI scripting to automate some of the screenshots used in Marked marketing and documentation. One (significant) part of that scripting is sending keyboard commands, so I’ve built a few routines to help out.
The script includes 3 different routines. The base is keyCmd(_string)
. It takes a single key, with modifiers either typed out or defined using DefaultKeyBindings-style shortcuts, where “$” is Shift, “~” is Option, “^” is Ctrl, and “@” is Command. So you can send either “cmd i” or “@i”. Named keys are recognized, so you can also use “shift opt left” to hit ⇧⌥←. When using named keys, you need to either have a space after shortcuts (e.g. “$~ left”), or use the string versions, as in the previous example.
keySeq
is a shortcut for sending a batch of keyCmd
s at once, e.g. keySeq("@n $~@s",1)
to send Command-N followed by Shift-Option-Command-S. The second parameter is the delay between keys, 0 for none.
keyType
takes a string and a delay and types each character out, simulating keyboard typing. This command doesn’t allow modifiers, just characters, and the modifier shortcuts are typed as characters. Running keyType("This will type out in whatever field is focused",.01)
will simulate typing the sentence out with a very brief delay between each keystroke.
I’m just sharing these in case they’re of use in your own scripting. If I get around to it, I’ll share more of my routines for window manipulation, menu clicking, and screen capture. I’m certain I can name several readers who will know of more elegant ways to accomplish all of these. I’d be delighted to update with your genius if you share it.
-- set the application to type into
-- you need to activate and focus a window prior to calling keyCmd
property process_name : "Finder"
on lowercase(_text)
set _output to do shell script "echo " & quoted form of (_text) & " | tr A-Z a-z"
return _output
end lowercase
(* Trigger a hotkey or character
Usage: keyCmd("hotkey to trigger")
Shortcuts:
$ : shift
~ : option
@ : command
^ : Control
Examples:
Trigger "k"
keyCmd("k")
Trigger "K"
keyCmd("K")
keyCmd("$K")
Trigger Command-down arrow
keyCmd("cmd down")
Trigger Command-I
keyCmd("cmd i")
keyCmd("@i")
Trigger Shift-Option-Command-S
keyCmd("shift opt cmd s")
keyCmd("$~@s")
*)
on keyCmd(_string)
set _mod to {}
set _codes to {{name:"left", code:123}, {name:"right", code:124}, {name:"down", code:125}, {name:"up", code:126}, {name:"escape", code:53}, {name:"esc", code:53}, {name:"pgdown", code:115}, {name:"pgup", code:119}, {name:"home", code:116}, {name:"end", code:121}, {name:"f1", code:122}, {name:"f2", code:120}, {name:"f3", code:99}, {name:"f4", code:118}, {name:"f5", code:96}, {name:"f6", code:97}, {name:"f7", code:98}, {name:"f8", code:100}, {name:"f9", code:101}, {name:"f10", code:109}, {name:"f11", code:103}, {name:"f12", code:111}, {name:"f13", code:105}, {name:"f14", code:107}, {name:"f15", code:113}, {name:"f16", code:106}, {name:"f17", code:64}, {name:"f18", code:79}, {name:"f19", code:80}, {name:"f20", code:90}, {name:"delete", code:51}, {name:"del", code:51}, {name:"tab", code:48}, {name:"return", code:36}, {name:"enter", code:76}, {name:"space", code:49}, {name:"shift", code:60}, {name:"option", code:61}, {name:"opt", code:61}, {name:"control", code:62}, {name:"ctrl", code:62}, {name:"command", code:55}, {name:"cmd", code:55}, {name:"capslock", code:48}}
if _string contains "cmd" or _string contains "command" or _string contains "⌘" or _string contains "@" then set end of _mod to command down
if _string contains "shift" or _string contains "⇧" or _string contains "$" then set end of _mod to shift down
if _string contains "opt" or _string contains "option" or _string contains "⌥" or _string contains "~" then set end of _mod to option down
if _string contains "ctrl" or _string contains "control" or _string contains "⌃" or _string contains "^" then set end of _mod to control down
log (_string)
try
set _key to last item of words of _string
on error errMsg number errNum -- errors if string is punctuation
set _key to _string
end try
if _key contains "$" or _key contains "@" or _key contains "^" or _key contains "~" then
set _key to last item of characters of _key
end if
set _code to 0
set _maybe_sys_key to my lowercase(_key)
repeat with _keycode in _codes
if name of _keycode is equal to _maybe_sys_key then
set _code to code of _keycode
end if
end repeat
log (_code)
tell application "System Events"
tell process process_name
if _code > 0 then
key code _code using _mod
else
keystroke _key using _mod
end if
end tell
end tell
end keyCmd
(* trigger a sequence of keystrokes
_sequence: Pass either a space separated string or a list of quoted keys
_delay: delay between characters, 0 for none
Usage: keySeq("character list with shortcut modifers", 0-9)
Example:
Hit ⇧⌘K and type "test"
keySeq("$@k t e s t")
keySeq({"shift cmd k","t","e","s","t")
Select two words left
keySeq({"shift opt left", "shift opt left"})
*)
on keySeq(_sequence, _delay)
if class of _sequence is not list then
set {astid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
set _sequence to every text item of _sequence
set AppleScript's text item delimiters to astid
end if
repeat with _key in _sequence
if _delay > 0 then delay _delay
keyCmd(_key)
end repeat
end keySeq
(* Type a string, no modifiers, with delay
_string: characters to type
_delay: float delay (0 for none)
Usage: keyType("testing something out", 0.1)
*)
on keyType(_string, _delay)
tell application "System Events"
tell process process_name
repeat with _chr in characters of _string
if _delay > 0 then delay _delay
keystroke _key
end repeat
end tell
end tell
end keyType
-- example
set process_name to "TextEdit"
tell application process_name to activate
-- create a new doc, convert to rich text, type tab
keySeq("@n $@t tab", 1)
-- type out a sentence at a decent simulated typing speed
keyType("This is going to type out in TextEdit", 0.02)