This is my personal blog. I also have a professional blog at http://siliconsparrow.com/

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;
}

5 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

  4. Comment by antoine stern — 28 March 2011 @ 1:10 pm

    I want to turn off echo. Is it possible? I don’t want the key I stroke to be echoed.

  5. Comment by adam — 29 March 2011 @ 7:24 am

    “man termios” will answer your question but to save you the trouble of reading it, add this line and it should disable echo (disclaimer: I didn’t try it but that’s what the manual says):

    t.c_lflag &= ~ECHO;

RSS feed for comments on this post.

Leave a comment

COMMENTS ARE DISABLED DUE TO EXCESSIVE SPAM. I'm sorry about this, I really love to read your comments but the amount of time I spend deleting spam is too much.


Powered by WordPress