Evolutions of a script I have been using for 8 years straight

Eight years ago (maybe even longer), I started using an AutoHotkey script that you can download for free, apparently it was first published in 2013, which puts it at 12 years old now. I must have been a somewhat early adopter of it, back in the day.

What it does is simple:

  • You make a typo

  • You press WindowsKey-M

  • The script selects the last word you typed and opens an input box

  • You type your text replacement

  • You never make that typo again

That is huge, the more you type, the more you save. Not just time, also focus loss, key presses, and I can type a lot faster than I otherwise could, because I know that the results will be legible even when I type with closed eyes, shortly before falling asleep.

I want to write about the evolutions that this script has gone through for me, because I think we can learn a lot about iterative processes, practical concerns, and feature creep that serves me well instead of hindering me.

The very first evolution: Capslock

I can not tell you how often I have sighed when I accidentally pressed capslock. I don't know why that key is there at all, I have never used it. I especially don't get why it has such a prominent place right to the left of my home row.

One of the very first things that I realized is that pressing Windows-M was nice, but several times too slow for something I was going to use thousands of times. So now, I use capslock to enter a new text replacement, and it is amazing how quick that made using this script. It becomes literally faster to enter a new replacement than it would be to fix that typo even once, because even control-backspace is more key presses and takes more time. No longer.

In my opinion, this tiniest of changes has upped the script from a fun novelty to a highly efficient method of saving years of my time and a lot of strain on my fingers. A lot of us programmers are fast with correcting typos, but even then, I estimate it takes a minute of our time to fix one, between the focus loss, the opportunity costs of not being able to write instead of fixing, and the fact that you have to go over your text and edit it after finishing it. At this point, my script has grown enough to where I usually don't have to edit, which saves about half an hour or even more on a post like this. I will try not to edit anything at all on it so you can see the effects.

The second evolution: Using exact matching because the automatic rules get in the way

In the first two years, I must admit that I struggled with the script sometimes, and had to correct errors that the script was making. The reason were the automatic rules, like automatic capitalization after a sentence start. Nice idea in theory, but they got in the way and didn't always work, and sometimes messed with the typo correction because the sentence-start rule would trigger before the typo correction, and then I had a nicely capitalized typo instead of a regular one.

In the end, I ended up throwing all the automatic rules out, and going with the option to have exactly-matched replacements only. That means I might have to press that capslock button a few more times, but now I can make sure that I don't suffer from a good thing. If I mistype that word twice in two different ways, I'll add two corrections to my file.

Side note: I now have over 20,000 text replacements in my file and there is zero lag in the replacements, they happen so fast that you don't really notice more than a flicker on your screen. Very impressive for 12 year old tech.

Takeaway: Anyone who has worked with RegEx before will know how bitchy those statements can get, not giving you the results you wanted even though they worked perfectly fine in testing, simply because you didn't consider some edge case. So, the takeaway I got from this was dont act like you're smart enough for RegEx magic when you can go with simple replacements. That has proven to be a good rule at work, too.

The third evolution: Creating an identical copy to support bilingual use

I am German by birth, and sometimes I can't help but speak or write it. Very early on into my usage of the script, I realized that rules that make sense for English create errors for German. Some words are the same, but capitalized differently, and common mistakes in English might be fine in German, or vice versa.

Back then, I saw no good option to throw it both into one script, so I created an identical copy and switched between the two anytime I felt a larger German text approaching. That led to a few things:

  • I never used the German version because manual switching takes too long

  • I routinely added English corrections to the German file, or the other way around, making me sigh and manually edit the file to copy and paste it where it belonged

  • Surprise, I used the German version even less

What I think we can learn from this is that a good thing can still get in the way, and that your users will stop using something that gets in the way for them when the usability is bad - even though this script might be one of the purest forms of speed improvement and practicability that I have found in my 15 years in tech. It is really good - and I still wasn't using it.

The fourth evolution: Adding abbreviations instead of just typos

It took me a while to realize that I was using only half of the script's potential, and really only used it to fix my mistakes. However, these days, I average around 30-50% less key presses on every text that I type, simply because it lets me type stuff like "stuf", or "leters" or "abbrs" instead of "abbreviations".

The interesting thing here is that unlike my earlier struggles, this does not get in the way of me just typing manually. If I want to type the word out completely, I just do it, and the way I think for a second before adding one of these corrections means I don't add any false positives.

I found it interesting to study how words behave and how many of them have stuff in them that we really don't need, like double-letters, "uou" constructs and the like. Like I said, I am German, so a lot of my originally learning English process was remembering rules that don't really make sense to a foreigner. You think about words a lot more deeply, like "why is the word queueueueueue not just spelled "Q"?"

Continuously is one of those words - what even is that? That might as well be written continsly or something like that.

The fifth evolution: Actually bilingual

In the past two years, I found myself writing a lot more in German than I was used to, and I really started to miss the benefits of my script. I felt sluggish writing in my mother tongue, and like a speed demon in English. I dreaded writing in German, and that still hasn't really left me today.

So, one of the first things I did when I started experimenting with LLMs was to see if I couldn't improve this somehow. AutoHotkey is an ancient scripting language and very hard to design features for when every step of the chain makes you struggle with the lingo instead of the actual design challenge. In short: I was too stupid to make anything work that could give me an easy switch between two languages.

