【问题标题】:Polling the Keyboard in C and Win32 api在 C 和 Win32 api 中轮询键盘
【发布时间】:2017-05-11 20:15:25
【问题描述】:

这段代码没有做它应该做的事情。

当我按一次光标键时,菜单会跳转不止一次。

我该如何解决这个问题?

.

相关源代码

#include <windows.h>
#include <conio.h>

BOOL IsKeyPressed(KEY_CODE key)
{
    if (GetAsyncKeyState(key) < 0)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
} 

int select_menu(char**menus, int x, int y, int items_count)
{
    int selection = 0;
    show_menu(x, y, menus, items_count);    
    gotoxy(x, y);

    while (1)
    {
        if (IsKeyPressed(vk_Down))
        {
            int xx = wherex();
            int yy = wherey() + 1;

            if ((yy - x + 1) > items_count)
            {
                gotoxy(x, y);
            }
            else
            {
                gotoxy(xx, yy);
            }
        }
        if (IsKeyPressed(vk_Up))
        {
            int xx = wherex();
            int yy = wherey() - 1;

            if (yy < y)
            {
                gotoxy(x, y + items_count);
            }
            else
            {
                gotoxy(xx, yy);
            }
        }
        if (IsKeyPressed(vk_Return))
        {
            int xx = wherex();
            int yy = wherey();

            selection = yy - y + 1;
        }
    }

    return selection;
}

参考:

https://sourceforge.net/projects/conio/

【问题讨论】:

  • 您应该执行一次操作,然后等待按键被释放。或者添加一些超时。或者有一个检测transitions的功能。
  • GetAsyncKeyState() 返回 2 位信息。按键按下时设置高位,即您现在正在测试的那个。当您再次调用 IsKeyPressed() 时,它仍然处于关闭状态,除非您的手指快速点亮。自从您上次调用它以来,当键更改状态时设置低位,您希望知道该状态以避免键重复。
  • 你为什么要开始投票?

标签: c winapi


【解决方案1】:

您遇到了软件反弹。

来自微软页面。 GetAsyncKeyState

确定在调用函数时某个键是向上还是向下,以及在上一次调用 GetAsyncKeyState 之后是否按下了该键。

函数返回提供了两条信息:
1. 按键的瞬时状态。
2. 键的历史状态(自上次调用以来)。
您应该了解并使用两者来做出决定。

为了防止弹跳,看一下返回值的说明:

如果函数成功,则返回值指定自上次调用 GetAsyncKeyState 以来是否按下了键,以及是否 键当前是向上或向下。 如果最高有效位是 设置,键向下,如果设置了最低有效位, 在上一次调用 GetAsyncKeyState 之后按下该键。 但是,您不应该依赖最后一种行为;更多 信息,请参阅备注。 [强调我的]

例如,您可以专门针对每个条件编写函数:

BOOL IsKeyPressed(KEY_CODE key)
{
    if(0x80000000 & GetAsyncKeyState(key))//most significant bit is high
    return TRUE;                          //key IS down
    else return FALSE;
} 

BOOL WasKeyDown(KEY_CODE key)
{
    if(0x00000001 & GetAsyncKeyState(key))//least significant bit is high
    return TRUE;                          //key WAS down
    else return FALSE;
} 

如果在某个时候可能需要查看历史记录当前状态,同时您正在监视多个按键,此示例说明了如何执行此操作。特别是,这段代码定义了一组可以用来杀死应用程序的键:

void KillThisApp(void)
{
    if ((0x80000000 & GetAsyncKeyState(VK_CONTROL)) || 
        (0x00000001 & GetAsyncKeyState(VK_CONTROL))) 
    {
        if ((0x80000000 & GetAsyncKeyState('k')) || 
            (0x00000001 & GetAsyncKeyState('k')) ||
            (0x80000000 & GetAsyncKeyState('K')) ||
            (0x00000001 & GetAsyncKeyState('K')) ) 
        {
            if((0x80000000 & GetAsyncKeyState(VK_SHIFT)) || 
               (0x00000001 & GetAsyncKeyState(VK_SHIFT)))
            {    
                gRunning = FALSE;
            }
        }
    }
}

此版本不关心键 是否关闭或 已关闭,但可以很容易地进行编辑以要求所有键 在cal 在每次调用期间只查看高位。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 2013-12-11
    • 2017-09-08
    相关资源
    最近更新 更多