A Tool For Poor Typists - SendKeys
![](https://res.cloudinary.com/strozstuff/image/fetch/https://idmqjyw9i2ib.objectstorage.us-ashburn-1.oci.customer-oci.com/n/idmqjyw9i2ib/b/blog/o/2023/send-keys-intro/header.jpg)
Ask anyone who has had a conversation with me over IM or email, and they will tell you I am a horrible typist. I was never a great typist, but was much better in high school. After graduating, it would be about 13 years before I would need to type again. So, it was like learning all over again.
The Problem
I have gotten better at typing, and usually, my issues stem from trying to type too fast. When writing blog posts or crafting presentations, I have the luxury of tools like built-in spell checkers or Grammarly to help me catch issues before they “go live”. However, about 8 months ago, I started producing a series of short instructional videos for work. I quickly realized that I needed to figure out a way to make capturing my typing easier. I was making so many typos that recording my code samples would take way too long. Then a good friend introduced me to SendKeys.
The Solution
SendKeys is a library that runs on Mac OS (Sorry, Windows users) and allows you to programmatically send keystrokes to apps running on your computer. This was the help I needed. However, I found it cumbersome to set up the commands for SendKeys and then run them while trying to do screen recordings. After some digging around, I discovered that SendKeys has a Node module. I decided to write a wrapper in Node.js, using Express, so I can run my commands from a web browser. I am now making the project known to the public to help all the other poor typists.
Getting the Code
Getting the code is easy. Head to the GitHub repo and clone it.
Install the Dependencies
Once you have cloned the project, navigate to the project directory and run the command:
npm install
Now, we can get started with setting up a command set.
Building a Command Set
Create a JSON file in the command-sets
directory to create a command set. It does not matter what it is named.
The contents of this file should match the structure in the command-set.json.template
file.
{
"name": "Command Set template",
"commands": [
{
"title": "List Folder",
"string": "ls<c:return>",
"target": "terminal",
"delay": 0.1,
"initialDelay": 0.25
},
{
"title": "Clear Console",
"string": "clear<c:return>",
"target": "terminal",
"delay": 0.1,
"initialDelay": 0.25
}
]
}
- The
name
property differentiates one script from another in the web interface. - The
commands
property is an array of commands we can execute.- The
title
property is the title of the command. - The
string
property contains the keystroke definitions sent usingSendKeys
. - The
target
property is the app receiving the keystrokes. - The
delay
property is the time between keystrokes (in seconds). - The
initialDelay
property is how longSendKeys
should delay before sending the keystrokes.
- The
Here is a command set I used for my most recent video.
{
"name": "Date Functions",
"commands": [
{
"title": "First Query",
"string": "<c:l:control>select\n now(),\n curdate(),\n curtime();<p:2><c:return>",
"target": "Tabby",
"delay": 0.05
},
{
"title": "Date Add/Sub",
"string": "<c:l:control>select\n date_add(now(), interval 5 day) date_add,\n date_sub(now(), interval 5 month) date_sub;<p:2><c:return>",
"target": "Tabby",
"delay": 0.05
},
{
"title": "Date Add/Sub Reverse",
"string": "<c:l:control>select\n date_add(now(), interval -2 week) date_add,\n date_sub(now(), interval -2 year) date_sub;<p:2><c:return>",
"target": "Tabby",
"delay": 0.05
}
]
}
You can see that my target
for each of these is Tabby - a multi-platform, tabbed terminal. You will also notice that some blocks are wrapped in < >
inside the’ string’ property. These blocks are instructions for SendKeys
. For example, <:c:l:contro;>
would be the same as typing control + l
. Head to the documentation to learn more about these key codes and modifier keys.
I should point out that for the code above, I also run these commands in Tabby after starting MySQL Shell.
Starting The App
With a command set defined, let’s start the app.
You can use the following command to start the app:
npm run start
However, if you need to tweak your command sets, it might be easier to use:
npm run monitor
This will run the app and refresh the Node side whenever a file changes. You still need to refresh the web page.
The Web Interface
With the app started, navigate to https://localhost:3000
to see the user interface.
Here is the UI for the command set from my last video.
The drop-down at the top will contain references to each command set you have defined in the command-sets
directory.
Each command is listed with the title
, target
, initialDelay
, and delay
. Lastly, each command has a button to run that command. Take a look below to see what the output looks like in Tabby. The delay before the query results are shown is a result of adding a 2-second pause before ‘pressing’ return. This syntax is <p:2><c:return>
.
The Wrap-Up
To recap, I could be a better typist, and sometimes I need to capture video of my typing. Due to my less-than-stellar typing abilities, this would often take a long time to accomplish without having any typos. Thanks to SendKeys and this Node app I wrote, it has become much easier and faster to get my recordings done.
Photo by Patrick Fore on Unsplash