【问题标题】:Arrow Key Press detected at ANY POINT在任意点检测到箭头键按下
【发布时间】:2019-10-25 15:34:24
【问题描述】:

我对按键检测如何与 c++ 一起工作进行了一些搜索,并且我有一个按键检测程序可以检查 向下右箭头键,它可以工作美好的。但是我有另一个非常简单的输入程序,我想知道是否能够检测到用户在其他地方输入时按下了箭头键,即在something1 变量中例子。

这就是我的意思:

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

using namespace std;

#define KEY_RIGHT 77
#define KEY_DOWN 80

string something1, something2, something3;

bool loggedIn = false;
int value = 0;

void type() {
cout << "Type something: ";
cin >> something1;

cout << "Type something again: ";
cin >> something2;

cout << "Type something one more time: ";
cin >> something3;
}

int main()
{
type();

while (loggedIn == false)
{
    value = 0;

    switch ((value = _getch())) {
        break;
    case KEY_DOWN:
        cout << "You pressed the Down Arrow Key" << endl;
        break;
    case KEY_RIGHT:
        cout << "You pressed the Right Arrow Key" << endl;
        break;
    }

}
}

type() 函数要求用户输入 3 个字符串,因此在所有 3 个字符串提示都通过之前,我们不会点击 while 循环。但是有没有办法以某种方式将这两个代码块合并在一起,这样当用户输入变量something1 并点击向下箭头时,他们会在@ 987654325@案例?

我不确定这种事情是否可能,但我认为值得一试。

【问题讨论】:

  • cin &gt;&gt; stringvar 在输入行尾之前不会返回,因此无法在中间换行以使用箭头键。您可以使用窗口输入来做到这一点,但这远远超出了简单答案的范围。
  • 我已经对 c++ 中的按键检测如何工作进行了一些搜索 -- C++ 语言对按键检测一无所知。这是一个操作系统特定的项目。
  • 你需要一个键盘挂钩。查看SetWindowsHookEx()RegisterRawInputDevices() 以在它们到达cin(或任何其他应用程序)之前从操作系统接收击键事件。

标签: c++ visual-studio winapi


【解决方案1】:

正如@Remy Lebeau 所说,您可以使用SetWindowsHookEx() 来检测箭头键。

这里是示例:

#define _WIN32_WINNT 0x0400
#pragma comment( lib, "user32.lib" )

#include <Windows.h>
#include <conio.h>
#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

HHOOK hKeyboardHook;
string something1;
string something2;
string something3;

__declspec(dllexport) LRESULT CALLBACK KeyboardEvent(int nCode, WPARAM wParam, LPARAM lParam)
{
    DWORD SHIFT_key = 0;
    DWORD CTRL_key = 0;
    DWORD ALT_key = 0;


    if ((nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)))
    {
        KBDLLHOOKSTRUCT hooked_key = *((KBDLLHOOKSTRUCT*)lParam);
        DWORD dwMsg = 1;
        dwMsg += hooked_key.scanCode << 16;
        dwMsg += hooked_key.flags << 24;
        int key = hooked_key.vkCode;
        if (key == 40)
        {
            cout << "You pressed the Down Arrow Key" << endl;
        }   

    }
    return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}

void MessageLoop()
{
    MSG message;
    while (GetMessage(&message, NULL, 0, 0))
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
}

DWORD WINAPI my_HotKey(LPVOID lpParm)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    if (!hInstance) hInstance = LoadLibrary((LPCSTR)lpParm);
    if (!hInstance) return 1;

    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardEvent, hInstance, NULL);
    MessageLoop();
    UnhookWindowsHookEx(hKeyboardHook);
    return 0;
}

int main(int argc, char** argv)
{
    HANDLE hThread;
    DWORD dwThread; 
    HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mode = 0;

    GetConsoleMode(out, &mode);
    SetConsoleMode(out, mode &~ENABLE_LINE_INPUT);

    hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)my_HotKey, (LPVOID)argv[0], NULL, &dwThread);

    std::cout << "Type something: " << endl;
    cin >> something1 ;
    std::cout << "Type something again: " << endl;
    cin >> something2;
    std::cout << "Type something one more time: " << endl;
    cin >> something3;

    /* uncomment to hide console window */
 //ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false);
    //Used for test:
    std::cout<< "----" << something1;
    std::cout << "-------" << something2;
    std::cout << "----------" << something3;
    if (hThread) return WaitForSingleObject(hThread, INFINITE);
    else return 1;

}

调试:

如果你不知道如何使用钩子,那么请参考官方文档。

链接:Using Hooks

您需要创建另一个线程来放置MessageLoop,因为MessageLoopcin 输入流都有阻塞机制..

注意:由于控制台本身的缓存机制,对于方向键的一些效果,比如输入字符,按向上箭头会清除字符。请自行尝试。

【讨论】:

    猜你喜欢
    • 2011-08-01
    • 2016-11-11
    • 2015-05-07
    • 2014-09-03
    • 2022-01-12
    相关资源
    最近更新 更多