I’m trying to use “select()” to test if a key has been struck and then read it. It sort of works but only if {Enter} is pressed after the character.
Sample code is as follows:
// selectkb.c #include <stdio.h> #include <sys/select.h> //@ Main program int main( int argc, char **argv) { int n; fd_set readfds; FD_ZERO( &readfds ); FD_SET( 0, &readfds ); printf( "calling select on fd 0...n" ); n = select( 1, &readfds, NULL, NULL, NULL ); printf( "select reports %d fd readyn", n ); if( FD_ISSET( 0, &readfds ) ) { char c; printf( "select reports fd 0 ready.n" ); c = getchar(); printf( "getchar returned "%c"n", c ); } else { printf( "fd 0 not ready.n" ); } return( 0 ); }
If I press A nothing happens, but if I Press A{Enter}, the output is:
calling select on fd 0... select reports 1 fd ready select reports fd 0 ready. getchar returned "A"
The output is the same if I press ABC{Enter}
Why is the {Enter} required?
(Note: I know there are other ways to do this, but in my actual app, I select on some sockets as well as fd0, but I omitted that for succinctness)
Advertisement
Answer
I found the solution based on a response from @Ben Voigt. Apparently, by default, the terminal operates in “Canonical” (cooked) mode wherein the kernel does not deliver characters until an {Enter} is pressed. The solution is to set the terminal to non-canonical (raw) mode. The easiest way to do this is using termios as shown in the updated code below. When this is done, characters are delivered one-by-one and select() behaves as I want.
// selectkb.c #include <stdio.h> #include <sys/select.h> #include <termios.h> //@ Main program int main( int argc, char **argv) { int n; fd_set readfds; struct termios attr; // SET RAW MODE tcgetattr( 0, &attr ); attr.cflag &= ~ICANON; tcsetattr( 0, TCSANOW, &attr ); FD_ZERO( &readfds ); FD_SET( 0, &readfds ); printf( "calling select on fd 0...n" ); n = select( 1, &readfds, NULL, NULL, NULL ); printf( "select reports %d fd readyn", n ); if( FD_ISSET( 0, &readfds ) ) { char c; printf( "select reports fd 0 ready.n" ); c = getchar(); printf( "getchar returned "%c"n", c ); } else { printf( "fd 0 not ready.n" ); } return( 0 ); }