Home
Head's Up: I'm in the middle of upgrading my site. Most things are in place, but there are something missing and/or broken including image alt text. Please bear with me while I'm getting things fixed.

Exmaples Of Sending Simulated Keystrokes To Mac Apps With OSA/JXA JavaScript

One of my favorite little hacks is being able to send key presses to mac apps from apple's javascript functions. I used it to put together a script to automate text for making gifs.

Here's a basic example :

js
// File: hello-world.js

  const sys = new Application('System Events')
  const app = new Application('Stickies')

  app.activate()
  sys.keystroke('hello, world')

That script opens the built - in Stickeis app and types 'hello, world' when you run it with :

osascript -l JavaScript hello-world.js

Sending letters with a modifiers (i.e. shift, command, option, control, or function) is done like this :

js
// File: upper-case.js

const sys = new Application('System Events')
const app = new Application('Stickies')

app.activate()
sys.keystroke('this is upper case', { using: ['shift down'] })
osascript -l JavaScript upper-case.js

Add multiple modifiers to the array if you need more than one. For example, [TODO: Code shorthand span ] + [TODO: Code shorthand span ] + ` c ` opens the colors pallet in the Stickes app. The scripting approach to that is :

js
// File: color-pallet.js

  const sys = new Application('System Events')
  const app = new Application('Stickies')

  app.activate()

  sys.keystroke('t', { using: [
      'command down',
      'option down'
  ] })
osascript -l JavaScript color-pallet.js

(TKTKTKT - Test examples of option, control, and the function key to verify they work as expected.)

There are some keys (like the arrow keys) that don't work with the [TODO: Code shorthand span ] method. The way to get to them is to use the internal code for the key with the [TODO: Code shorthand span ] method.

For example, if you still have the test sticky note from above open, this will move the cursor back one chracters.

js
// File: arrow-press.js

  const sys = new Application('System Events')
  const app = new Application('Stickies')

  app.activate()
  sys.keyCode(123)
osascript -l JavaScript arrow-press.js

For example, this mimics pressing the F3/Mission Control key.

js
const sys = new Application('System Events')
  sys.keyCode(160)

** NOTES

- TKTKTKTK Note the difference between Enter and Return (and how that doesn't matter most of the time)

- TKTKTK Note the differences between the function keys that have two sets of codes and check to see if the other F keys do as well.

- TKTKTKT Note the media keys that do and don't work.

- TKTKTK Do examples with "command down" type stuff on keyCode() calls to check functionality.

- Some things don't work the way you'd expect (or don't work at all). For example, I can't do the equivelent of [TODO: Code shorthand span ] + [TODO: Code shorthand span ] + [TODO: Code shorthand span ] to take a screenshot. Seems like that should work, but it doesn't. You'll likely run into other things like that were you need to find another approach to the automation.

- These examples are a bit contrived. I don't know why you'd want to open the color pallet in the Stickies app, but that's not the point. The goal is to show how the tools work.

- While these examples are all JavaScript you can also use AppleScript to do the same thing.

- TODO : Put in AppleScript examples or make a version of this page with ApplieScript

- Sometimes the speed of the keystrokes comes into play and goes too fast if you're swithing things around. Adding a delay can help alleviate that.

bash
The code blocks below are only for testing the
  code in the main body of the post.
bash
cat <<- "EOC" > /private/tmp/emacs_tmp_1.txt
  <<source_hello_world>>
  EOC
  osascript -l JavaScript /private/tmp/emacs_tmp_1.txt
            
  osascript -l JavaScript -e "Application('Emacs').activate()"
bash
cat <<- "EOC" > /private/tmp/emacs_tmp_2.txt
  <<source_upper_case>>
  EOC
  osascript -l JavaScript /private/tmp/emacs_tmp_2.txt
            
  osascript -l JavaScript -e "Application('Emacs').activate()"
bash
cat <<- "EOC" > /private/tmp/emacs_tmp_3.txt
  <<source_color_pallet>>
  EOC
  osascript -l JavaScript /private/tmp/emacs_tmp_3.txt
  sleep 0.2
  osascript -l JavaScript -e "Application('Emacs').activate()"
bash
cat <<- "EOC" > /private/tmp/emacs_tmp.txt
  <<source_arrow_press>>
  EOC
  osascript -l JavaScript /private/tmp/emacs_tmp.txt
  sleep 0.2
  osascript -l JavaScript -e "Application('Emacs').activate()"