LeoNerd.org.uk logo LeoNerd.org.uk LeoNerd.org.uk logo

Fix Keyboard Input on Terminals - Please

Keyboard input on Terminals has many deficiencies to it. I want them all fixed. I have a plan on how to do it but it Needs Your Help

I want terminal keypresses to Just Work. What do I mean Just Work? I mean programs in a simple orthogonal way, can determine the key that was pressed, and this model should easily map to the user's expectation.

Why doesn't it currently?

How can we fix this?

By having a sane and sensible model on BOTH ends of the terminal interaction, and a well-defined way of communicating. How exactly we go about this really depends who you are:

Authors of Programs that Read Terminal Keypresses

The simplest way to go about this is to use my terminal key input library, libtermkey. Failing this, if you're using some existing system of keyboard input, such as GNU Readline, I suggest you apply pressure to the maintainers of that system until they adopt this method of reading extended keypresses.

Authors of Terminal Emulators

Making a terminal send the correct key encodings should be a relatively easy task, given the encoding scheme already splits modifiers and keysyms in a way likely to be similar to the underlying input system at work, such as X11 or Win32.

TODO: More on this later. Notetoself: libvterm does it too; paste example?

End-users of Programs

Even if you're not the author of a program like this, you can still help fix the situation. Write to the maintainer of your program, report a bug. Explain that you wanted to use such a keybinding, or whatever the problem was. Explain that, because their program doesn't correctly handle these cases, it wasn't possible, but if they were to adopt this scheme, then it would be and your problem would be solved. With enough voices, even the most stubbon developer who believes it's 1970 and everyone lives behind a green-phosphor glass teletype on a 9,600 baud modem, can still change his ways.

Encoding Specification

The primary motivation of this scheme is to encode any possible keypress uniquely; that a keypress maps to one possible sequence of bytes, and a valid sequence of bytes encodes only one keypress. For backward compability, it is also required that any keypress that can be represented without this scheme is also represented by the same bytes within it; that is, this scheme is an extension of existing encodings, not a replacement of.

Unmodified Unicode
Just send UTF-8 bytes as normal. No UTF-8 sequence of a regular character starts with a C0 or C1 byte, so these will be unique
Modified Unicode
Certain key presses have special behaviours with modifiers. Alt tends to prefix Escape or set the top bit. Ctrl ends to mask with 0x1f. When the simplest form of these keys are pressed, they should be encoded as previously. Existing schemes lack a way to encode more general modifiers with Unicode codepoints at present, so we are at liberty to invent something new for these.
CSI [codepoint];[modifier] u
The u CSI command lies in the private-use area, so has no fixed meaning at present.
Special keys
Existing schemes usually use CSI ~ to encode special (i.e. non-Unicode) keypresses. XTerm and other terminals use the second CSI parameter to pass encoding the set of modifiers in effect.
CSI [number];[modifier] ~
The modifier is value 1 + a bitmask encoding the modifiers. 1 for Shift, 2 for Alt, 4 for Ctrl.
Really special keypresses
Some terminals encode certain keys outside of the CSI ~ encoding, instead picking a different CSI command. This too can accomodate the modifier in its second position.
CSI 1;[modifier] {ABCDFHPQRS}

TODO: The above can be made a lot more precise, into a big table explaining the bytes to send for classes of key + modifier combinations. Too much detail here? Perhaps..

Advantages: solves above problems. Can be fitted into existing programs with a minimum of fuss and without breaking back-compat.

Extension: Can take it one step further, and require CSI to be sent as 8bit code, never as 7bit Esc [. Is unambiguous wrt. well-formed UTF-8. Can then reserve Esc exclusively for the real Escape key. Hey presto - no need to rely on timing information.