delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/1999/08/18/18:08:37

Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm
List-Unsubscribe: <mailto:cygwin-unsubscribe-archive-cygwin=delorie DOT com AT sourceware DOT cygnus DOT com>
List-Archive: <http://sourceware.cygnus.com/ml/cygwin/>
List-Post: <mailto:cygwin AT sourceware DOT cygnus DOT com>
List-Help: <mailto:cygwin-help AT sourceware DOT cygnus DOT com>,
<http://sourceware.cygnus.com/ml/#faqs>
Sender: cygwin-owner AT sourceware DOT cygnus DOT com
Delivered-To: mailing list cygwin AT sourceware DOT cygnus DOT com
Message-Id: <199908182201.RAA31653@mercury.xraylith.wisc.edu>
To: "'Cygwin Mailing List'" <cygwin AT sourceware DOT cygnus DOT com>
Subject: Re: Porting getch() and kbdhit() ???
In-Reply-To: Your message of "Wed, 18 Aug 1999 16:39:24 EDT."
<B3953869CBF8D211A1E50004AC4C1B5402F437 AT ULTIMATE2>
Date: Wed, 18 Aug 1999 17:01:29 -0500
From: Mumit Khan <khan AT xraylith DOT wisc DOT EDU>

"Lincoln, W. Terry" <terryl AT ultimatetechnology DOT 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 AT sourceware DOT cygnus DOT com

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019