Thread: faq: cached input with mygetch()

  1. #1
    GA ichijoji's Avatar
    Join Date
    Nov 2002
    Posts
    179

    faq: cached input with mygetch()

    So I'm trying to put together a little text game at school on their redhat machines, right? I'm using a char buffer with system("clear") to write to the screen and mygetch() from the faq to get input.
    Code:
    int mygetch() {
      struct termios oldt,
                     newt;
      int            ch;
      tcgetattr( STDIN_FILENO, &oldt );
      newt = oldt;
      newt.c_lflag &= ~( ICANON | ECHO );
      tcsetattr( STDIN_FILENO, TCSANOW, &newt );
      ch = getchar();
      tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
      return ch;
    }
    This function does what I need, except it waits for keyboard input before returning a value. Is there any way to get it to return like 0 or something when there's no input, or maybe a whole other function that does that?
    Last edited by ichijoji; 04-07-2004 at 12:19 PM.
    Illusion and reality become impartiality and confidence.

  2. #2
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Hmm not sure if there is a kbhit() for linux or not. But you could use select() on stdin to find out when there is input, however I think that requires the enter key. Might want to change the program to use raw input all the way through and then switch it back before exiting.

  3. #3
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Good news

    If you change it to raw mode then you select will work without the enter key:

    Test program:
    Code:
    #include <stdio.h>
    #include <termios.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/time.h>
    
    void changemode(int);
    int  kbhit(void);
    int main(void)
    {
      int ch;
      changemode(1);
      while ( !kbhit() )
      {
        putchar('.');
      }
    
      ch = getchar();
    
      printf("\nGot %c\n", ch);
    
      changemode(0);
      return 0;
    }
    
    void changemode(int dir)
    {
      static struct termios oldt, newt;
    
      if ( dir == 1 )
      {
        tcgetattr( STDIN_FILENO, &oldt);
        newt = oldt;
        newt.c_lflag &= ~( ICANON | ECHO );
        tcsetattr( STDIN_FILENO, TCSANOW, &newt);
      }
      else
        tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
    }
    
    int kbhit (void)
    {
      struct timeval tv;
      fd_set rdfs;
    
      tv.tv_sec = 0;
      tv.tv_usec = 0;
    
      FD_ZERO(&rdfs);
      FD_SET (STDIN_FILENO, &rdfs);
    
      select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
      return FD_ISSET(STDIN_FILENO, &rdfs);
    
    }
    I'm sure there can be improvements but hey it works
    Last edited by Thantos; 04-07-2004 at 02:45 PM. Reason: Fixing small bug V2 :)

  4. #4
    Registered User
    Join Date
    Apr 2004
    Posts
    9
    To make this work on Solaris you might also find you need the following:

    Code:
    	newt.c_lflag &= ~(ICANON|ECHO|IEXTEN);
    	/* also set TIME to 0 and MIN to 1 (getc will block until there 
    	     is atleast 1 char avalible, and return as soon as there is)*/
    	newt.c_cc[VTIME] = 0;
    	newt.c_cc[VMIN] = 1;
    IEXTEN is a implementation defined extension which seems to be on by default on Solaris and makes bad things (tm) happen, and also Solaris seems to default to VMIN being 4 (haven't actualy confirmed it is 4, but it felt like that, and this fixed it)

    Alan

  5. #5
    Registered User
    Join Date
    Jun 2008
    Posts
    1
    Quote Originally Posted by awoodland View Post
    To make this work on Solaris you might also find you need the following:

    Code:
    	newt.c_lflag &= ~(ICANON|ECHO|IEXTEN);
    	/* also set TIME to 0 and MIN to 1 (getc will block until there 
    	     is atleast 1 char avalible, and return as soon as there is)*/
    	newt.c_cc[VTIME] = 0;
    	newt.c_cc[VMIN] = 1;
    IEXTEN is a implementation defined extension which seems to be on by default on Solaris and makes bad things (tm) happen, and also Solaris seems to default to VMIN being 4 (haven't actualy confirmed it is 4, but it felt like that, and this fixed it)

    Alan
    Man, thanks for that! I can confirm that the VMIN item needs to be set if compiling on HPUX/Itanium (but not for other OSes like Linux); otherwise, you have to press a key exactly 4 times before one gets recognized!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Input class project (again)
    By Elysia in forum C++ Programming
    Replies: 41
    Last Post: 02-13-2009, 10:52 AM
  2. can someone help me with these errors please code included
    By geekrockergal in forum C Programming
    Replies: 7
    Last Post: 02-10-2009, 02:20 PM
  3. Determining if input is int, double, or char
    By Lucid003 in forum C++ Programming
    Replies: 4
    Last Post: 11-16-2005, 04:16 PM
  4. EOF messing up my input stream?
    By Decrypt in forum C++ Programming
    Replies: 4
    Last Post: 09-30-2005, 03:00 PM
  5. FAQ Keyboard Input ? (C++)
    By Malikive in forum FAQ Board
    Replies: 6
    Last Post: 11-07-2001, 09:30 PM