The best way to read single characters from a stream in a C++-friendly way is to get the underlying streambuf and use the sgetc()/sbumpc() methods on it. However, if cin is supplied by a terminal (the typical case) then the terminal likely has line buffering enabled, so first you need to set the terminal settings to disable line buffering. The example below also disables echoing of the characters as they are typed.
#include <iostream> // cout, cin, streambuf, hex, endl, sgetc, sbumpc
#include <iomanip> // setw, setfill
#include <fstream> // fstream
// These inclusions required to set terminal mode.
#include <termios.h> // struct termios, tcgetattr(), tcsetattr()
#include <stdio.h> // perror(), stderr, stdin, fileno()
using namespace std;
int main(int argc, const char *argv[])
{
struct termios t;
struct termios t_saved;
// Set terminal to single character mode.
tcgetattr(fileno(stdin), &t);
t_saved = t;
t.c_lflag &= (~ICANON & ~ECHO);
t.c_cc[VTIME] = 0;
t.c_cc[VMIN] = 1;
if (tcsetattr(fileno(stdin), TCSANOW, &t) < 0) {
perror("Unable to set terminal to single character mode");
return -1;
}
// Read single characters from cin.
std::streambuf *pbuf = cin.rdbuf();
bool done = false;
while (!done) {
cout << "Enter an character (or esc to quit): " << endl;
char c;
if (pbuf->sgetc() == EOF) done = true;
c = pbuf->sbumpc();
if (c == 0x1b) {
done = true;
} else {
cout << "You entered character 0x" << setw(2) << setfill('0') << hex << int(c) << "'" << endl;
}
}
// Restore terminal mode.
if (tcsetattr(fileno(stdin), TCSANOW, &t_saved) < 0) {
perror("Unable to restore terminal mode");
return -1;
}
return 0;
}