How can I capture single keystrokes in a unix console application without blocking?

I have a very simple TCP server written in C. It runs endlessly, waiting for connections. On Windows, I use select to check activity on the socket, and if not, I have the following code allowing me to exit by pressing "q" on the keyboard:

 if( kbhit() ) { char c = getch(); if( c == 'q' ) break; } 

This does not work on unix, as kbhit does not exist, and getch works differently. I found some sample code that uses tcsetattr to change terminal settings and allow character input by character. After calling the init function, I open / dev / stdin (using O_NONBLOCK ) and read the character, but read( f, &c, 1 ) blocked until the character is printed.

I assume that I could create a separate thread and wait for it indefinitely, and then signal the first thread if the user presses q, but that seems a bit heavy. Of course, is there an easier way?

+4
source share
3 answers

Add stdin to your descriptor list, and if it has data, call read to read one character from it.

+5
source

Rather, add "f" from your

 read( f, &c, 1 ) 

to select a call. When f is ready to read, the character has been pressed and read () will not block.

+1
source

On Unix, whether on the system console or in the X-terminal window, keyboard I / O passes through the virtual terminal. Device / dev / tty is currently the usual way to access the process control terminal. Device operations other than open / close / read / write are handled by the ioctl (2) system call for that particular device. The general idea of ​​what you want to do is

Open a control terminal (which may or may not be stdin)

Change the operating mode on this terminal to return without waiting for the full input line (which is the standard default)

Continue working with the rest of your program, knowing that reading from this terminal (which may be stdin) can return partial strings or even null characters without being an error or termination condition.


A detailed answer on how to take the second step can be found in the C-programming faq . They also point out that this is an OS issue, not a language issue. They provide nine possibilities, but the three main ones relate to this issue:

  • Use the curses library (3)
  • Old BSD style systems, use sgttyb to install CBREAK or RAW
  • Posix or older System V systems, use TCGETAW / TCSETAW to set c_cc [VMIN] to 1 and c_cc [VTIME] to 0.

Following a few links in the C FAQ can lead to this page of kbhit code snippets .

+1
source

Source: https://habr.com/ru/post/1277575/


All Articles