Character combinations appearing on the terminal when certain key-combinations are pressed
The input on a terminal is a sequence of characters (or more precisely a sequence of bytes). Non-printable input, such as function and arrow keys, has to be encoded as one or more characters. A few keys are encoded as control characters, for example ^I
(HT, Ctrl+I) for the Tab key. But there aren't nearly enough control characters to encode all key combinations. So function keys and cursor keys are encoded as sequences of multiple characters. In practice, all terminals use escape sequences that start with the character ESC (Escape, ^[
) followed by some printable characters. The details of the encoding can vary between terminals and can depend on the terminal configuration.
Escape sequences have a variable length, so the only way to know when one ends is to know how it's constructed. If the application running in the terminal (for example the shell) recognizes the escape sequence as a key chord, it invokes whatever functionality is bound to that key chord. If the application doesn't recognize the escape sequence, there's a point where it gives up and treats subsequent characters as ordinary characters.
The de facto standard encoding for cursor keys is that Up sends ^[[A
(where ^[
means an escape character, not the two-character sequence circumflex-bracket), Down sends ^[[B
, Right sends ^[[C
and Left sends ^[[D
. Modifiers are indicated with a semicolon and a number, and for cursor keys an extra 1
before the semicolon. The number 6
indicates the modifiers Ctrl+Shift. See this answer for more details.
When you press Ctrl+Shift+Left, the terminal sends ^[[1;6D
(recall that ^[
is an escape character here). The shell reads ^[[1
and, at that point, notices that none of its key bindings start with these three characters. So it gives up (and it might beep if it's configured to beep when it receives invalid input). It keeps reading and sees ;6D
which are ordinary printing characters.
To see what escape sequence your terminal sends for a given key or key chord, press Ctrl+V then the key chord. Ctrl+V (^V
) is a key binding in shells and other terminal applications that means “treat the next character literally”, and that causes the leading escape character in the escape sequence to be inserted literally, followed by the other characters in the escape sequence (which are ordinary printing characters). If you want to bind that key chord in your shell or other terminal application, you need to bind this escape sequence.
As I noted above, there are differences between terminals. There's a de facto standard for simple cases, but less so when modifiers are involved. Furthermore many terminals simply ignore certain modifiers on certain keys. For example, on Big Sur terminal, Ctrl+Shift+cursor key is indistinguishable from cursor key by default; this can be configured in the preferences (“Profiles” > “Keyboard”)). Iterm2 comes with more escape sequences out of the box including Ctrl+Shift+cursor key.
Further reading:
- Difference between a terminal and a shell
- How do keyboard input and text output work? (the GUI part discusses the traditional Unix GUI using the X window system, not the macOS GUI)
- A more detailed presentation of escape sequences (with Unix modifier names; Alt/Meta is the Option key on a Mac)
- An example of binding Ctrl+arrow in a terminal application
- Information about Emacs (which can be informative even if you don't use Emacs)