Unbuffered input from stdin

Unbuffered input from stdin

Post by Jan Schamper » Thu, 09 Jan 2003 12:59:06



Hello!

Is there a way (under C and Linux) to get unbuffered keyboard input when
stdin is a terminal? I disabled the stdio-buffers, but it doesn't take
effect. I guess the terminal driver buffers.

I forgot: I don't want to use (n)curses libs.

Regards, Jan

 
 
 

Unbuffered input from stdin

Post by Floyd Davidso » Thu, 09 Jan 2003 15:03:32



>Hello!

>Is there a way (under C and Linux) to get unbuffered keyboard input when
>stdin is a terminal? I disabled the stdio-buffers, but it doesn't take
>effect. I guess the terminal driver buffers.

>I forgot: I don't want to use (n)curses libs.

>Regards, Jan

/*
 *  kbhit(), a keyboard lookahead monitor
 *  getch(), a blocking single character input from stdin
 *
 *  Plus a demo main() to illustrate usage.
 */

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>

int getch(void);
int kbhit(void);

#define CMIN  1

#ifdef CTIME
#undef CTIME
#endif

#define CTIME 1

/*
 *  kbhit()  --  a keyboard lookahead monitor
 *
 *  returns the number of characters available to read.
 */
int
kbhit(void)
{
  int                   cnt = 0;
  int                   error;
  static struct termios Otty, Ntty;

  tcgetattr(0, &Otty);
  Ntty = Otty;

  Ntty.c_iflag          = 0;       /* input mode        */
  Ntty.c_oflag          = 0;       /* output mode       */
  Ntty.c_lflag         &= ~ICANON; /* raw mode              */
  Ntty.c_cc[VMIN]       = CMIN;    /* minimum chars to wait for */
  Ntty.c_cc[VTIME]      = CTIME;   /* minimum wait time */

  if (0 == (error = tcsetattr(0, TCSANOW, &Ntty))) {
    struct timeval      tv;
    error     += ioctl(0, FIONREAD, &cnt);
    error     += tcsetattr(0, TCSANOW, &Otty);
    tv.tv_sec  = 0;
    tv.tv_usec = 100;   /* insert a minimal delay */
    select(1, NULL, NULL, NULL, &tv);
  }

  return (error == 0 ? cnt : -1 );

Quote:}

/*
 *  getch()  --  a blocking single character input from stdin
 *
 *  Returns a character, or -1 if an input error occurs.
 *
 *  Conditionals allow compiling with or without echoing of
 *  the input characters, and with or without flushing pre-existing
 *  existing  buffered input before blocking.
 *
 */
int
getch(void)
{
  char                  ch;
  int                   error;
  static struct termios Otty, Ntty;

  fflush(stdout);
  tcgetattr(0, &Otty);
  Ntty = Otty;

  Ntty.c_iflag  =  0;           /* input mode           */
  Ntty.c_oflag  =  0;           /* output mode          */
  Ntty.c_lflag &= ~ICANON;  /* line settings        */

#if 1
  /* disable echoing the char as it is typed */
  Ntty.c_lflag &= ~ECHO;    /* disable echo         */
#else
  /* enable echoing the char as it is typed */
  Ntty.c_lflag |=  ECHO;        /* enable echo          */
#endif

  Ntty.c_cc[VMIN]  = CMIN;      /* minimum chars to wait for */
  Ntty.c_cc[VTIME] = CTIME;     /* minimum wait time    */

#if 1
/*
 * use this to flush the input buffer before blocking for new input
 */
#define FLAG TCSAFLUSH
#else
/*
 * use this to return a char from the current input buffer, or block if
 * no input is waiting.
 */
#define FLAG TCSANOW

#endif

 if (0 == (error = tcsetattr(0, FLAG, &Ntty))) {
    error  = read(0, &ch, 1 );                /* get char from stdin */
    error += tcsetattr(0, FLAG, &Otty);   /* restore old settings */
  }

  return (error == 1 ? (int) ch : -1 );

Quote:}

/*
 * a cutsie main() to demo how getch() and kbhit() work.
 */

#include <ctype.h>

