Curses Key Definition Doesn't Work

I was learning curses (using Pluto Project PDCurses) when I found out the keypad key definitions doesn't really work.

For example, this program shows nothing after I press the up arrow key on my keyboard.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <curses.h>

int main()
{
    int ch;

    initscr();
    keypad(stdscr, TRUE);

    ch = getch();
    if(ch == KEY_UP)
        printw("IT WORKS!");

    getch();
    endwin();

    return 0;
}


After a bit of debugging I learned that up arrow key is interpreted as the number 60419. I tried changing KEY_UP to that number and the program works.

The problem only happens when I test the value of ch with non ASCII characters. I did everything on CodeBlocks in a Windows machine.

I have two questions about this:

1. What is this number? I know it's not ASCII or Alt Codes. I tried Google but I got a bank somewhere in England.
2. If this is system related, should I mess around with curses.h file to associate every key with this number? I think this is a really really bad idea.

For reference, I tried to check what number is associated with each arrow key and this is the result

http://puu.sh/jnzF0.JPG (top to bottom: a, s, d, f, g, h, j, k, l, ;, up arrow, right arrow, down arrow, left arrow, up arrow, right arrow, down arrow, left arrow)

Curses are weird.
Are you sure you are using the correct curses.h header file?
(Check again!)

The number means nothing -- it's a magic number.
It makes perfect sense, though. Print it (and other 'extended key' values) in hexadecimal to see what's going on.

curses.h
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
/*----------------------------------------------------------------------
 *
 *  Function and Keypad Key Definitions.
 *  Many are just for compatibility.
 *
 */

#ifdef PDC_WIDE
   #define KEY_OFFSET 0xec00
#else
   #define KEY_OFFSET 0x100
#endif

#define KEY_CODE_YES     (KEY_OFFSET + 0x00) /* If get_wch() gives a key code */

#define KEY_BREAK        (KEY_OFFSET + 0x01) /* Not on PC KBD */
#define KEY_DOWN         (KEY_OFFSET + 0x02) /* Down arrow key */
#define KEY_UP           (KEY_OFFSET + 0x03) /* Up arrow key */
#define KEY_LEFT         (KEY_OFFSET + 0x04) /* Left arrow key */
#define KEY_RIGHT        (KEY_OFFSET + 0x05) /* Right arrow key */
#define KEY_HOME         (KEY_OFFSET + 0x06) /* home key */
#define KEY_BACKSPACE    (KEY_OFFSET + 0x07) /* not on pc */
#define KEY_F0           (KEY_OFFSET + 0x08) /* function keys; 64 reserved */ 

Curses is weird because it works with so many different terminals, all of varying functionality. The IBM PC was unique, in part, because it set a clear standard for how devices attached to the system, like the keyboard, were to behave. Responding to keyboard interrupts is just a matter of table-lookup of make/break codes.

Many other systems, even today, are nowhere near as easy to handle. On an old SunSPARC station I used to use at school, pressing an arrow key required the system to handle a seven or eight character escape sequence.

Likewise, handling the Esc character is a hassle, because of a commonly-perpetuated bad design decision to use \033 as the first in a sequence of formatted control codes -- hence the ESCDELAY -- how long does Curses want to wait to see if Esc is just a single Esc key press or a control sequence? On a dial-up tty, it might be a lot longer than you would think.

Anyway, fix your curses.h header.

Hope this helps.
That part in my curses.h is exactly the same as yours.

Weird update:
I found out the weird number appears when I declare ch as an integer. When I declared it as char, I got 2, 3, 4, 5 for down, up, left, and right.

However, this code still only works
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <curses.h>

int main()
{
    char ch;

    initscr();
    keypad(stdscr, TRUE);

    ch = getch();
    if(ch == KEY_UP)
        printw("IT WORKS!");

    getch();
    endwin();

    return 0;
}

when I replace KEY_UP with 3.



Another thing, this is the tutorial I tried to follow (first example)

http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/windows.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <ncurses.h>


WINDOW *create_newwin(int height, int width, int starty, int startx);
void destroy_win(WINDOW *local_win);

int main(int argc, char *argv[])
{	WINDOW *my_win;
	int startx, starty, width, height;
	int ch;

	initscr();			/* Start curses mode 		*/
	cbreak();			/* Line buffering disabled, Pass on
					 * everty thing to me 		*/
	keypad(stdscr, TRUE);		/* I need that nifty F1 	*/

	height = 3;
	width = 10;
	starty = (LINES - height) / 2;	/* Calculating for a center placement */
	startx = (COLS - width) / 2;	/* of the window		*/
	printw("Press F1 to exit");
	refresh();
	my_win = create_newwin(height, width, starty, startx);

	while((ch = getch()) != KEY_F(1))
	{	switch(ch)
		{	case KEY_LEFT:
				destroy_win(my_win);
				my_win = create_newwin(height, width, starty,--startx);
				break;
			case KEY_RIGHT:
				destroy_win(my_win);
				my_win = create_newwin(height, width, starty,++startx);
				break;
			case KEY_UP:
				destroy_win(my_win);
				my_win = create_newwin(height, width, --starty,startx);
				break;
			case KEY_DOWN:
				destroy_win(my_win);
				my_win = create_newwin(height, width, ++starty,startx);
				break;	
		}
	}
		
	endwin();			/* End curses mode		  */
	return 0;
}


I declared ch as a character and I got
 
warning: case label value exceeds maximum value for type [enabled by default]|


If the value of KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT are 2, 3, 4, 5, how come it exceeds the maximum value of char (128 if I'm not mistaken)?
'ch' should be an int.

(The returned key codes aren't just characters.)

BTW, the code works perfectly for me (except for having to change <ncurses.h> to <curses.h>).

I'm still not sure what's causing you problems.
Topic archived. No new replies allowed.