32
\$\begingroup\$

Here's a little script that enters text into a document when activated.

tell application "TextEdit"
 activate
end tell
delay 0.2
tell application "System Events"
 keystroke "Hello World!"
 keystroke return
end tell

I stuck the delay in there because otherwise the first few keystrokes tend to trigger before the window is done activating, so I end up with "lo World!" in the document and "Hel" in whatever other window had focus when the script was activated. Is that the proper use of delay, or is there a better way to circumvent that problem?

200_success
146k22 gold badges191 silver badges481 bronze badges
asked Dec 17, 2014 at 22:00
\$\endgroup\$
8
  • 17
    \$\begingroup\$ Hello and welcome Abby and all to Code Review. Just as a head's up to all, these comments will be regularly monitored, and purged. Have (courteous) fun. \$\endgroup\$ Commented Dec 17, 2014 at 22:10
  • 1
    \$\begingroup\$ You might find this blog useful. \$\endgroup\$ Commented Dec 17, 2014 at 22:26
  • 1
    \$\begingroup\$ Wiki Books has a code example that is similar here: en.wikibooks.org/wiki/AppleScript_Programming/System_Events This would seem to be an accepted practice due to the lack of custom events in Applescript (stackoverflow.com/questions/3127153/…). \$\endgroup\$ Commented Dec 18, 2014 at 16:41
  • 1
    \$\begingroup\$ Is your intention to insert "Hello World!" wherever the cursor happens to be? \$\endgroup\$ Commented Dec 18, 2014 at 17:22
  • 3
    \$\begingroup\$ Despite being on permanent patrol for all other things Apple here on Code Review, and contrary to popular belief, AppleScript is outside my realm of expertise. With that said though, I believe this is our first AppleScript question? And I'm left wondering why we don't have an AppleScript FizzBuzz. Look out CodeReview... \$\endgroup\$ Commented Dec 25, 2014 at 1:32

2 Answers 2

11
+100
\$\begingroup\$

Rather than using System Events to generate keystrokes, consider using TextEdit itself to insert text.

tell application "TextEdit"
 activate
 tell first document to set its text to its text & "Hello World!\n"
end tell

There is a difference, though: this version always appends "Hello World!" to the end of the document, rather than wherever the cursor happens to be. (Unfortunately, TextEdit's AppleScript dictionary mentions nothing about cursors.)

A side benefit of this approach is that you don't have to grant permission to use Assistive Access to your script.

answered Dec 18, 2014 at 17:23
\$\endgroup\$
7
\$\begingroup\$

Assuming that you want to stick with the original plan to insert text wherever the cursor happens to be, you would need something more deterministic than an arbitrary delay.

This script covers all the scenarios that I can think of:

tell application "System Events" 
 -- In case TextEdit was already running and all windows were closed
 repeat until first window of application "TextEdit" exists
 tell application "TextEdit" to make new document at the front
 delay 0.001
 end repeat
 -- Ensure TextEdit can have focus
 repeat until process "TextEdit" is frontmost
 set frontmost of process "TextEdit" to true
 delay 0.001
 end repeat
 -- Give focus to the window
 set focused of first window of process "TextEdit" to true
 keystroke "Hello world\n"
end tell

In particular, the scenarios I tested include:

  • TextEdit was not running at all
  • TextEdit was running, but had no document windows at all
  • TextEdit was already running with one or more windows

To convince yourself that the technique is sound, try each of these scenarios with the loop bodies commented out, and you should see that the script will wait until the conditions are appropriate before continuing.

There is no guarantee, however, that the user won't deliberately try to induce a race condition while the keystrokes are being sent.

answered Dec 20, 2014 at 22:03
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.