RoboFont has an interface for defining keyboard shortcuts or “Hot Keys” for menu items, the Menu Preferences. With a bit of code, we can also create custom Hot Keys for actions that are not available in the UI.

In this example, we’ll show how to use an observer to make the Glyph Editor jump to the foreground layer when the f key is pressed.

Creating a basic controller object

We’ll start by creating a new Python object, using a class definition.

class JumpToForeground(object):

    def __init__(self):
        print("Initialized!")

JumpToForeground()

In the above script, a new JumpToForeground class is defined which contains one function, named __init__. The last line of the script calls the JumpToForeground class to construct a new object. The __init__ function is a special one, you’ll notice that it’s automatically run when the object is constructed — if everything worked correctly you should see a printed output of the word Initialized! showing that the __init__ function was called.

So here’s the plan — now that we have a definition for a new object, let’s make it do something useful:

  • have the object observe for a notification from RoboFont that a key has been pressed
  • define a callback function in our object that should be executed when that notification comes in

Adding a callback function

Let’s start by adding the callback function, keyWasPressed, which will contain the code that should be run when a notification comes in:

class JumpToForeground(object):

    def __init__(self):
        print("Initialized!")

    def keyWasPressed(self, info):
        print(info)

JumpToForeground()

Adding an observer for key events

And then let’s add an observer to listen in for a notification.

To observe for notifications, start by importing addObserver from mojo.events at the top of your script, as seen below. Then, instead of simply printing something in the __init__ function, go ahead and run the addObserver function at startup.

from mojo.events import addObserver

class JumpToForeground():

    def __init__(self):
        addObserver(self, "keyWasPressed", "keyDown")

    def keyWasPressed(self, info):
        print(info)

JumpToForeground()

You’ll notice that addObserver needed three arguments:

  • the self will tie our new JumpToForeground object to the observer
  • the name of the callback function that should be run when the correct notification comes in (in this case keyWasPressed)
  • the name of the notification that we wish to observe for (in this case keyDown)

I found this keyDown notification name by running the Event Observer extension and taking note of the notifications that were broadcast when typing a key when a glyph window was open.

The event info dictionary

Now, when you run the script, nothing will happen at first, but when you press a key down in a glyph window, a dictionary of info about the event will be printed to the output:

{
    'event': NSEvent: type=KeyDown loc=(476.078,629.277) time=354798.6 flags=0x100 win=0x10b7cb190 winNum=46377 ctxt=0x0 chars="a" unmodchars="a" repeat=0 keyCode=0,
    'notificationName': 'keyDown',
    'tool': <__main__.ScalingEditTool object at 0x112c82be0>,
    'view': <DoodleGlyphView: 0x10b7d64d0>,
    'glyph': <RGlyph 'P' ('foreground') at 4621436856>
}​

There’s a lot going on in there, but there’s really a lot of useful information about what just happened! Among other things, notification lets us know which glyph the event occurred in, and which characters had been typed.

Observing one particular key

We only want to take action when the f key is pressed, so let’s make a few changes to the script.

from mojo.events import addObserver

class JumpToForeground():

    def __init__(self):
        addObserver(self, "keyWasPressed", "keyDown")

    def keyWasPressed(self, info):
        event = info["event"]
        characters = event.characters()
        if characters == "f":
            print("f was pressed!")

JumpToForeground()

If you run this updated script you’ll notice two things: a message is printed only if you type the f key, but the entire info dictionary is still being printed even though we’re not asking for it any longer! This is because our script only uses the addObserver function and doesn’t removeObserver yet when it’s no longer needed. So, each time you run the script you’ll be adding yet another copy of the object which will keep running until RoboFont has been quit.

In the end this is what we want, our final script will be run one time on startup and will continue to run in the background waiting for the keyDown event to happen. But, while you’re working on writing the script you’ll need to restart RoboFont each time you wish to run any revised code to kill off any older versions that are still running in memory.

Once you’ve done that you should notice that the script only responds to the f key.

Switching layers when a key is pressed

It needs one last thing, we can import the SetCurrentLayerByName function from mojo.UI to call when the f key is pressed:

from mojo.events import addObserver
from mojo.UI import SetCurrentLayerByName

class JumpToForeground():

    def __init__(self):
        addObserver(self, "keyWasPressed", "keyDown")

    def keyWasPressed(self, info):
        event = info["event"]
        characters = event.characters()
        if characters == "f":
            SetCurrentLayerByName("foreground")

JumpToForeground()

Setting the script as a start-up script

And that’s it! Save this script in a place you can keep track of, and from the Extensions Preferences, you can add this as a Start Up Script so that it’s always run one time when RoboFont launches.


Contributed by Andy Clymer.

Last edited on 26/09/2018