3

I have a simple program that can detect arrow key presses from the user, though I have two questions. But First, here's the code:

#include <iostream>
#include <conio.h>
#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 77
#define KEY_RIGHT 75

using namespace std;

int main()
{
    while(1)
    {
        char c = getch();
        cout << "Hello";
        switch(c) {
        case KEY_UP:
            cout << endl << "Up" << endl;//key up
            break;
        case KEY_DOWN:
            cout << endl << "Down" << endl;   // key down
            break;
        case KEY_LEFT:
            cout << endl << "Right" << endl;  // key right
            break;
        case KEY_RIGHT:
            cout << endl << "Left" << endl;  // key left
            break;
        default:
            cout << endl << "NULL" << endl;  // any other key
            break;
        }
    }
    return 0;
}

Question 1: Whenever I press any arrow key, why does it print "Hello" TWICE?

Question 2: Whenever I press any arrow or non-arrow key, it prints the default switch case, "NULL", which is supposed to be only for non-arrow keys. Why is this?

Thanks

Loqz
  • 373
  • 4
  • 16
  • 1
    Probably the newline. – erip Oct 28 '15 at 02:48
  • Have you tried printing the characters you're getting? – erip Oct 28 '15 at 02:50
  • @erip Yup I did, the characters for c are simply alpha, M, K and the just usual arrow key characters.. what do you mean newline? – Loqz Oct 28 '15 at 02:55
  • 1
    I think the definitions for KEY_UP, KEY_DOWN... are wrong: those are not the right values for the arrow key codes on Windows. Try `int c = getch();`, and check the values you get for the arrow keys – Daniel Strul Oct 28 '15 at 02:59

2 Answers2

5

When reading keys with conio and getch, in order to be able to handle special keys (arrow keys, function keys) while still fitting its return value in a char, getch returns special keys as two-char sequences. The first call returns 0 (or 0xe0, depending on the C++ implementation you're using), while the second call returns the code of the special key. (Otherwise, your KEY_DOWN - ASCII 80 - by itself would be 'P'.)

MSDN has more info.

One approach to putting all of this together would be something like the following:

char c = getch();
if (c == 0) {
    switch(getch()) {
        // special KEY_ handling here
        case KEY_UP:
            break;
    }
} else {
    switch(c) {
        // normal character handling
        case 'a':
            break;
    }
 }
Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
  • That explains it, thanks! If that's so, is it possible to take only the second return value of getch() and disregard the first? – Loqz Oct 28 '15 at 03:12
  • 1
    The current documentation says _"The first call returns 0 or 0xE0. The second call returns the key scan code."_ so shouldn't it be `if (c == 0 || c == 0xE0)` ? – Ted Lyngmo Aug 22 '23 at 12:56
  • 1
    @TedLyngmo - Yes, you're correct. Although it looks like the [current MSVC](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwch?view=msvc-170) uses `_getch()` instead of `getch()` - for older or alternative libraries that still use `getch()`, `0` may still be correct. – Josh Kelley Aug 22 '23 at 13:33
0

you can check yourself by printing the output of _getch(). For the arrow keys you need to call it twice since arrow keys return two values. The first value depends on the Number lock.

#include <iostream>
#include <conio.h>

void Input() {
    if (_kbhit()) {
        if(_getch()==224)
            switch (_getch())
            {
            case 72:
                printf("up arrow\n");
                break;
            case 75:
                printf("left arrow\n");
                break;
            case 77:
                printf("right arrow\n");
                break;
            case 80:
                printf("down arrow\n");
                break;
            default:
                break;
            }
    }
}
int main()
{
    while (1) {
        Input();
    }
    return 0;
}
HariUserX
  • 1,341
  • 1
  • 9
  • 17