How to write keypressed()?

Jim Hayes @dance jjh at telesoft.UUCP
Fri Sep 30 03:37:49 AEST 1988


  I'm working on a user interface that needs to differentiate between the
keyboard arrow keys, which send <esc>[<some character>, and the escape key.
Fine, says I, I'll just write a little routine to use when I see <esc> to look
for a character in the stdin stream. Well, not so fine. The routine I wrote
never detected the '[' after the <esc>, so I interpreted all the arrow keys as
escape. Ok, maybe a timing problem; I'll try sleeping a bit before I look for
a character. This works better, but, if I type arrow keys fast enough,
eventually I get the same result -- even though I've typed a bunch of arrows my
function tells me there's nothing in the stdin stream after the <esc>. I've
included the current incarnation of my function below; can anyone shed some
light on what my problem is?
  Some environmental information: I'm running under Sun3-3.5 Unix, using
curses, and I've got the terminal in cbreak mode when I'm calling this routine.
I originally tried using select(2) to look for the character; switching to
fcntl(2) and read(2) calls improved things significantly. I've tried playing
with the amount of time the routine sleeps -- I tried a single long sleep, a
single short sleep, incrementally longer sleeps, and, below, a series of short
sleeps. The last two seem to work best.

/*===========================================================================*/
short keypressed() {
/* Returns 1 if a character is available for reading from stdin; 0 otherwise */

  char a_char;
  int  old_flags;
  int  result;
  int  retry;

  if ( isatty( fileno(stdin) ) == 1 ) {
    old_flags = fcntl(fileno(stdin), F_GETFL, 0);
    if (old_flags < 0) {
      return (0);
    }
    if ( fcntl(fileno(stdin), F_SETFL, old_flags | FNDELAY) < 0 ) {
      return (0);
    }
    for (retry = 1; retry <= 10; ++retry) {
      usleep(2000);
      result = read(fileno(stdin), &a_char, 1);
      if (result >= 0) {
        ungetc(a_char, stdin);
        (void) fcntl(fileno(stdin), F_SETFL, old_flags);
        return (1);
      }
    }
    (void) fcntl(fileno(stdin), F_SETFL, old_flags);
    return (0);
  }
  else {
    return (0);
  }
}

------------------------------------------------------------------------------
"There's no problem so awful that you can't    |   Jim Hayes
 add some guilt to it and make it even worse!" |   ...!ucsd!telesoft!jjh



More information about the Comp.unix.wizards mailing list