【问题标题】:Catching keypresses C++捕捉按键 C++
【发布时间】:2012-09-21 10:00:36
【问题描述】:

我正在使用一个简单的循环来捕获用户按键;

while (1)
{
    for(i = 8; i <= 190; i++)
    {
       if (GetAsyncKeyState(i) == -32767){
         //Do stuff
       }
    }
}

当用户按下某个键时,它会“做事”,但很明显,因为它无限循环,而且我是 C++ 新手,它占用了 100% 的 CPU,这不适合简单的输入。

我做错了什么?我已经尝试过 Sleep() 函数(如果我把它放在“for 循环”中,它会错过按键,如果我把它放在“while 循环”中,它根本不会降低 CPU,afaik)

我怎样才能让它捕捉到相同的按键,但使用的 CPU 几乎没有那么多;我错过了一个技巧吗?我敢肯定大多数程序都能捕捉按键,但您不会看到所有的按键都 100% 使用!

非常感谢。

【问题讨论】:

  • 你不能使用线性算法来做到这一点......你需要在你的程序中添加一个监听器。谷歌那个。
  • 使用钩子。 GetMessage 将处于空闲状态,直到发生关键事件。对于更脏的解决方案,请在循环中添加 Sleep(10); 或其他内容。
  • 过去我使用了RegisterHotkey 和UnregisterHotkey 的组合。但是,我只想在窗口处于焦点时检测按键,所以我在窗口失去焦点时调用UnregisterHotkey,并在窗口重新聚焦时将其注册回来。也许这些功能会对你有所帮助。如果您在窗口失焦时不取消注册热键,可能会弄乱其他应用程序热键。

标签: c++ for-loop while-loop keypress


【解决方案1】:

将你的无限循环放在一个工作线程中,并让它在每次迭代时休眠一段合理的时间间隔。 C++11 让这变得非常简单:

#include <thread>
#include <chrono>

std::chrono::milliseconds THREAD_WAIT = 50;

int keypress = -1;

void GetKeyPress()
{
   while (1)
   {
       for(i = 8; i <= 190; i++)
       {
          int k = GetAsyncKeyState(i);
          if (/*whatever condition needs to be satisfied*/)
              keypress = k;
       }
       if (keypress != -1) break; //Use this only if you have td.join() below
       std::this_thread::sleep_for(THREAD_WAIT);
   }
}

int main(void)
{
   ...

   std::thread td( GetKeyPress );
   td.join(); //If you want to block until the user presses a key, otherwise remove.

   //If no join(), do the rest of your program, checking in on keypress when need be

   return 0;
}

【讨论】:

    【解决方案2】:

    请查看以下链接,该链接通过示例代码解释了正确使用 GetAsyncKeyState()。 http://www.mpgh.net/forum/31-c-c-programming/120656-proper-use-getasynckeystate.html

    希望此链接可以帮助您解决问题

    已编辑: GetAsyncKeyState() 函数不适合您尝试执行的操作。

    它所做的只是检查键盘上某个键的实际、当前纳秒位置。这样做几乎总是不正确的。

    相反,使用正确的输入函数读取控制台输入。请在下面找到示例代码。

    #include <stdio.h>
    #include <windows.h>
    
    int main()
    {
        DWORD        mode;          /* Preserved console mode */
        INPUT_RECORD event;         /* Input event */
        BOOL         done = FALSE;  /* Program termination flag */
        unsigned int counter = 0;   /* The number of times 'Esc' is pressed */
    
        /* Don't use binary for text files, OK?  ;-) */
        FILE* myfile = fopen( "example.txt", "w" );
    
        /* Get the console input handle */
        HANDLE hstdin = GetStdHandle( STD_INPUT_HANDLE );
    
        /* Preserve the original console mode */
        GetConsoleMode( hstdin, &mode );
    
        /* Set to no line-buffering, no echo, no special-key-processing */
        SetConsoleMode( hstdin, 0 );
    
        /* Give the user instructions */
        printf(
            "Press Escape as many times as you like.\n"
            "Press anything else to quit.\n\n"
            );
    
        while (!done)
        {
            if (WaitForSingleObject( hstdin, 0 ) == WAIT_OBJECT_0)  /* if kbhit */
            {
                DWORD count;  /* ignored */
    
                /* Get the input event */
                ReadConsoleInput( hstdin, &event, 1, &count );
    
                /* Only respond to key release events */
                if ((event.EventType == KEY_EVENT)
                &&  !event.Event.KeyEvent.bKeyDown)
                    switch (event.Event.KeyEvent.wVirtualKeyCode)
                    {
                        case VK_ESCAPE:
                            counter++;
                            fprintf( myfile, "Escape: %d\n", counter );
                            printf( "Button pressed!\n" );
                            break;
                        default:
                            done = TRUE;
                    }
            }
        }
    
        /* All done! */
        printf( "You pressed the Escape key %d times\n", counter );
        fclose( myfile );
        SetConsoleMode( hstdin, mode );
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      你可以使用

      while (!kbhit());
      

      这可能会有所帮助。

      【讨论】:

      • 我的编译器无法识别 kbhit (DevC++) 该命令在哪个编译器中工作?
      • 现在可以工作了,谢谢,虽然 CPU 仍然很高,但我会尝试像其他 cmets 建议的钩子或侦听器。谢谢。
      猜你喜欢
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-31
      • 2013-01-09
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      相关资源
      最近更新 更多