Non-blocking user input in loop without ncurses. | c/c++ programming by examples

# Non-blocking user input in loop without ncurses.

Posted on April 8, 2007 by mysurface

The title sounds a bit awkward, let my briefly explain what is it all about.

In my program, I want to wait for user input, but at the same time, I want my other operations keep continue processing. That I define it as non-blocking user input. I want my program to wait for user input in the loop, if receives user input process it and continue wait for next user input, else continue processing other circular operations.

Usually, people will think about using ncurses library. By using ncurses, you can easily perform non-blocking user input using timeout(0) and getch(). Refers to the ncurses matrix for references.

What if I don’t want to uses ncurses? Its there any alternatives? Sometimes I just wanna add a function which need non-blocking in a large program, I don’t want to use ncurses because it makes my print line acts differently, or some other reason.

I have figure out a way, thanks to programmers at ##c@irc.freenode.net. It might look messy and complected, but it works the way I wanted. I uses functions of termios and select, lets look at the functions one by one.

?

01
02
03
04
05
06
07
08
09
10
11

`int` `kbhit()`
`{`
`` `struct` `timeval tv;`
`` `fd_set fds;`
`` `tv.tv_sec = 0;`
`` `tv.tv_usec = 0;`
`` `FD_ZERO(&fds);`
`` `FD_SET(STDIN_FILENO, &fds);` `//STDIN_FILENO is 0`
`` `select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);`
`` `return` `FD_ISSET(STDIN_FILENO, &fds);`
`}`

This function perform non-blocking checking on the standard input (stdin) without timeout 0, tv.tv_sec and tv.tv_usec both set to zero. select usually uses in the case where there have multiple I/O need to process, or check at the same time. But in this case, I only interested in standard input, therefore only one FD_SET(STDIN_FILENO, &fds) is trigger. For select parameters details, please check out the manual. Seems we are only interested in input, so we place out fd set at second parameter of select(), the 3rd is for output and 4th is for exception.

Important part, after select if user input is trigger, FD_ISSET will return non zero value, else return 0. So, we now can use it like this

?

1 2 3 4 5 | `while``(!kbhit())` `{` `` `//do certain operation..` `}` `//user hits enter.`

Due to the canonical mode of your terminal, you need to hit enter to confirm your user input. Canonical mode means it always wait for enter to confirms the user input. If that is not your case, bellow is another function to cater that.

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23

`void` `nonblock(``int` `state)`
`{`
`` `struct` `termios ttystate;`
`` `//get the terminal state`
`` `tcgetattr(STDIN_FILENO, &ttystate);`
`` `if` `(state==NB_ENABLE)`
`` `{`
`` `//turn off canonical mode`
`` `ttystate.c_lflag &= ~ICANON;`
`` `//minimum of number input read.`
`` `ttystate.c_cc[VMIN] = 1;`
`` `}`
`` `else` `if` `(state==NB_DISABLE)`
`` `{`
`` `//turn on canonical mode`
`` `ttystate.c_lflag |= ICANON;`
`` `}`
`` `//set the terminal attributes.`
`` `tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);`
`}`

The function name might be misleading, what the function actually does is turn off the canonical mode for stdin. First, get the states of stdin of term. Next turn off the canonical by set 0 to the bits. The line of ttystate.c_cc[VMIN] is set the minimum number of user input to accept. If you set it as 2, the select will wait until 2 character is given, then it will capture as input. At last set the term state. The function actually does allow you to turn on and off the canonical mode.

Okay, Let see how it apply to work

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

`int` `main()`
`{`
`` `char` `c;`
`` `int` `i=0;`
`` `nonblock(NB_ENABLE);`
`` `while``(!i)`
`` `{`
`` `usleep(1);`
`` `i=kbhit();`
`` `if` `(i!=0)`
`` `{`
`` `c=``fgetc``(stdin);`
`` `if` `(c==``'q'``)`
`` `i=1;`
`` `else`
`` `i=0;`
`` `}`
`` `fprintf``(stderr,``"%d "``,i);`
`` `}`
`` `printf``(``"\n you hit %c. \n"``,c);`
`` `nonblock(NB_DISABLE);`
`` `return` `0;`
`}`

Press ‘q’ will lead the program to quit, else you will see the print of ’0′ overwhelming the screen. Observed that I am using usleep(1) inside the loop, without putting usleep, the programs is more responsive, but it uses high CPU resources. On the other hand, putting usleep(1) reduces the CPU resources and also decreases responsiveness of the program. Depend on your needs, you may choose to put it in or not.

I have make the comparison between this application and a simple ncurses program, this program seems to use lesser memory. Couldn’t measure for CPU resources, as both ps and top shows 0.0 %.

Curses sample shows as bellow:

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

`#include<stdio.h>`
`#include<curses.h>`
`#include<unistd.h>`
`int` `main ()`
`{`
`` `int` `i=0;`
`` `initscr();` `//in ncurses`
`` `timeout(0);`
`` `while``(!i)`
`` `{`
`` `usleep(1);`
`` `i=getch();`
`` `printw(``"%d "``,i);`
`` `if``(i>0)`
`` `i=1;`
`` `else`
`` `i=0;`
`` `}`
`` `endwin();`
`` `printf``(``"\nhitkb end\n"``);`
`` `return` `0;`
`}`

Download the source code:
Non-blocking kbhit sample source code.

## 10 thoughts on “Non-blocking user input in loop without ncurses.”

1. thanks again! I find your site very helpful, over and over again!

2. Fascinating. it’s exactly what i want. thanks.

3. Thanks! I was already using the select, but had the cin in my select statment. Had no idea about fgetc. Perfect.

4. Thanks. Anyway – here is a question.
   Why can’t we get the first pressed button?

5. This is just what I was looking for. As an OS/Driver/Platform/Multicore-Exec programmer, I sometimes need basic guidance on simple app layer stuff. This was helpful.
   Except the sample source download seems lost.

6. amazing

7. Thanks a lot , it was of great help

8. any one can help me to present a term paper regarding the topic
   ‘c programming database”

9. http://cc.byexamples.com/20070408/non-blocking-user-input-in-loop-without-ncurses/non-blocking-kbhit/

   I tried downloading the source code from yr site but the file is gone could you please send me the codes?

   thanks for sharing

10. Very helpful – thanks!

### Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Name *

Email *

Website

Comment

You may use these HTML tags and attributes: `<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>`