Detecting shift + keyup/down in the terminal

From the context of the question, shift+up and shift+down refer to shift-cursor-up and shift-cursor-down (rather than, for instance, shift-page-up and shift-page-down), because the question asked about selecting multiple lines.

This is actually more than one question:

  • first, how to make ncurses recognize shift+up, etc., and
  • whether the ncurses menu library does this, and
  • how to get a menu doing that, if not.

First, ncurses provides predefined (per X/Open Curses) definitions for a portable (more/less) set of special keys. Referring to terminfo(5), you might notice:

   key_sf                    kind   kF   scroll-forward key
   key_sleft                 kLFT   #4   shifted left-arrow
                                         key
   key_sr                    kri    kR   scroll-backward key
   key_sright                kRIT   %i   shifted right-arrow
                                         key

but there is nothing labeled "shifted up-arrow key". Only with some hindsight can one related kind and kri to kLFT and kRIT. Before adding support for modified special-keys to xterm in 1999, there was little prior art:

Patch #94 - 1999/3/27 - XFree86 3.9Pf
add parameters to function keys to indicate if shift, control or alt are set. The codes are based on a description of a DEC VT510 with a PC keyboard, from Jeffrey Altman .

Later, that scheme was amended to reduce application confusion. Other developers who copied the feature from xterm did not follow suit by amending their programs:

Patch #167 - 2002/8/24 - XFree86 4.2.0
add modifyCursorKeys resource to control how the shift- and similar modifiers are used to make a cursor escape sequence. The default makes a modified escape sequence always start with CSI and puts the modifier as the second parameter, to avoid confusing applications that would interpret the first parameter as a repeat count. The original behavior can be obtained by setting the resource to 0 (newsgroup discussion with Stephen J Turnbull, Jeffrey Altman).

Meanwhile, in ncurses, it seemed useful to incorporate these into terminal descriptions (because ncurses uses the terminal database than, say, tables such as those that tmux uses). These rely upon a feature for user-defined capabilities introduced by ncurses 5.0. In the terminal database, the feature is mentioned for xterm in 2004:

# 2004-07-17
#       * add xterm-pc-fkeys -TD

which (besides consolidating earlier work as early as 2001) attempted to deal with the variations of modifier encodings that might be used with different combinations of xterm resources — as well as the look-alikes which differed in varying degrees from the xterm encoding scheme.

The convention used for the user-defined capabilities started with adding kDN and kUP to the list (your shift+down and shift+up), and a number corresponding to the xterm modifier codes. Much later, it became apparent that kind and kri could have the same meaning. But as a result, you might find terminal descriptions with kDN and kUP (which only ncurses reads — other applications and libraries which read the terminal database directly having neglected this for some 16 years).

The extended capabilities are summarized in the terminal database.

Now (beginning the second part), ncurses does provide a menu library. This is (with a few extensions such as supporting multibyte characters) a reimplementation of the SVr4 menu library. Refer to the manual page for menu_driver(3x) for that, as well as the programs in ncurses-examples which demonstrate the library. The short answer is that the menu library does not predefine the behavior you are asking about, but that an application can use the library to do what is asked. Start by looking to see how to use this detail:

REQ_TOGGLE_ITEM
Select/deselect an item.

The larger issue is that raised by using user-defined capabilities in this application. Most of the applications using the form- and menu-libraries rely on making case-statements with the predefined symbols for special keys. For shift+up and shift+down you would not have that (unless the coincidence of kind and kri was noted and applied). For user-defined capabilities, there are no predefined key-codes (such as KEY_DOWN in curses.h). You have instead runtime-defined values determined by the key_defined function. So instead of a simple case-statement (there is no KEY_SDOWN in curses.h), some indirection is needed.


Terminals transmit characters, not keys. Most characters are printable, which doesn't leave much room to encode function keys and keychords. Function keys are encoded as escape sequences, i.e. sequences of bytes starting with the escape character (byte value 27, which can be written out as \e in many programming languages). For more details, see How do keyboard input and text output work?

There's no universal standard on what escape sequence each key or keychord sends. The curses library provides an abstraction layer that decodes function keys. It uses the termcap (old-style) or terminfo (modern) library under the hood; you can use termcap/terminfo directly if you don't want to link with curses.

Alternatively, you can hard-code the usual control sequences for Up and Down. While there is no standard, almost every terminal sends either \eOA or \e[A for Up and either \eOB or \e[B for Down, and I've never seen a terminal that sent these sequences for a different key.

The Shift keychords are another matter: the escape sequences they send are more diverse, and many terminals don't distinguish e.g. Up from Shift+Up. You can't rely on these being distinct unless you only support a restricted set of configurations. There are emerging standards but they're still not supported by many popular terminal emulators.

Terminals don't send key up events. (Your use case doesn't require them, though, according to your description.)

Unless you can afford to require a specific terminal emulator (e.g. recent-ish xterm), don't rely on the user being able to type Shift+Up. Support an alternate method, such as a “start multiple selection” key followed by plain Up/Down.