I recently had the pleasure of trying to figure out a friend’s terminal woes.  His function keys weren’t behaving properly.  It turns out that his terminal was sending escape codes that differed from the terminfo definition his terminal was using.  I set out to find what the correct solution was.  These are my results.  (Note that I use Debian GNU/Linux.  Some of this may be Debian-specific.)

Most terminal emulators these days emulate some superset of a DEC VT100.  (Not all of them emulate a VT100 exactly, though.  cf.  vttest.)  The VT100 didn’t have function keys in the sense that it didn’t have keys labeled F1, F2, F3, etc.  It did, however, have four keys over the numeric keypad labeled PF1 through PF4.  These keys are generally regarded as analogous to F1 through F4 on a modern keyboard.  They generated escape codes ^[OP through ^[OS.  The appropriate $TERM type for a VT100 is vt100.

One of the best well known terminal emulators around, xterm, actually emulates (or strives to emulate) a DEC VT220.  I’ll get to xterm in a bit, but the VT220 was a more advanced terminal than the VT100.  Among other things, it had twenty function keys, labeled F1 through F20.  The first five were strictly for local terminal functions; the host never saw any escape codes from them.  The remainder (F6 through F20) sent escape codes ^[[17~ to ^[[21~, ^[[23~ to ^[[26~, ^[[28~, ^[[29~, and ^[[31~ to ^[[34~.  The appropriate $TERM type for a VT220 is vt220.  (Note that, on my system, the vt220 $TERM type actually defines VT100 escape codes for F1 through F4.  There’s no definition for F5.)

This brings me to xterm.  xterm has a long history, and the function key definitions have changed over time.  The original xterm from the X Consortium (even before they became the Open Group) used escape codes based on the VT220, but extended to cover the range from F1 to F48.  F1 through F12 generated, respectively, codes ^[[11~ to ^[[15~, ^[[17~ to ^[[21~, ^[[23~, and ^[[24~.  Shift-F1 through Shift-F12 were used for F13 through F24, and generated codes from ^[[11;2~ to ^[[24;2~.  Similarly Ctrl-F1 through Ctrl-F12 were used for F25 through F36 and generated codes ^[[11;5~ to ^[[24;5~, and Ctrl-Shift-F1 through Ctrl-Shift-F12 were used for F37 through F48 and generated codes ^[[11;6~ to ^[[24;6~.  None of the base xterm $TERM types on my system correspond to this series of escape codes, though you can still get xterm to exhibit the old behavior by setting the OldXtermFKeys resource to ‘true’.

The current XFree86 xterm mixes VT100 and VT220.  Since the original VT220 didn’t have F1 through F5, the XFree86 xterm uses the escape sequences from the VT100’s PF1 through PF4 for F1 through F4 while retaining the VT220-based escape sequences from the X Consortium xterm for F5 through F12.  So the differences from the earlier xterms are: F1 through F4 generate escape codes ^[OP through ^[OS, F13 to F16 generate ^[O2P to ^[O2S, F25 to F28 generate ^[O5P to ^[O5S, and F37 to F40 generate ^[O6P to ^[O6S.  On my system, the $TERM types that have the appropriate function key definitions are xterm, xterm-debian, xterm-mono, and xterm-xfree86.

The GNOME project’s terminal emulator is gnome-terminal.  It generates the exact same escape codes as the XFree86 xterm and will work with the same $TERM settings.  Note, however, that some function keys are bound to gnome-terminal actions and will not be passed through to applications running in the terminal.  (For example, F1 calls up the GNOME help browser to view the gnome-terminal documentation.)

multi-gnome-terminal is based on gnome-terminal, but it implements multiple tabbed terminal sessions in a single window.  It also does the function keys a little differently, though it’s a bit more like the original VT220.  F1 through F12 behave exactly the same as the XFree86 xterm.  Shift-F1 through Shift-F10 function as F11 through F20 and generate escape codes from ^[[23~ to ^[[34~, just like the VT220.  Note that this means there are two ways to get F11 and F12. (Actually, there are three, since Shift-F11 and Shift-F12 are also equivalent to F11 and F12.)  On my system, the $TERM types with the appropriate function key definitions are xterm-color, xterm-r6, and xterm-vt220.  xterm can be made to behave like this by setting the SunKeyboard resource to ‘true’.  Note that, like gnome-terminal, multi-gnome-terminal binds some function keys for its own use and may not pass then through to the programs in the terminal.

rxvt is a very popular xterm replacement.  It uses the same escape sequences at the X11R6 xterm for F1 through F12.  Shift-F1 through Shift-F12 work similarly to multi-gnome-terminal; they add ten to the number on the key (so there are again two ways to get F11 and F12).  rxvt generates the same escape sequences as multi-gnome-terminal for F11 through F20, and uses ^[[23$ and ^[[24$ for F21 and F22, respectively.  The sequence continues with Ctrl-F1 through Ctrl-F12 generating ^[[11^ through ^[[24^ for F23 through F34 (no overlap with previous sequences), Ctrl-Shift-F1 through Ctrl-Shift-F10 generating ^[[23^ through ^[[34^ for F33 through F42 (two-key overlap), and Ctrl-Shift-F11 and Ctrl-Shift-F12 generating ^[[23@ and ^[[24@ for F43 and F44.  The base $TERM type for rxvt is rxvt, though it ships with several types for different circumstances, including rxvt-basic and rxvt-m.  It also comes with rxvt-unicode, but on my system that definition only lists function keys up to F20.

GNU screen is also a terminal emulator, though it expects to run within another terminal environment (as opposed to displaying text in a graphical environment like xterm or displaying text on physical hardware like an actual terminal).  As such, it translates many escape sequences from its containing terminal environment to the VT100-like environment it provides.  It will recognize and translate the sequences for F1 through F12.  For those, it will generate the same escape codes as the XFree86 xterm.  It does not recognize F13 and above; those escape codes will pass through unchanged to the programs running within screen.  (Note that the screen ‘bindkey’ command has a -k option that uses termcap capabilities to represent keys.  It understands k1 through FA, which correspond to F1 through F20.)  The $TERM type for screen is screen.

key VT100 VT220 X11R6 xterm XFree86 xterm rxvt MGT screen
F1 ^[OP ^[[11~ ^[OP ^[[11~ ^[OP ^[OP
F2 ^[OQ ^[[12~ ^[OQ ^[[12~ ^[OQ ^[OQ
F3 ^[OR ^[[13~ ^[OR ^[[13~ ^[OR ^[OR
F4 ^[OS ^[[14~ ^[OS ^[[14~ ^[OS ^[OS
F5 ^[[15~ ^[[15~ ^[[15~ ^[[15~ ^[[15~
F6 ^[[17~ ^[[17~ ^[[17~ ^[[17~ ^[[17~ ^[[17~
F7 ^[[18~ ^[[18~ ^[[18~ ^[[18~ ^[[18~ ^[[18~
F8 ^[[19~ ^[[19~ ^[[19~ ^[[19~ ^[[19~ ^[[19~
F9 ^[[20~ ^[[20~ ^[[20~ ^[[20~ ^[[20~ ^[[20~
F10 ^[[21~ ^[[21~ ^[[21~ ^[[21~ ^[[21~ ^[[21~
F11 ^[[23~ ^[[23~ ^[[23~ ^[[23~ ^[[23~ ^[[23~
F12 ^[[24~ ^[[24~ ^[[24~ ^[[24~ ^[[24~ ^[[24~
F13 ^[[25~ ^[[11;2~ ^[O2P ^[[25~ ^[[25~
F14 ^[[26~ ^[[12;2~ ^[O2Q ^[[26~ ^[[26~
F15 ^[[28~ ^[[13;2~ ^[O2R ^[[28~ ^[[28~
F16 ^[[29~ ^[[14;2~ ^[O2S ^[[29~ ^[[29~
F17 ^[[31~ ^[[15;2~ ^[[15;2~ ^[[31~ ^[[31~
F18 ^[[32~ ^[[17;2~ ^[[17;2~ ^[[32~ ^[[32~
F19 ^[[33~ ^[[18;2~ ^[[18;2~ ^[[33~ ^[[33~
F20 ^[[34~ ^[[19;2~ ^[[19;2~ ^[[34~ ^[[34~
F21 ^[[20;2~ ^[[20;2~ ^[[23$
F22 ^[[21;2~ ^[[21;2~ ^[[24$
F23 ^[[23;2~ ^[[23;2~ ^[[11^
F24 ^[[24;2~ ^[[24;2~ ^[[12^
F25 ^[[11;5~ ^[O5P ^[[13^
F26 ^[[12;5~ ^[O5Q ^[[14^
F27 ^[[13;5~ ^[O5R ^[[15^
F28 ^[[14;5~ ^[O5S ^[[17^
F29 ^[[15;5~ ^[[15;5~ ^[[18^
F30 ^[[17;5~ ^[[17;5~ ^[[19^
F31 ^[[18;5~ ^[[18;5~ ^[[20^
F32 ^[[19;5~ ^[[19;5~ ^[[21^
F33 ^[[20;5~ ^[[20;5~ ^[[23^
F34 ^[[21;5~ ^[[21;5~ ^[[24^
F35 ^[[23;5~ ^[[23;5~ ^[[25^
F36 ^[[24;5~ ^[[24;5~ ^[[26^
F37 ^[[11;6~ ^[O6P ^[[28^
F38 ^[[12;6~ ^[O6Q ^[[29^
F39 ^[[13;6~ ^[O6R ^[[31^
F40 ^[[14;6~ ^[O6S ^[[32^
F41 ^[[15;6~ ^[[15;6~ ^[[33^
F42 ^[[17;6~ ^[[17;6~ ^[[34^
F43 ^[[18;6~ ^[[18;6~ ^[[23@
F44 ^[[19;6~ ^[[19;6~ ^[[24@
F45 ^[[20;6~ ^[[20;6~
F46 ^[[21;6~ ^[[21;6~
F47 ^[[23;6~ ^[[23;6~
F48 ^[[24;6~ ^[[24;6~