Mac Terminal App and Special Key Mapping

Mapping key presses in Apple’s macOS Terminal app

For fun I like to write command line applications in C using VIM. It’s like rolling back the calendar to a golden age before mice and OOP ruined everything. The discipline of writing and debugging a C99 program without a modern IDE’s firehose of autocompletion suggestions is like zen meditation for me. I have to be totally focused, totally present to get anything to compile!

Apple’s Terminal app is fine. There are other options, many of them awesome, but as part of this painstakingly minimal approach I just want to stick with vanilla. Even my vim.rc file is vanilla.

So far I’ve only run into one super annoying problem with Terminal and processing key presses with C99’s ssize_t read(int fildes, void *buf, size_t nbytes)!

Apple’s Terminal doesn’t send me some of the special keys by default. Specifically <PAGE UP> and <PAGE DOWN>. And I am betting that other, like <HOME> and <END> may have been overridden as well.

I need <PAGE UP> and <PAGE DOWN> to send read() the ASCII codes "<esc>[5~" and "<esc>[6~" respectively so I can pretend it’s 1983! (The original Macintosh was put on sale to the public in 1984 and after that it’s been all mice and OOP).

But there is a cure for Terminal!

Under the Terminal menu choose Preferences and click the Keyboard tab for the profile you are going use as a pre-GUI app shell. Press the tiny + button to “add key setting”. Select your special key from the key popup and make sure modifier is set to “none” and action is set to “send text”.

If you want tom map <PAGE UP> to its historically accurate function click into the input field and hit the <ESC> key. Terminal will populate the input field an octal escape code (\033).

So far this has been the hardest part of the exercise and why I wrote this blog post for posterity. If you need to remap key codes you probably know that <ESC> is \o33. You might think the letter o is the number 0 but then you have bigger problems if you are writing a C99 program like me.

Anyway, the rest of this exercise just involves normal typing of keys that turn into letters in the expected way!

Making <PAGE UP> send <esc>[5~ to STDIN_FILENO

This is all just bad behavior for so many reasons. What makes the Terminal beautiful it that works with ASCII codes that are both Integer values, Character values, and key codes. These ASCII code describe the data and the rendering of the data on the screen. If Apple, anybody’s, Terminal app diverts a key code so that that read() can’t read it–well it’s a web browser that doesn’t conform to HTML standards.

You might be thinking: “Who cares about a terminal app in this age of 5G, Mixed Reality, Machine Learning, Cloud-based, Retina Displays?”

Under all our modern fancy toys are command line apps access through terminals. Your web server, your compliers, and your operating systems, are all administered through command lines.

For decades enterprise companies, including Microsoft, have tried to make the command line and ASCII terminals obsolete. They created GUI control panels and web-based admin dashboards. But you know what? They are all failures of various magnitudes–slow, incomplete, and harder to use than typing commands into an interactive ASCII terminal. Especially during a crisis, when the servers are down, and software is crashing, and the OS is hung.

OK, back to work on my C code. I bet I could run over one million instances of this ASCII terminal app on my off-the-shelf Mac Mini!