I'm trying to write a program in C (on Linux) that loops until the user presses a key, but shouldn't require a keypress to continue each loop.
Is there a simple way to do this? I figure I could possibly do it with select()
but that seems like a lot of work.
Alternatively, is there a way to catch a ctrl-c keypress to do cleanup before the program closes instead of non-blocking io?
As already stated, you can use
sigaction
to trap ctrl-c, orselect
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>
functionskbhit()
andgetch()
:If you are happy just catching Control-C, it's a done deal. If you really want non-blocking I/O but you don't want the curses library, another alternative is to move lock, stock, and barrel to the AT&T
sfio
library. It's nice library patterned on Cstdio
but more flexible, thread-safe, and performs better. (sfio stands for safe, fast I/O.)select()
is a bit too low-level for convenience. I suggest you use thencurses
library to put the terminal in cbreak mode and delay mode, then callgetch()
, which will returnERR
if no character is ready:At that point you can call
getch
without blocking.You probably want
kbhit();
this may not work on all environments. A portable way would be to create a monitoring thread and set some flag on
getch();
Another way to get non-blocking keyboard input is to open the device file and read it!
You have to know the device file you are looking for, one of /dev/input/event*. You can run cat /proc/bus/input/devices to find the device you want.
This code works for me (run as an administrator).
You can do that using select as follow:
Not too much work :D