C ++检测用户何时按下箭头键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24708700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:48:11  来源:igfitidea点击:

C++ Detect when user presses arrow key

c++windows-8console-applicationarrow-keys

提问by SplatFace Development

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:

我在检测 C++ 控制台应用程序中的箭头键按下时遇到问题。我已经尝试了我在这里和其他教程网站上找到的所有东西,但是每当我按下箭头时,它们都会给我同样的东西:

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.

我的代码中是否有一些错误让我回到我的主方法,或者它跳过了一些代码?有没有更快的方法来做到这一点?我几乎 100% 确定我的其他代码与这个问题没有任何关系,因为我将代码与程序的任何其他方面隔离开来,并且我一直遇到同样的问题。

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.

再一次,我尝试了我能找到的所有按箭头键的方法,但我一直遇到同样的问题。如果重要的话,我使用的是 Windows 8 三星 ATIV 智能 PC 并使用键盘扩展坞。

Thanks in advance for any help.

在此先感谢您的帮助。

回答by arbboter

#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!

检测到箭头键按下!

回答by James

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)

这是使用事件而不使用getch()的另一种方法(评论得很好,我试图让它尽可能简单)

#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)

(感谢一位评论者,我现在知道这段代码不是标准的,但如果你用 编译它会起作用g++,更多信息在评论中)

回答by Putra Kusaeri

// Example for inputting a single keystroke in C++ on Linux
// by Adam Pierce <[email protected]> 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;
}

回答by Erik Anderson

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.

arbboter 的先前答案很接近,但忽略了箭头键(和其他特殊键)返回两个字符的扫描码的事实。第一个是 (0) 或 (224) 表示密钥是扩展密钥;第二个包含扫描码值。

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

如果不考虑这一点,“H”、“K”、“M”和“P”的 ASCII 值会被误解为“上”、“下”、“左”和“右”。

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

这是 arbboter 代码的修改版本,用于演示在按下其中一个箭头键时读取扩展值:

#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;
}

回答by user93353

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

检查http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspxhttp://msdn.microsoft.com/en-us/library/windows/桌面/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;
    } 

}

回答by Saket Sharad

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.

这里给出的一些答案没有考虑到按下箭头键时会收到 2 个字符的事实。另外,需要注意的是输入字符应该是unsigned char。这是因为要确定是否按下了箭头键,我们使用 ASCII 值 224,它只能存储在 8 位字符(无符号字符)中,而不能存储在 7 位有符号字符中。

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.

您可以使用以下代码片段。这里处理 2 种类型的输入。ch1 是用户输入的第一个字符。这是用户正在提供的输入。但是在箭头键的情况下,接收到 ch1 和 ch2 的 2 个字符序列。ch1 标识按下了某个箭头键,ch2 确定按下了特定的箭头键。

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.
    }
}