The solution it came up with seems a bit fragile, but it has proven 100% reliable. It works like this:

  • I press left shift and right shift together (I requested this, it seemed like a good shortcut that you only press consciously)

  • It gives me a notification in the bottom right corner to tell me what language I am in now

  • Any new replacement gets added to the right language of the script file by finding a marker in the text like "here be English" (This is the part I found iffy, but it works well)

Takeaway: I had the general problem identified for years, but the solution was outside my skill set, and while I understand the principles behind it, I still couldn't write the same thing because I struggle so much with the actual language. I am 15 years deep into programming, and have written thousands of line of code in a dozen language, but this one made me give up on a script I was using every single day.

I find this interesting because it shows that while we all shrug and say "I don't care about the language I write in", it does still matter quite a bit. Writing this in Python would be completely differently, probably with a tiny database in the background or just pulling from two text files in the working directory instead of stuffing it all into one script file. But I want it in one, because that makes it much easier to transport and use, just one file and no setup guide other than "put that in your startup folder".

The sixth evolution: Making it stay in the same language

While the language switching feature worked perfectly, I quickly found that I had made a design error by implicitly expecting a feature instead of spelling it out in the prompt/requirement document. Classical user-wants-stuff error: I forgot to say that I would like the script to stay in the language it was in when I added a new correction.

I had originally assumed that I wouldn't mind having the script start in German by default when I boot up my computer, and then switch first thing if I knew I would be writing in English. That part turned out true, there is very little friction apart from the occasional "oh right I forgot" when I make the first typo in English because I haven't yet switched. No problemo.

The actual issue arose with the way that this script works under the hood when you enter a replacement: It adds a line to its own file, then reloads itself. Quite nifty, but in this case, it would add an English replacement, and then reload itself to the German default. Or the other way around, no matter which way I would have written it.

I stuck with this flaw for like a week, just getting into a habit of pressing both shift keys after adding a replacement - but I knew I didn't want that long term. The solution that sprung up immediately was to have a config file next to the script, but I wanted to avoid that because again, I like having just one file.

It took some time before I realized that this was still the easiest way, that I could just write an initial config file if it wasn't where the script expects it the first time, and then never bother again. I still just need to bring the main script file, it is pretty much independent and just assumes German default the first time it starts, after which it starts up with the configured language and changes the config file if I press both shift keys.

This has proven to be 100% reliable and super convenient, and I have been using this for about a year now with absolutely zero friction.

Takeaway: small evolutions can feel like big revolutions

Every time I upgraded my script, it felt like unlocking a whole new layer of speed and usability. Now, for the past year, I have not seen the need to make any changes, this last part of staying inside the same language was really the last piece of the puzzle that I was missing.

I tracked the time that it took to write this whole blog post and it turns out that I needed exactly 35 minutes to write what amounts to 2067 words right here, 2070 now. That is pretty damn fast when you consider I needed to come up with the structure, write it all out, and drink coffee in between. There is a good chance it would have taken longer to write this with an LLM and correct it into a usable state afterward than it is to just type it all out flat in one go.

A few minor takeaways:

  • The differences between German and English are quite interesting, I feel like German profits mostly from allowing me to write in all lowercase and automatically capitalizing nouns, while English profits most from abbreviations for words that take forever to type like those words with uou in them.

  • I can't seem to convince other people of using this, to the point where I have heard several times "I prefer to just learn how to type". A lot of people don't see the use, and just watching them share their screen while they write a single email makes me silently point and go "there! you would have just saved five minutes, and I mean MY FIVE MINUTES WATCHING YOU FIX THREE TYPOS PER SENTENCE OH MY GOD". You can't convince people to use something where the problem is too small individually for them to recognize it as a problem.

    • It's the same with macros, automated deployments, automated tests - a lot of people don't see the use, even while it can take a whole hour out of their days sometimes. But the fact that they lose it "just ten minutes of work at a time" means they are completely oblivious to the cumulative time wasted for zero benefit. It's not like deploying code profits from the loving human touch - on the contrary, every manual deployment opens up the doors to avoidable mistakes like deploying the DEV config to production.

  • This script is the main reason why I sold my MacBook after a year of experimentation, they don't really have a similar equivalent software, and systemic rules in place that prevented me from building one (they don't seem to like hooking into keyboard events programmatically, I wonder why). I find this quite interesting because the two operating systems look so similar on the surface now (virtually no difference between Windows 11 and MacOS apart from shifting the close-me-X from the right to the left) - but there are key differences that make you either stick with one or the other as soon as you open the hood to stare at the engine.

  • Linguistics are a fascinating field. I was surprised to find the word "stumm" / "shtum" being an English word with the same meaning, which led me on a journey to realize that many of these words have their origin in yiddish, and that is how they made their way across the pond. It is sometimes quite fascinating to see the paths that language takes, as with words like Kindergarten / kindergarten in English.

I hope you found this post useful, either on a software design level or maybe even because you become the first person I can convince of using the script yourself 😀 By the way: I added 8 new replacements to the script while writing this for words that I apparently haven't messed up before.

Edit: Here is the script with all my personalized corrections removed if you want to test it yourself: https://pastecode.io/s/oah5q334