Search code examples
creadlinencurseskeypadlibreadline

Readline & NCurses, handle special keys and keys combinations


I'm replicating an Irssi interface for a student project. I would like to use NCurses for the text interface, and readline to provide better text-editing capabilities while writing messages.

This question, answer and project provided me with a great starting point.

My problem is that I would like to have an input/event loop like this:

int ch;
while (exit_condition) {
    ch = wgetch(window);
    switch (ch) {
    case ERR: continue;
    case KEY_F(1): /* do something */ break;
    case KEY_UP: /* do something else */ break;
    default: forward_to_readline(ch); break;
    }
}

But in order to match KEY_F(n) or KEY_UP I need to enable keypad(window, TRUE), which will modify the input and make it unusable for readline.

From the manual:

If keypad is TRUE, and a function key is pressed, the token for that function key is returned instead of the raw characters.

When a character that could be the beginning of a function key is received (which, on modern terminals, means an escape character), curses sets a timer. If the remainder of the sequence does not come in within the designated time, the character is passed through; otherwise, the function key value is returned. For this reason, many terminals experience a delay between the time a user presses the escape key and the escape is returned to the program.

Here are my thoughts:

  • Is there a function to reverse the effect of keypad ?
  • Should I implement myself the behaviour of keypad ? I suppose I must also do this if I want to catch events like Shift + Up. I'd be glad to have examples of this.
  • Can readline give me the combination of keys if I can't obtain it form NCurses ? maybe with key binding callbacs (relevant ?) ?

Thank you for your time !


Solution

  • That's multiple questions. Briefly:

    • the reverse of the keypad function is by calling that for a given window with the parameter set to FALSE.
    • some applications implement their own version of keypad/wgetch, but (given that you can control the timeout with ncurses' ESCDELAY), there's not a lot of gain there unless you wanted to be portable, say, to Solaris curses.
    • you wouldn't get any improvement with shift + up, for instance (that's a terminal-dependent escape sequence)
    • readline doesn't look at the capabilities in the terminal database which list shift + up (it's not in the subset of termcap which it knows about). What it could do for you is associate a string with a readline function.