int
main(void)
{
  int ch, cnt;
  static struct termios Otty, Ntty;

  tcgetattr(0, &Otty);
  Ntty = Otty;
  Ntty.c_lflag &= ~ECHO;

  printf("You must enter 10 characters to get\nthis program to continue:  ");
  fflush(stdout);
  /* collect 10 characters */
  while (1) {
    if (10 <= (cnt = kbhit())) {
      break;
    }
  }

  tcsetattr(0, TCSANOW, &Ntty); /* disable echoing of further input */
  printf("\nSTOP!");
  fflush(stdout);
  printf("\nNow type <Enter> to continue!");
  fflush(stdout);
  ch = getchar();
  tcsetattr(0, TCSANOW, &Otty); /* enable echoing of further input */
  printf("\n\nThe first five characters are:  \"");
  /*
   * print a few chars, note that calling getch() will flush
   * remaining buffered input.
   */
  cnt = 4;
  do {
    printf("%c", ch);
    ch = getchar();
  } while  (--cnt);
  printf("%c\"\n\n", ch);

  printf("\n\n      ***  Demo Menu  ***\n\n");
  printf("      Option       Action\n");
  printf("        A          Exit and print an A word\n");
  printf("        B          Exit and print a  B word\n");
  printf("        C          Exit and print a  C word\n");
  printf("\n      Enter your choice:  ?\b");
  fflush(stdout);

  while(1) {
    switch (ch = getch()) {
    case 'a': case 'A':
      printf("%c\n\nThat is an *awesome* function!\n", toupper(ch));
      break;
    case 'b': case 'B':
      printf("%c\n\nThat is a *beneficial* function!\n", toupper(ch));
      break;
    case 'c': case 'C':
      printf("%c\n\nThat is a *critical* function!\n", toupper(ch));
      break;
    default:
      continue;
    }
    break;
  }
  return 0;

Quote:}

--
Floyd L. Davidson         <http://www.ptialaska.net/~floyd>


 
 
 

Unbuffered input from stdin

Post by Jan Schamper » Thu, 09 Jan 2003 15:33:33



>>Is there a way (under C and Linux) to get unbuffered keyboard input when
>>stdin is a terminal? I disabled the stdio-buffers, but it doesn't take
>>effect. I guess the terminal driver buffers.

>>I forgot: I don't want to use (n)curses libs.

(snipped some code)

Thank you very much, this is exactly what I need. I searched the whole night
and didn't find some really useful information.

Thanks again.

Bye,
Jan

 
 
 

Unbuffered input from stdin

Post by scz » Thu, 09 Jan 2003 15:46:06


/*
 * gcc -Wall -pipe -O3 -o keypress keypress.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>

static struct termios originalTermParam;

static void set_keypress ( void )
{
    struct termios currentTermParam;

    tcgetattr( 0, &originalTermParam );
    memcpy( &currentTermParam, &originalTermParam, sizeof( struct termios ) );

    /*
     * Disable canonical mode, and set buffer size to 1 byte
     */
    currentTermParam.c_lflag       &= ~ICANON;
    currentTermParam.c_lflag       &= ~ECHO;
    currentTermParam.c_cc[ VTIME ]  = 255;
    currentTermParam.c_cc[VMIN]     = 1;

    tcsetattr( 0, TCSANOW, &currentTermParam );
    return;

Quote:}  /* end of  set_keypress */

void reset_keypress ( void )
{
    tcsetattr( 0, TCSANOW, &originalTermParam );
    return;

Quote:}  /* end of reset_keypress */

int main ( void )
{
    puts( "main start" );
    set_keypress();
    while ( 1 )
    {
        if ( getchar() == ( int )'q' )
        {
            break;
        }
    }
    reset_keypress();
    puts( "main stop" );
    return( EXIT_SUCCESS );
Quote:}  /* end of main */


Quote:> Hello!

> Is there a way (under C and Linux) to get unbuffered keyboard input when
> stdin is a terminal? I disabled the stdio-buffers, but it doesn't take
> effect. I guess the terminal driver buffers.

> I forgot: I don't want to use (n)curses libs.

> Regards, Jan

 
 
 

1. unbuffered stdin in aix using standard C

Hi!  I'm trying to get a user's keypress as soon as it's typed (no waiting
for a newline
or a full buffer) using standard C in an AIX environment (though a solution
for any flavor of UNIX would be ideal).  I've tried getc, getchar, read,
getch (from the curses library), all without luck.  Complicating this is
it's at the receiving end of a pipe (stdin has been dup() and /dev/tty has
been freopen()).  For example:
<data generating prog> | myprog.  Also, I can't use any curses call that
requires a
window (wgetchl() does exactly what I want, but it requires a curses window,
which I can't use).

How can I set stdin to be unbuffered so I can get a char as soon as it's
typed?

Thanks in advance for any help.

Mary

2. cdrom timeouts

3. Unbuffering stdin with idiosyncracies

4. Asking too much ? slirp+nntpd: how to read NEWS locally

5. How to unbuffer stdin?

6. XF_Mach32 harware cursor -> white rectangle

7. Help-Unbuffered read from stdin???

8. Lots of segmentation faults.

9. unbuffered stdout/stdin

10. Unbuffered STDIN

11. Help-Unbuffered read from stdin???

12. Unbuffering stdin

13. Unbuffered input