27

I have been having a problem with detecting arrow key presses in my C++ console application. I have tried everything I have found, both here and on other tutorial sites, but all of them give me the same thing whenever I press the arrow:

Process returned 0 <0x0> execution time : 2.249 s
Press any key to continue.

Here are all the methods of detecting the key press that I have tried, all ending up the same way. These are the only two left in my code, the others I attempted I deleted instead of commenting out.

Method one:

c1 = getch();
if(c1 == 0)
{

    c2 = getch();

    if(c2 == 72) {cout << endl << "Up Arrow" << endl;}
    else if(c2 == 80) {cout << endl << "Down Arrow" << endl;}
    else{cout << endl << "Incorrect Input" << endl;}

}

Method two:

switch(getch()) {
case 65:
       cout << endl << "Up" << endl;//key up
    break;
case 66:
    cout << endl << "Down" << endl;   // key down
    break;
case 67:
    cout << endl << "Right" << endl;  // key right
    break;
case 68:
    cout << endl << "Left" << endl;  // key left
    break;
}

Is there some error in my code which made me go back to my main method, or did it skip over some code? Is there a faster way to do this? I'm almost 100% sure that my other code doesn't have anything to do with this problem, because I isolated the code from be dependent on any other aspect of the program, and I kept having the same problem.

Again, I tried every method of getting the arrow key press that I could find, and I keep getting the same problem. If it matters, I'm on a Windows 8 Samsung ATIV Smart PC and using the keyboard dock.

