getch and arrow codes

149,724

Solution 1

By pressing one arrow key getch will push three values into the buffer:

  • '\033'
  • '['
  • 'A', 'B', 'C' or 'D'

So the code will be something like this:

if (getch() == '\033') { // if the first value is esc
    getch(); // skip the [
    switch(getch()) { // the real value
        case 'A':
            // code for arrow up
            break;
        case 'B':
            // code for arrow down
            break;
        case 'C':
            // code for arrow right
            break;
        case 'D':
            // code for arrow left
            break;
    }
}

Solution 2

getch () function returns two keycodes for arrow keys (and some other special keys), as mentioned in the comment by FatalError. It returns either 0 (0x00) or 224 (0xE0) first, and then returns a code identifying the key that was pressed.

For the arrow keys, it returns 224 first followed by 72 (up), 80 (down), 75 (left) and 77 (right). If the num-pad arrow keys (with NumLock off) are pressed, getch () returns 0 first instead of 224.

Please note that getch () is not standardized in any way, and these codes might vary from compiler to compiler. These codes are returned by MinGW and Visual C++ on Windows.

A handy program to see the action of getch () for various keys is:

#include <stdio.h>
#include <conio.h>

int main ()
{
    int ch;

    while ((ch = _getch()) != 27) /* 27 = Esc key */
    {
        printf("%d", ch);
        if (ch == 0 || ch == 224)
            printf (", %d", _getch ()); 
        printf("\n");
    }

    printf("ESC %d\n", ch);

    return (0);
}

This works for MinGW and Visual C++. These compilers use the name _getch () instead of getch () to indicate that it is a non-standard function.

So, you may do something like:

ch = _getch ();
if (ch == 0 || ch == 224)
{
    switch (_getch ())
    {
        case 72:
            /* Code for up arrow handling */
            break;

        case 80:
            /* Code for down arrow handling */
            break;

        /* ... etc ... */
    }
}

Solution 3

So, after alot of struggle, I miraculously solved this everannoying issue ! I was trying to mimic a linux terminal and got stuck at the part where it keeps a command history which can be accessed by pressing up or down arrow keys. I found ncurses lib to be painfuly hard to comprehend and slow to learn.

