Non-Blocking Console Input C++

C non-blocking keyboard input

As already stated, you can use sigaction to trap ctrl-c, or select to trap any standard input.

Note however that with the latter method you also need to set the TTY so that it's in character-at-a-time rather than line-at-a-time mode. The latter is the default - if you type in a line of text it doesn't get sent to the running program's stdin until you press enter.

You'd need to use the tcsetattr() function to turn off ICANON mode, and probably also disable ECHO too. From memory, you also have to set the terminal back into ICANON mode when the program exits!

Just for completeness, here's some code I've just knocked up (nb: no error checking!) which sets up a Unix TTY and emulates the DOS <conio.h> functions kbhit() and getch():

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>

struct termios orig_termios;

void reset_terminal_mode()
{
tcsetattr(0, TCSANOW, &orig_termios);
}

void set_conio_terminal_mode()
{
struct termios new_termios;

/* take two copies - one for now, one for later */
tcgetattr(0, &orig_termios);
memcpy(&new_termios, &orig_termios, sizeof(new_termios));

/* register cleanup handler, and set the new terminal mode */
atexit(reset_terminal_mode);
cfmakeraw(&new_termios);
tcsetattr(0, TCSANOW, &new_termios);
}

int kbhit()
{
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv) > 0;
}

int getch()
{
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}

int main(int argc, char *argv[])
{
set_conio_terminal_mode();

while (!kbhit()) {
/* do some work */
}
(void)getch(); /* consume the character */
}

How do you do non-blocking console I/O on Linux in C?

You don't, really. The TTY (console) is a pretty limited device, and you pretty much don't do non-blocking I/O. What you do when you see something that looks like non-blocking I/O, say in a curses/ncurses application, is called raw I/O. In raw I/O, there's no interpretation of the characters, no erase processing etc. Instead, you need to write your own code that checks for data while doing other things.

In modern C programs, you can simplify this another way, by putting the console I/O into a thread or lightweight process. Then the I/O can go on in the usual blocking fashion, but the data can be inserted into a queue to be processed on another thread.

Update

Here's a curses tutorial that covers it more.

Non-blocking console input C++

I would do this by creating separate a thread which calls normal blocking IO functions and pass it a callback function which it would call when it got input. Are you sure you need to do what you said you want to do?

As for outputting information at the same time, what would happen if the user was in the middle of typing some input and you printed something?

Non blocking input C

When time ran out have timeleft() set a global flag, which is tested by questions(), and if set makes the code leave the while (1) loop.

Make sure access to the flag is protected using a mutex.

Talking about "protected access": key is accessed concurrently without protection. Not good.

Non-Blocking i/o in c? (windows)

From the documentation for _kbhit():

The _kbhit function checks the console for a recent keystroke. If the function returns a nonzero value, a keystroke is waiting in the buffer. The program can then call _getch or _getche to get the keystroke.

So, in your loop:

while (true) {
// ...
if (_kbhit()) {
char c = _getch();
// act on character c in whatever way you want
}
}

So, you can still use _getch(), but limit its use to only after _kbhit() says there is something waiting. That way it won't block.

Non-blocking ReadConsoleInput

This is all documented in ReadConsoleInput. You can determine if there is a console input with GetNumberOfConsoleInputEvents. And you are able to to determine the type of console input events with PeekConsoleInput.

So GetNumberOfConsoleInputEvents is all you need.

You can also use WaitForSingleObject with the console handle to wait for a next available input. This is also documented in ReadConsoleInput

Cin without waiting for input?

It's sad that there is no simple portable way to checking asynchronously if a key was hit. But I guess that the standard committee has carefully evaluated the pros and cons.

If you don't want to rely on third party event management libraries, and if multithreading would be overkill, one alternative could be to have your own version of kbhit(), with conditional compiling for the environments you want to support:

  • if your conio.h supports kbhit() just use it.
  • for windows, you can refer to _kbhit()
  • for linux and posix, you can use Matthieu's answer, or look here for Morgan Mattews's code

It's not the most academic answer, but it's pragmatic.



Related Topics



Leave a reply



Submit