This is the mail archive of the cygwin@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Porting getch() and kbdhit() ???


"Lincoln, W. Terry" <terryl@ultimatetechnology.com> writes:
> I have a M$-C book on my shelf and it says that the function kbhit() should
> return a 0 if no characters have been struck otherwise the character-code of
> the struck key (without removing the key from the KB queue).
> 
> getch() removes a single key from the KB queue (waiting for one if
> necessary) and returns it character-code without echoing it to the terminal
> screen.
> 
> getche() is the same but echoes the character it gets to the screen.

Unfortunately, I know nothing about DOS, and DJ already pointed the fact
that my kbhit is not what DOS has.

However, it should still be reasonably straight forward to implement using
select with 0 timeout (not NULL, but 0 for the values) to check if there's
input pending for standard input descriptor.

Here's an untested attempt that should work on all POSIX systems. Note
the global cbreak/raw mode wrapper, which is necessary for this type of
input handling to work.

This needs work, especially in the area of cleanups/tty reset if things
go bad, and catching signals and so on. Left as an exercise ;-)

I'm sure this code is full of holes, but I don't care enough about to 
actually spend time on it ...

Regards,
Mumit

--- cut from here to end
/* kbhit.c -- sample kbhit/getch implementation. */

#include <stdio.h>
#include <sys/time.h>
#include <termios.h>

#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif

/* Use of raw mode requires that you understand how to manage signals
   and all that.  */
#ifdef USE_RAW_MODE
# define RAW_MODE(x) tty_raw((x))
#else
# define RAW_MODE(x) tty_cbreak((x))
#endif

static struct termios save_termios;

static int
tty_cbreak (int fd)
{
  struct termios ios;

  if (tcgetattr (fd, &save_termios) < 0)
    return -1;

  ios = save_termios;
  ios.c_lflag &= ~(ICANON | ECHO);
  ios.c_cc[VMIN] = 1;
  ios.c_cc[VTIME] = 0;

  return tcsetattr (fd, TCSAFLUSH, &ios);
}

static int
tty_raw (int fd)
{
  struct termios ios;

  if (tcgetattr (fd, &save_termios) < 0)
    return -1;

  ios = save_termios;
  ios.c_lflag &= ~(ICANON | ECHO | IEXTEN | ISIG);
  ios.c_lflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
  ios.c_lflag &= ~(CSIZE | PARENB);
  ios.c_lflag |= CS8;
  ios.c_lflag &= ~(OPOST);

  ios.c_cc[VMIN] = 1;
  ios.c_cc[VTIME] = 0;

  return tcsetattr (fd, TCSAFLUSH, &ios);
}

static int
tty_reset (int fd)
{
  return tcsetattr (fd, TCSAFLUSH, &save_termios);
}

int
kbdhit (void)
{
  fd_set rfds;
  struct timeval tv;

  /* Watch stdin (fd 0) to see when it has input. */
  FD_ZERO (&rfds);
  FD_SET (STDIN_FILENO, &rfds);

  /* Return immediately. */
  tv.tv_sec = 0;
  tv.tv_usec = 0;

  /* Must be in raw or cbreak mode for this to work correctly. */
  return select (STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) &&
    FD_ISSET (STDIN_FILENO, &rfds);
}

int
getch (void)
{
  int c;

  /* Must be in raw or cbreak mode for this to work correctly. */
  if (read (STDIN_FILENO, &c, 1) != 1)
    c = EOF;

  return c & 0xff;
}

int
main ()
{
  int i;
  char c;

  puts ("Press Q to quit ... ");
  fflush (stdout);

  RAW_MODE (STDIN_FILENO);
  while (1)
    {
      fputs ("going to sleep for 2 seconds ... ", stdout);
      fflush (stdout);
      sleep (2);
      fputs ("awake. Checking for key\n", stdout);
      fflush (stdout);
      if (kbdhit ())
	{
	  int c;
	  fputs ("yes ... ", stdout);
	  fflush (stdout);
	  c = getch ();
	  fprintf (stdout, "%c\n", c);
	  fflush (stdout);
	  if (c == 'q' || c == 'Q' || c == EOF)
	    break;
	}
      fputs ("Nope. back to sleep\n", stdout);
    }
  tty_reset (STDIN_FILENO);

  puts ("\nDone.");
  return 0;
}


--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe@sourceware.cygnus.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]