ADAM'S WEB PRESENCE

2 February 2009

Reading a single keystroke with C++ on Linux

Filed under: Nerd Notes — adam @ 9:03 am

Just say you want to input a single key from your user such as asking “Would you like to continue [y/n] ?” without requiring the user to press ENTER. You’d think you could do it like this:

char c;
cin >> c;
cout << "You pressed " << c << endl;

But it doesn't work! The user has to press ENTER before the cin function will complete.

I read all sorts of crazy solutions on the web to fix this, most of which involve using NCURSES but I think that is total overkill. I have found a simpler way.

Now it's not the fault of std::cin or even C++. It's the operating system which buffers the keyboard input, only releasing it to your app when the user whacks ENTER. So what you need to do is tell the OS not to buffer keystrokes. You can do this with the termios functions in Linux. Here is an example:

// Example for inputting a single keystroke in C++ on Linux
// by Adam Pierce <adam@doctort.org>
// This code is freeware. You are free to copy and modify it any way you like.

#include <iostream>
#include <termios.h>

using namespace std;
main()
{
// Black magic to prevent Linux from buffering keystrokes.
    struct termios t;
    tcgetattr(STDIN_FILENO, &t);
    t.c_lflag &= ~ICANON;
    tcsetattr(STDIN_FILENO, TCSANOW, &t);

// Once the buffering is turned off, the rest is simple.
    cout << "Enter a character: ";
    char c = cin.get();
    cout << "Your character was " << c << endl;

    return 0;
}

3 Comments »

  1. Comment by David — 23 July 2009 @ 9:32 am

    Ingenious! I never would have thought the problem came from the operating system for the keyboard. I would give you applause if you could hear it.

  2. Comment by Prashant — 29 August 2009 @ 12:29 am

    can you explain the line ?please..
    t.c_lflag &= ~ICANON

  3. Comment by adam — 29 August 2009 @ 7:08 am

    It is a boolean operation to remove the ICANON flag from t.c_lflag. The ~ operator performs a bitwise negation operation – effectively turning on all bits except ICANON. The &= operator performs a logical AND of that with the c_lflag member and puts the result back into c_lflag.

    It can be read as t.c_lflag AND EQUALS NOT ICANON.

    See this Wikipedia page for more information about C and C++ operators:

    http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B

RSS feed for comments on this post. TrackBack URI

Leave a comment


Powered by WordPress