4

I am implementing a key reader program in c/c++. I am using linux. I know that the unbuffered getchar function will return little data values of keys. For all ASCII keys (a-z, A-Z, 1-9, punctuation, enter, tab, and ESC) there will be a single value returned from getchar(). For other keys, such as the arrow keys, there will be the ESC key read, but then when getchar() is called again, it will get another value (A, B, C,or D).

A = 65

B = 66

UP arrow = 27 91 65

F5 = 27 91 49 53 126

ESC = 27

full table here

Is there any way to check if there are more characters to be read or if there is just a single character? When a key is read and it's first value is ESC I do not know if it is a function key that starts with ESC or if it is just the ESC key.

#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <iostream>
#include <string>
#include <termios.h>
#include <unistd.h>

using namespace std;

int main(int argc, char *argv[]) {

    int ch[5];
    int i;
    struct termios term;

    tcgetattr( STDIN_FILENO, &term );
    term.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &term );

    ch[0] = getchar();

    // If ch[0] = 27 and there is more data in the buffer
    // printf("You pressed a function key");
    // Else
    // printf("You pressed ESC");

    return 0;   

}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Blue Ice
  • 7,888
  • 6
  • 32
  • 52
  • 2
    What operating system are you targeting? – paddy May 22 '13 at 05:08
  • try using read on stdin and set property of stdin to non-block. Read until it returns a size 0. – bikram990 May 22 '13 at 05:32
  • 1
    if you enter keys beyond what is contained in the ASCII character set – such as the function keys or the control key with another key – that the return value is generally meaningless. These keys are outside the ANSI C definition and therefore the behavior of getchar() when dealing with those key and/or key combinations is system dependent. – Dayal rai May 22 '13 at 06:21
  • @paddy I am using linux. – Blue Ice May 22 '13 at 12:32
  • Would you consider using [ncurses](http://www.gnu.org/software/ncurses/ncurses.html) for your input? I'm pretty sure it handles all the ANSI codes for you. – paddy May 22 '13 at 13:47
  • @paddy I am trying to use only the standard libraries. – Blue Ice May 22 '13 at 14:49

3 Answers3

0

You can mark stdio nonblocking when you get escape and then read as much as possible. You need to include <fcntl.h>

if (ch[0] == 27) {
    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
    for (;;) {
        int c = getchar();
        if (c == EOF)
            break;
        printf("%u ", c);
    }
    fcntl(STDIN_FILENO, F_SETFL, flags);
    puts("\n");
}

There is still a problem with two keys after each other as the loop will read until there is no more data available.

the_jk
  • 539
  • 2
  • 10
  • You'll need to call `clearerr(stdin)` at some point; otherwise all subsequent `getchar` calls will return EOF... – Chris Dodd Nov 19 '15 at 21:40
0

After you get first ESC character, you can read other characters without waiting (for example by setting c_cc[VMIN] = 0 and c_cc[VTIME] = 0 in the termios structure), then if chars you found did not match a function key pattern, you insert the chars you have read in a buffer to be read back. Then, at the next get you return buffered chars first, if any.

-1

Add the getchar() inside a loop and come out of the loop when the key entered is ENTER. For example:

char ch[5];
int i=0;
while(1)
{
   ch[i] = getchar();
   if('\n'==ch[i])
   {
     break;
   }
   i++;
   if(i==5)
   {
     break;
   }

}
akhil
  • 732
  • 3
  • 13