4

I am trying to use ESC to escape from a program using getch(). I created a small program to demonstrate my problem.

#include <ncurses.h>

int main(void) {

    int key = 0;

    initscr();
    noecho();
    keypad(stdscr, TRUE);

    do {

        key = getch();
        clear();
        mvprintw(0, 0, "Key = %d\n", key);
        refresh();

    } while (key != 27); 

    clear();
    refresh();
    endwin();
    return 0;

}

I am trying to allow a user to use either the arrow keys or keypad (whichever is more convenient)

the issue lies within the keypad (whether numlock is on or not). When I compile and run the program and try and use the numpad keys in this simple test it exits as soon as I touch a numpad key. If I remove the while (key != 27) (esc being 27) condition it reads the keys and displays their numbers. Why does it exit the loop when the numpad keys register as

ENTER   343
UP      120
DOWN    114
LEFT    116
RIGHT   118

Any help is much appreciated!

Ambiguities
  • 415
  • 6
  • 18
  • Your program will effectively only show the last byte of a multi-byte escape sequence, as would be sent if you hadn't set keypad to true. Since such sequences start with an escape, they will cause your program to exit. I'm puzzled by the values 114, 116, 118, and 120; which keypad numbers do they correspond to? – rici Jun 07 '13 at 03:23
  • Try adding `setenv("ESCDELAY","1000");` before calling initscr(). Try larger values instead of 1000 if that doesn't work. – Craig Jun 07 '13 at 15:00
  • What is your TERM environment variable set to, and what terminal are you running your test in? – Craig Jun 07 '13 at 20:58

2 Answers2

5

I found a fix in the source for Dungeon Crawl Stone Soup. It basically sets the keycodes for those.

{DCSS-dir}/source/libunix.cc (333)

define_key("\033Op", 1000);
define_key("\033Oq", 1001);
define_key("\033Or", 1002);
define_key("\033Os", 1003);
define_key("\033Ot", 1004);
define_key("\033Ou", 1005);
define_key("\033Ov", 1006);
define_key("\033Ow", 1007);
define_key("\033Ox", 1008);
define_key("\033Oy", 1009);

// non-arrow keypad keys (for macros)
define_key("\033OM", 1010); // Enter
define_key("\033OP", 1011); // NumLock
define_key("\033OQ", 1012); // /
define_key("\033OR", 1013); // *
define_key("\033OS", 1014); // -
define_key("\033Oj", 1015); // *
define_key("\033Ok", 1016); // +
define_key("\033Ol", 1017); // +
define_key("\033Om", 1018); // .
define_key("\033On", 1019); // .
define_key("\033Oo", 1020); // -

// variants.  Ugly curses won't allow us to return the same code...
define_key("\033[1~", 1031); // Home
define_key("\033[4~", 1034); // End
define_key("\033[E",  1040); // center arrow
voidraen
  • 748
  • 10
  • 18
  • 1
    PSA: Hilariously, I'm a member of the dcss devteam who ran across this answer while trying to figure out where these mappings come from, many years later. Using this blindly is not recommended, at least some of these are wrong. (In particular, what I do know is that `\033OP` through `\033OS` are more typically used for F1-F4 on most terms, and I'm not at all sure under what conditions these are used for numpad keys instead.) – kgr Dec 27 '20 at 20:15
2

The XTERM terminal emulator sends an escape for certain numpad keys if Num Lock is off.

You can turn on Num Lock, use something other than the numpad, use something other than ESC to break your loop, or try to find a terminal emulator that doesn't do this. There is no way for your program to distinguish between ESC and certain numpad characters when Num Lock is off within the confines of your terminal emulator.

Alex V
  • 3,416
  • 2
  • 33
  • 52
  • Yes, this my conclusion as well from my experimentation and reading. @James C, I think the easiest solution here is to *not* use ESC as the end condition for your loop. Use for something else. Note that on my system it was only the Home/7 and End/1 keys (with numlock off) that produced keycode 27. I also concur with rici on the direction keys. My values were in the 258-261 range. Ncurses has constants to use in the pgm for these anyway e.g. KEY_HOME, KEY_END, KEY_RIGHT and so forth. – Duck Jun 07 '13 at 03:37
  • ncurses should handle this. After ncurses receives an ESC character it waits the number of milliseconds in the ESCDELAY environment variable (default 1000) and only if no multi-character sequence arrives does it send the Esc character. For this reason you may notice a delay after pressing Esc before your ncurses program responds. Your program works perfectly on my system inside an xterm. – Craig Jun 07 '13 at 14:54
  • @Craig Are you absolutely positive you do not have Num Lock on? What character codes are being printed when you press numpad characters? – Alex V Jun 07 '13 at 17:36
  • @MaxwellHansen the number pad "8" gives me 56 with numlock off and 259 with numlock on (259 is KEY_UP as defined in ncurses.h) up arrow not on the number pad also returns 259 – Craig Jun 07 '13 at 18:22
  • @Craig, The 8 key on the numpad works fine on my system as well. It's only the 1, 3, 5, 7, and 9 that send escape for me. This is why I was vague in my response regarding which numpad keys send ESC. It appears to vary between users, however I'm not sure what the source of the inconsistency is. – Alex V Jun 07 '13 at 21:34