[comp.unix.questions] Arrow Keys and Esc

korson@hubcap.clemson.edu (Timothy Korson) (02/15/90)

Reading ESC Char and the Arrow Keys from Keyboard:

Problem: 
I want to be able to read the ESC char (^[) and also the escape 
sequence for the arrow keys (eg. ^[[D for Left) from the keyboard.

Is there any elegant solution to this problem?

I tried the following method and would not call it an elegant solution
because it won't work in all cases.  Here is my solution :

I used System V curses library functions "nodelay" and "getch" that are 
explained below (excerpts from man pages) :

nodelay (win, bf)   This option  causes  wgetch()  to  be  a
                    non-blocking   call.   If  no  input  is
                    ready, wgetch() will return ERR. If dis-
                    abled, wgetch() will hang until a key is
                    pressed.


getch()                  A character is read  from  the  terminal
                         associated  with the window.  In NODELAY
                         mode, if there is no input waiting,  the
                         value  ERR  is returned.  In DELAY mode,
                         the program will hang until  the  system
                         passes  text  through  to  the  program.
                         Depending on the  setting  of  cbreak(),
                         this will be after one character (CBREAK
                         mode), or after the first newline  (NOC-
                         BREAK  mode).   In  HALF-DELAY mode, the
                         program will hang until a  character  is
                         typed  or the specified timeout has been
                         reached.  Unless noecho() has been  set,
                         the  character  will also be echoed into
                         the  designated  window.
                         If keypad (win, TRUE) has  been  called,
                         and a function key is pressed, the token
                         for that function key will  be  returned
                         instead  of  the  raw  characters.  (See
                         keypad() under Input  Options  Setting.)
                         Possible  function  keys  are defined in
                         <curses.h> with integers beginning  with
                         0401, whose names begin with KEY_.  If a
                         character is received that could be  the
                         beginning  of  a  function  key (such as
                         escape), curses will set  a  timer.   If
                         the  remainder  of  the  sequence is not
                         received within the designated time, the
                         character will be passed through, other-
                         wise the  function  key  value  will  be
                         returned.  For this reason, on many ter-
                         minals, there will be a  delay  after  a
                         user  presses  the escape key before the
                         escape is returned to the program.  (Use
                         by  a programmer of the escape key for a
                         single character routine is discouraged.
                         Also see notimeout() below.)

The following program illustrates my approach.  It is necessary to compile 
this program with System V C-compiler since some of the above functions are
defined only in System V library.  On my Sun system I used the 
following command to make a.out:

/usr/5bin/cc filename.c -lcurses -ltermlib

/*----------  The program begins here  ----------*/
#include <curses.h>
#define  ESC		'\033'

main ()
{
	int  in, in1;

	/* initialise curses setup */
	initscr();
	cbreak ();
	noecho ();
	move (3,3);

	in = getch ();
	if (in == ESC)  {
		nodelay (stdscr, 1);		/* NODELAY mode ON  */
		in1 = getch ();				/* returns ERR or garbage */
		nodelay (stdscr, 0);		/* NODELAY mode OFF  */
		if (in1 == ERR)
			printw ("ESC \n");
		else  {
			in1 = getch ();			/* returns 1st char after ESC */
			if (in1 = '[')  {
				in1 = getch ();		/* returns 2nd char after ESC */
				if (in1 == 'D')
					printw ("LEFT ARROW %d \n",in1);
			} else
				printf("NONE");
		}
	}
	refresh();
	sleep(1);
	endwin();
}
/*----------  The program ends here  ----------*/

The above program reads the ESC and Left Arrow keys correctly when I work on
the console.  But it won't work correctly when I remote login and type
the ESC / Arrow keys (because of transmission delay???).

Another weird thing : The getch() issued to read a char, if any, after the
ESC char should return the input char ('[' for Left arrow) if one is present.
Instead it returns garbage and the second getch() after the ESC char returns
the actual char that is present after the ESC ('[').