It is no secret that I have a few things permanently burned into my neurons: the 1802 instruction set, the commands for WordStar, and the commands for emacs. There was a time when emacs was almost my operating system. With no X11, emacs gave you a way to have a shell in one window, check your mail, and keep your work open.
I still use emacs a lot (although I’ve been getting more and more pleased with vscode with an emacs keybinding extension). But I also spend a lot of time — like right now — writing in a Web browser. Especially if I’m writing about code, it gets hard to remember which set of keys you have to use and I’ve wanted to do something about it for a long time. The answer is a very cool program called Autokey. (You can download my files for it, but you probably want to read more first.) It probably doesn’t work if you have switched to Wayland, but it can do a lot for you ranging from saving you some typing to reprogramming your favorite program to have different keystrokes. However, it isn’t without its problems, and I’ll tell you what I know about it.
The Value Proposition
Autokey sits in your system tray and it watches what you type. In its most simple usage, you can set up different phrases to substitute what you type.
For example, I might reprogram HaD to show up as Hackaday to save myself some typing. I usually use some odd character at the start or end so I don’t accidentally trigger things. So maybe I’m tired of typing or mistyping
http://www.hackaday.com. I could set up
~had to automatically type the correct URL for me.
Scripts vs Phrases
If that’s all AutoKey did, it would be pretty handy. But it does a lot more than that. On the other hand, if that’s all you want, it is easy to set up using phrases. A phrase has two parts: a trigger and some text. The trigger can be a hotkey (like Alt+Shift+F6) or it can be text you type like
~had. It is possible to add multiple abbreviations, so I could have extra triggers of
http://www.hakday.com if I wanted the program to automatically correct my bad spelling.
A phrase can only have one hotkey, but you can have a hotkey and abbreviations; either will trigger the phrase. Of course, you can also support multiple hotkeys with multiple identical entries. Finally, you can limit the match to a particular window class matched with a regular expression. So it is possible to have one set of shortcuts for your word processor and another set for your web browser.
The real power, though, is that you can create scripts instead of phrases. These are exactly the same except instead of typing a phrase, a piece of Python code runs. There are some classes to help you do things like control the keyboard and mouse from a script. You can even create GUI dialogs using QT or GTK. However, I found out there is a slight downside to using scripts, but for many things, they work great. You’ll see what I mean in a bit.
In addition to scripts, phrases can have certain dynamic content like the date, a file, or even the output of a program. There are also provisions for positioning the cursor at a certain spot after the text entry is done which is useful for creating code snippets.
There are a few useful options you can apply to abbreviations. For one thing, you can control how they send text to the target program. I usually use the keyboard method to simulate typing because I will use special characters, but you can also paste the text in using one of several common shortcuts. That is, the program can load the clipboard with your phrase and then paste it with a Control+V.
The real power comes when you set up the abbreviations. A dialog lets you select a list of trigger words and you can set options. By default, the abbreviation won’t expand until you type some non-word character. You can also require a space or tab. However, there are other options. For example, you can have Autokey trigger immediately or even if the text is part of another word. There are options to ignore or respect case, among others.
The final thing you can use to control the triggering logic is to restrict a script or phrase to a window class that matches a regular expression. This is great because you probably don’t want to map strange things to all windows. Sure, it is handy to have
!address enter your mailing address in every program, but if you want to make
main expand to a boilerplate main function, you might not like that happening in LibreOffice.
In my case, the window class feature was pretty important because I didn’t want to remap things like control+s in every program, just the browser.
So, how do you put all this together to emulate emacs? Most of the commands are very simple. For example, in emacs, control+s starts a search, so it is sufficient to create a phase with that hotkey that types: <ctrl>+f which the browser knows is a search. Obviously, you can’t easily do things the browser doesn’t already know how to do. Control+r for reverse search, for example, is not feasible. I wound up mapping a little more than a dozen basic emacs commands that way. I did disable the control+w hotkey to do a clipboard copy because the browser uses that to close a tab, and I didn’t want to block that.
I used the built-in tool to find the class for the Vivaldi browser I use. I would find out later that I needed to make a change in this area, as you will see.
For now, that took care of the one key commands. However, there are also the two-character commands. I had a plan, but that plan didn’t work very well. For now, I’m just living without them, but I did leave a disabled example in the code for your review.
Since you can execute a script and there is a global variable storage mechanism for scripts, my plan was simple. Consider control+xu which is emacsese for undo. You can’t use a non-printing character in an abbreviation, so you have to handle the situation with a single hotkey. My plan was to set control+x to turn on a prefix flag in the script global storage. Then I could use Autokey to treat u as a hotkey — just the letter u — and either send a u or a control+z, depending on the state of the flag. Coincidentally, the code would also reset the flag.
There are problems with this even if it all worked well, which it didn’t. For example, if you pressed control+x and then an unexpected key, the flag stays set and the next time Autokey sees a u, you’ll get an undo. That would surprise you! It seems like the right thing to do would be to enable a catch-all rule that disables itself or have the script read a key. However, it doesn’t seem possible to do this, at least, not easily.
I was, however, willing to accept that limitation. I wrote a little Python code for control+x:
Then, just to test one thing at a time, I did the following for the letter u:
state=store.get_global_value("vmacs-prefix-x"); if state == "true": keyboard.send_keys("<ctrl>+z"); store.set_global_value("vmacs-prefix-x","false"); else: keyboard.send_key("U"); # note send key will respect shift, etc.
I was pleased that it worked. Sort of. When I was typing, I noticed that something was off. I type rather fast but something kept distracting me and I couldn’t figure out what it was. I finally realized that when any Autokey script or phrase runs, the browser loses focus for just a tick. When you are pressing some cursor command you don’t notice, but when you are typing at speed, look out! I left the scripts, but turned them off just like I did with control+w. You may not be as sensitive to the brief disconnects and, if so, you might want to implement other two-key combinations in a similar way.
The other problem I had was a big disappointment. The macros didn’t work in multiline editors or WordPress, where I spend way too much time. A quick check shows that the edit boxes have a different Window class. I wound up turning the filters into a regular expression:
.*Vivalid-stable. Of course, if you are using a different browser, you’ll need to adjust.
I am still a little disappointed that while the two-key combinations are feasible, they aren’t practical for me. I suspect this would bite you if you were trying to simulate vi, as well, since you would have to catch nearly every normal key.
Still, I wrote this whole post using emacs semantics, and other than occasionally forgetting to paste using control+y, it went great. I may yet turn control+w back no because I have accidentally closed the window a few times when I was trying to paste.
There are browser extensions that purport to let you edit text fields in your chosen editor. They do work, but they are little more than just copying text back and forth to the editor. That’s great for small things, but trying to work up a large post with WordPress features is not really practical. With this system, you can have emacs semantics while editing text and in the URL bar. It would be trivial to adapt the system to nearly any program.
You may not care about emacs, but there are plenty of timesaving things you can do with a program like Autokey. From shortcuts for URLs, to bash one-liners, to things you type over and over again, Autokey is both simple to set up for simple things and complex enough to handle big jobs. I just wish it worked on Wayland.