char ch = 0, k = 0;
while(1)
{
  ch = getch();
  if(ch == 27)                  // if ch is the escape sequence with num code 27, k turns 1 to signal the next
    k = 1;
  if(ch == 91 && k == 1)       // if the previous char was 27, and the current 91, k turns 2 for further use
    k = 2;
  if(ch == 65 && k == 2)       // finally, if the last char of the sequence matches, you've got a key !
    printf("You pressed the up arrow key !!\n");
  if(ch == 66 && k == 2)                             
    printf("You pressed the down arrow key !!\n");
  if(ch != 27 && ch != 91)      // if ch isn't either of the two, the key pressed isn't up/down so reset k
    k = 0;
  printf("%c - %d", ch, ch);    // prints out the char and it's int code

It's kind of bold but it explains alot. Good luck !

Solution 4

The keypad will allow the keyboard of the user's terminal to allow for function keys to be interpreted as a single value (i.e. no escape sequence).

As stated in the man page:

The keypad option enables the keypad of the user's terminal. If enabled (bf is TRUE), the user can press a function key (such as an arrow key) and wgetch returns a single value representing the function key, as in KEY_LEFT. If disabled (bf is FALSE), curses does not treat function keys specially and the program has to interpret the escape sequences itself. If the keypad in the terminal can be turned on (made to transmit) and off (made to work locally), turning on this option causes the terminal keypad to be turned on when wgetch is called. The default value for keypad is false.

Solution 5

Actually, to read arrow keys one need to read its scan code. Following are the scan code generated by arrow keys press (not key release)

When num Lock is off

  • Left E0 4B
  • Right E0 4D
  • Up E0 48
  • Down E0 50

When Num Lock is on these keys get preceded with E0 2A

  • Byte E0 is -32
  • Byte 48 is 72 UP
  • Byte 50 is 80 DOWN

    user_var=getch();
    if(user_var == -32)
    {
        user_var=getch();
        switch(user_var)
        {
        case 72:
            cur_sel--;
            if (cur_sel==0)
                cur_sel=4;
            break;
        case 80:
            cur_sel++;
            if(cur_sel==5)
                cur_sel=1;
            break;
    
        }
    }
    

In the above code I have assumed programmer wants to move 4 lines only.

Share:
149,724

Related videos on Youtube

qwertz
Author by

qwertz

Updated on July 09, 2022

Comments

  • qwertz
    qwertz almost 2 years

    I'm writing a programm that's using getch() to scan for arrow keys. My code so far is:

    switch(getch()) {
        case 65:    // key up
            break;
        case 66:    // key down
            break;
        case 67:    // key right
            break;
        case 68:    // key left
            break;
    }
    

    Problem is that when I press 'A', 'B', 'C' or 'D' the code will also executed, because 65 is the decimal code for 'A', etc...

    Is there a way to check for an arrow key without call others?

    Thanks!

    • FatalError
      FatalError about 12 years
      It's been ages since I played with this, it's not the least bit standardized... but back when I played with getch(), for "special" keys it actually returned twice. The first time it returned a 0, then a code for the special key, so that you could tell it apart from other keys.
    • P.P
      P.P about 12 years
      65 is only for character A. You have to use the control codes to receive these keys. See this post. stackoverflow.com/questions/2876275/…
    • Anchith Acharya
      Anchith Acharya over 4 years
      @FatalError Sorry, I'm around 7 years late, but what you said has piqued my curiosity. How is it possible that getch() can return twice? A function can only return once, right?
    • FatalError
      FatalError over 4 years
      @AnchithAcharya: You're in luck, because I'm still around 7 years later ;-). What I meant is that to read a "special key" you had to actually call getch() twice. The first call would return 0 (i.e. to say that the next value would be a special key). Then on the second call to getch() it would return a distinct value indicating which special key had been pressed. Mind you, getch() is a non-standard artifact from the DOS days, so it could well have varied by compiler. But here's an example on MSDN: docs.microsoft.com/en-us/cpp/c-runtime-library/reference/…
    • Anchith Acharya
      Anchith Acharya over 4 years
      @FatalError Ah, I got it now. Thanks!
    • Pryftan
      Pryftan over 4 years
      @FatalError Urgh. I was thinking what are you on about with DOS and then it occurred to me that this question doesn't refer to ncurses. That explains a lot. I did dabble with DOS console IO decades ago but I don't remember having to use getch() twice. Then again as much as I loved C (and still do) with DOS I really loved assembly - well both but you know. Anyway the point here is that this post could be ambiguous since it doesn't have any header files (answer does below) and doesn't specify OS/library etc. Even if I was okay editing questions/answers I wouldn't know what to specify it as!
  • Cheers and hth. - Alf
    Cheers and hth. - Alf about 8 years
    Is there some Unix-land version of getch where this answer is correct? The codes here are what you'd get from most terminals when using getchar. They're not what you'd get from getch from <conio.h>.
  • MD XF
    MD XF about 7 years
    Could you explain your answer, please?
  • Muffo
    Muffo almost 7 years
    Do you know why in my terminal I see a 'O' instead of '[' as second character? FYI, I am running zsh inside a tmux session. Thanks!
  • lolbas
    lolbas about 6 years
    Please, do a little reformatting of your code. Also, add explanations of why and how does your code work, especially magic numbers like 224.
  • Gar
    Gar almost 5 years
    This doesn't really answer OP question, as your "UP" will be triggered by the H character for example as well.
  • zwol
    zwol almost 5 years
    @Cheersandhth.-Alf Yes, this is Unix-land getch, specifically getch from the ncurses library (with "keypad" mode disabled).
  • EsmaeelE
    EsmaeelE over 4 years
    getch() ->getchar()
  • yoyo
    yoyo almost 4 years
    On Windows, _getch (from conio.h) must be called twice to handle an arrow key. The first return value is 224, the second is 'A' , 'B', etc. as above.
  • Anic17
    Anic17 over 3 years
    C++ is not the same as C.
  • DarthCucumber
    DarthCucumber about 3 years
    @Cheersandhth.-Alf you can use ncurses however if you don't want to then you have to enable terminal raw mode. Have a look at this link