Thanks in advance for any help.

  • Where did you get those character codes? They are just uppercase letters, for example try pressing H in the first example and A in the second and see what happens. – PeterJ Jul 12 '14 at 01:25
  • @PeterJ, It's a perk of `getch`. `ReadConsoleInput` would be a more suitable alternative, though. – chris Jul 12 '14 at 01:28
  • @chris, where could I find a good example of that? – SplatFace Development Jul 12 '14 at 01:32
  • How about [this one](http://stackoverflow.com/questions/24274310/why-does-switch-always-run-default-with-break-included/24274588#24274588)? – chris Jul 12 '14 at 01:32
  • answer is potentially in this [questions top answers](http://stackoverflow.com/questions/10463201/getch-and-arrow-codes) – James Jul 12 '14 at 01:34

7 Answers7

27
#include <conio.h>
#include <iostream>
using namespace std;

#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77

int main()
{
    int c = 0;
    while(1)
    {
        c = 0;

        switch((c=getch())) {
        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 << "Left" << endl;  // key left
            break;
        case KEY_RIGHT:
            cout << endl << "Right" << endl;  // key right
            break;
        default:
            cout << endl << "null" << endl;  // not arrow
            break;
        }

    }

    return 0;
}

output like this:

Up

Down

Right

Left

Up

Left

Right

Right

Up

detected arrow key press!

temarsden
  • 332
  • 5
  • 16
arbboter
  • 350
  • 2
  • 4
  • Thanks so much! I tested your exact code and it worked perfectly (minus one missing curly bracket) and it gave me a working outcome! Now I'll just put it into my code and see if it will continue to work – SplatFace Development Jul 12 '14 at 01:53
  • 1
    Visual Studio 2013 tells me to use _getch() as getch() is deprecated. "Warning C4996: 'getch': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _getch." – aj.toulan Nov 11 '15 at 17:12
  • What about different locales? Will this also work for a keyboard with Chinese layout? – normanius Oct 27 '16 at 15:49
  • 1
    arbboter's answer sets you on the right track but fails to take into account the scan code for the arrow keys actually returns two values. You can view my answer or any of these three answers for more information: https://stackoverflow.com/a/10473315/130614, https://stackoverflow.com/a/2877857/130614, https://stackoverflow.com/a/16510089/130614 – Erik Anderson Feb 07 '19 at 19:58
  • dont use conio.h its non standard and very old header file and not supported in modern compilers/IDE. – Haseeb Mir Feb 07 '20 at 20:58
15

The previous answer by arbboter is close but neglects the fact the arrow keys (and other special keys) return a scan code of two characters. The first is either (0) or (224) indicating the key is an extended one; the second contains the scan code value.

Without accounting for this, the ASCII values for "H", "K", "M", and "P" are misinterpreted as "Up", "Down", "Left", and "Right".

Here's a modified version of arbboter's code to demonstrate reading the extended value when one of the arrow keys is pressed:

#include <conio.h>
#include <iostream>
using namespace std;

#define KEY_UP    72
#define KEY_LEFT  75
#define KEY_RIGHT 77
#define KEY_DOWN  80

int main()
{
    int c, ex;

    while(1)
    {
        c = getch();

        if (c && c != 224)
        {
            cout << endl << "Not arrow: " << (char) c << endl;
        }
        else
        {
            switch(ex = getch())
            {
                case KEY_UP     /* H */:
                    cout << endl << "Up" << endl;//key up
                    break;
                case KEY_DOWN   /* K */:
                    cout << endl << "Down" << endl;   // key down
                    break;
                case KEY_LEFT   /* M */:
                    cout << endl << "Left" << endl;  // key left
                    break;
                case KEY_RIGHT: /* P */
                    cout << endl << "Right" << endl;  // key right
                    break;
                default:
                    cout << endl << (char) ex << endl;  // not arrow
                    break;
            }
        }
    }

    return 0;
}
Erik Anderson
  • 4,915
  • 3
  • 31
  • 30
11
// Example for inputting a single keystroke in C++ on Linux
// by Adam Pierce <adam@doctort.org> on http://www.doctort.org/adam/nerd-notes/reading-single-keystroke-on-linux.html
// This code is freeware. You are free to copy and modify it any way you like.
// Modify by me Putra Kusaeri


#include <iostream>
#include <termios.h>
#define STDIN_FILENO 0
using namespace std;
int 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,d,e;
    cin >> c;
    cin >> d;
    cin >> e;
    cout << "\nYour character was ";
// Using 3 char type, Cause up down right left consist with 3 character
    if ((c==27)&&(d==91)) {
        if (e==65) { cout << "UP";}
        if (e==66) { cout << "DOWN";}
        if (e==67) { cout << "RIGHT";}
        if (e==68) { cout << "LEFT";}
    }
    return 0;
}

reference

Tom Solid
  • 2,226
  • 1
  • 13
  • 32
Putra Kusaeri
  • 111
  • 1
  • 2
  • 4
    When giving an answer it is preferable to give [some explanation as to WHY your answer](http://stackoverflow.com/help/how-to-answer) is the one. – Stephen Rauch Feb 20 '17 at 01:00
  • 1
    There is a typo in the if statement it should be: `if ((c==27)&&(d==91)) {` I.e. it should be a comparison **==**, not an assignment **=** (I know it's an old answer. But for anyone stumbling over this. Watch out to correct this before using) – cbandera Aug 18 '22 at 21:03
5

Here is an alternate way to do it without getch() using events (well commented and i tried to make it as simple as i could)

#include <iostream>
#include <Windows.h>

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

    HANDLE rhnd = GetStdHandle(STD_INPUT_HANDLE);  // handle to read console

    DWORD Events = 0;     // Event count
    DWORD EventsRead = 0; // Events read from console

    bool Running = true;

    //programs main loop
    while(Running) {

        // gets the systems current "event" count
        GetNumberOfConsoleInputEvents(rhnd, &Events);

        if(Events != 0){ // if something happened we will handle the events we want

            // create event buffer the size of how many Events
            INPUT_RECORD eventBuffer[Events];

            // fills the event buffer with the events and saves count in EventsRead
            ReadConsoleInput(rhnd, eventBuffer, Events, &EventsRead);

            // loop through the event buffer using the saved count
            for(DWORD i = 0; i < EventsRead; ++i){

                // check if event[i] is a key event && if so is a press not a release
                if(eventBuffer[i].EventType == KEY_EVENT && eventBuffer[i].Event.KeyEvent.bKeyDown){

                    // check if the key press was an arrow key
                    switch(eventBuffer[i].Event.KeyEvent.wVirtualKeyCode){
                        case VK_LEFT:
                        case VK_RIGHT:
                        case VK_UP:
                        case VK_DOWN:   // if any arrow key was pressed break here
                            std::cout<< "arrow key pressed.\n";
                            break;

                        case VK_ESCAPE: // if escape key was pressed end program loop
                            std::cout<< "escape key pressed.\n";
                            Running = false;
                            break;

                        default:        // no handled cases where pressed 
                            std::cout<< "key not handled pressed.\n";
                            break;
                    }
                }

            } // end EventsRead loop

        }

    } // end program loop

    return 0;
}

(Thanks to a commenter I now know this code is not standard, though it will work if you compile with g++, more info in the comments)

James
  • 1,009
  • 10
  • 11
  • 1
    This code will fail on `INPUT_RECORD eventBuffer[Events];` because `Events` is non-const. But you can read events one by one. – vladon May 30 '15 at 07:27
  • I didn't know `Events` had to be `const`. I just compiled it (with `g++`) and it _appears_ to run like I intended... By all means if this is broken code i'll try to fix it or (most probably) just remove the answer but before i do i'd like to know how exactly this code is supposed to fail so i can try to see it for myself. – James May 30 '15 at 16:44
  • dynamic arrays is extension of g++, not standard c++ – vladon May 30 '15 at 20:09
  • Ah I see, thanks for the information, I think i'll just make an edit. – James May 31 '15 at 02:28
4

Some of the answers given here are not considering the fact that on pressing an arrow key, 2 characters are received. Additionally, it is to be noted that input character should be unsigned char. This is because to determine if an arrow key was pressed, we use ASCII value 224, which can only be stored in an 8-bit character (unsigned char) and not the 7-bit signed char.

You can use below code snippet. 2 types of inputs are processed here. ch1 is the 1st character that user enters. This is the input that user is feeding. But in case of arrow keys, a sequence of 2 characters are received ch1 and ch2. ch1 identifies that some arrow key was pressed, ch2 determines the specific arrow key pressed.

const int KEY_ARROW_CHAR1 = 224;
const int KEY_ARROW_UP = 72;
const int KEY_ARROW_DOWN = 80;
const int KEY_ARROW_LEFT = 75;
const int KEY_ARROW_RIGHT = 77;

unsigned char ch1 = _getch();
if (ch1 == KEY_ARROW_CHAR1)
{
    // Some Arrow key was pressed, determine which?
    unsigned char ch2 = _getch();
    switch (ch2) 
    {
    case KEY_ARROW_UP:
        // code for arrow up
        cout << "KEY_ARROW_UP" << endl;
        break;
    case KEY_ARROW_DOWN:
        // code for arrow down
        cout << "KEY_ARROW_DOWN" << endl;
        break;
    case KEY_ARROW_LEFT:
        // code for arrow right
        cout << "KEY_ARROW_LEFT" << endl;
        break;
    case KEY_ARROW_RIGHT:
        // code for arrow left
        cout << "KEY_ARROW_RIGHT" << endl;
        break;
    }
}
else
{
    switch (ch1)
    {
        // Process other key presses if required.
    }
}
Saket Sharad
  • 392
  • 2
  • 11
2

Check http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx and http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx

#include<windows.h>
#include <stdio.h>

int main()
{
    HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
    DWORD NumInputs = 0;
    DWORD InputsRead = 0;
    bool running = true;

    INPUT_RECORD irInput;

    GetNumberOfConsoleInputEvents(hInput, &NumInputs);

    ReadConsoleInput(hInput, &irInput, 1, &InputsRead);

    switch(irInput.Event.KeyEvent.wVirtualKeyCode)
    {
        case VK_ESCAPE:
        puts("Escape");
        break;

        case VK_LEFT:
        puts("Left");
        break;

        case VK_UP:
        puts("Up");
        break;

        case VK_RIGHT:
        puts("Right");
        break;

        case VK_DOWN:
        puts("Down");
        break;
    } 

}
user93353
  • 13,733
  • 8
  • 60
  • 122
  • this solution is giving me the same problem, I took the code and put it into a new project file, and it went right to `Process returned to 0`. What is stopping it from going right to `Return 0;` in this example? – SplatFace Development Jul 12 '14 at 01:44
1
#include <iostream>
#include <conio.h>

const int KB_UP = 72;
const int KB_DOWN = 80;
const int KB_RIGHT = 77;
const int KB_LEFT = 75;
const int ESC = 27;

int main() {
    
    while (true) {
        int ch = _getch();
        if (ch == 224) {
            ch = _getch();
            switch (ch) {
            case KB_UP: 
                std::cout << "up\n";   
                break;
            case KB_DOWN:
                std::cout << "down\n";
                break;
            case KB_RIGHT:
                std::cout << "right\n";
                break;
            case KB_LEFT:
                std::cout << "left\n";
                break;
            default: std::cout << "unknown\n";
            }
        }
        else if (ch == ESC)
        {
            std::cout << "Escape pressed, going out!\n";
            break;
        }
    }
}

This is very similar to some example above except that I used _getchar() instead of getchar() because Visual Studio compiler gives me error for doing the opposite.

I also put it in a loop till you press Escape bottom.

Kesto2
  • 70
  • 1
  • 13