How can I know that the user hit the ESC key in a

2019-07-13 10:51发布

问题:

I have a problem in detecting whether I just got a plain ESC key (just code 27) or whether it was another special key such as an Arrow Up which sends me three bytes: ESC [ A (27 91 65).

Now, I understand escape sequences, what I don't understand is how can I possibly know that the user actually typed ESC instead of a special key since both start with 27 and ESC is only 27?

Note that I use the wgetch() function from ncurses as in:

// initialization not shown initscr() should be enough for this test
while(!f_should_exit)
{
    int c(wgetch(f_win_input));

    // show codes of what the user types
    //
    printf("got [%d] ", c);
    // prints 27 when I hit ESC
    // prints 27 91 65 when I hit Arrow Up
}

I use the ESC and arrow keys all the time in vim so I would imagine that there is an easy way to specifically detect which key was pressed?!

回答1:

This is a standard feature of X/Open Curses. The manual page for wgetch discusses it in keypad mode:

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.

By default, keypad is not set to true for a given window, i.e., the library does not do this (your program must, if you want function-keys):

keypad(win, TRUE);

The timeouts are described in ncurses' input-options manual page. To distinguish an escape character from a function (or cursor, or keypad key), you could use notimeout, as mentioned in the discussion of nodelay:

While interpreting an input escape sequence, wgetch(3x) sets a timer while waiting for the next character. If notimeout(win, TRUE) is called, then wgetch does not set a timer. The purpose of the timeout is to differentiate between sequences received from a function key and those typed by a user.