1

I wrote a getch function for program. I couldn't use curses as it breaks the terminal for iostream I already use. The code:

inline std::string getch() {
    char inp[4];
    system("stty raw");
    inp[0] = std::cin.get();
    if(inp[0] == 27 && (inp[1] = std::cin.get()) != std::char_traits<char>::eof()) {
        std::cin>>inp[2];
        inp[3] = '\0';
    }
    else {
        inp[1] = '\0';
    }
    system("stty cooked echo");
    return std::string(inp);
}

I know it would be better to use termios.h instead of system calls. Everything works fine except if ESC key. I'm trying to capture arrows which are string of for example "\1B[A". When I detect ESC as first character I also read the second two to get full key code. The problem is that it shouldn't occur when I press ESC as it's code is 1B alone. The cin.get() should return EOF when the buffer is empty during read, but it simply stops.

Is there a way to read ESC key on linux without using curses? Why my solution isn't working?

Thanks

pkubik
  • 780
  • 6
  • 19

1 Answers1

1

After many hours of searching I found the solution. I had to use read function from unistd.h It fills an array of given size, with characters from the input. When a key is pressed the buffer is filled with all read characters (works also on multiple keys). So an ESC has simply {27,0,0,...,0} and arrow {27,'[','A',0,0,...,0}. I've rewritten my function using termios.h and put in library, so anyone can benefit.

Here is the code: readkey on github

pkubik
  • 780
  • 6
  • 19
  • Glad it works. Back in the day, programs that wanted to distinguish between the press of an escape key and the press of an arrow or numeric keypad key had to fiddle with the termios `VTIME` and `VMIN` values. Multiple characters that appeared within a few tenths of a second of each other were considered to have come from an arrow or numerical keypad key. – Mark Plotnick Dec 09 '13 at 18:28