When you are writing an interactive application under Linux, often it is necessary to constantly poll terminal for keyboard input. This can be done by using termio
and stdio
functions.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/types.h>
int r = 1; // if r == 0, exit loop
fd_set fd; // to store file descriptor masks
struct timespec d; // insert delay to give up CPU
struct timeval t; // used by select()
unsigned char k; // stores the key input
struct termios i, n; // stores terminal settings
// get current terminal settings so that we may restore it later
tcgetattr(0, &i);
// duplicate current settings and add the settings we want
memcpy(&n, &i, sizeof(struct termios));
n.c_lflag &= ~ICANON;
n.c_lflag &= ~ECHO;
n.c_lflag &= ~ISIG;
n.c_cc[VMIN] = 1;
n.c_cc[VTIME] = 0;
// update terminal settings with our own
tcsetattr(0, TCSANOW, &n);
// set up a sleep delay, to give up the input thread
d.tv_sec = 0;
d.tv_nsec = 1000000000 / 60;
while (r == 1) {
FD_ZERO(&fd);
FD_SET(STDIN_FILENO, &fd);
t.tv_sec = 0;
t.tv_usec = 0;
if (select(STDIN_FILENO + 1, &fd, NULL, NULL, &t) > 0) {
if (read(STDIN_FILENO, &k, 1) == 1) {
switch(k) {
case 'q':
case 'Q':
r = 0;
break;
default:
break;
}
}
}
nanosleep(&d, NULL);
}
// done with terminal input, restore initial settings
tcsetattr(0, TCSANOW, &i);
For an interactive application it is often undesirable to have all of the key presses echoed in the terminal and you may want to filter certain key combinations, so we use tcsetattr()
to set our own terminal settings with ECHO
and ISIG
bits switched off.