【问题标题】:How to handle key_down and key_up of char in WndProc?如何在 WndProc 中处理 char 的 key_down 和 key_up?
【发布时间】:2021-05-12 16:14:52
【问题描述】:

我正在尝试处理箭头键和AWSD 字符的向上和向下键消息。

我可以使用WM_KEYUPWM_KEYDOWN处理箭头键的向上和向下行为。

但是当我尝试处理上述字符的上下行为时,它无法正常工作。

我试过WM_KEYUPWM_KEYDOWN来处理字符。但是在我将它们更改为WM_CHARWM_DEADCHAR 之后。但是还是不行。

对于字符我可以处理前几个按键向下和向上消息,然后程序不处理这些。 但是对于方向键,程序可以正常运行。

我是新手,不知道如何处理角色的上下行为。

下面是我试过的最后一个代码(只是WndProc函数)。

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg)
    {
    case WM_CREATE:
        Hmainbmp = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE | SS_BITMAP | WS_THICKFRAME, 1, 23, WINDOW_WIDTH, WINDOW_HEIGHT, hWnd, nullptr, hInst, nullptr);
        start_game();
        break;

    case WM_CHAR:
        PRESSED_KEY = (int)wParam;
        if (PRESSED_KEY == 'A' or PRESSED_KEY == 'a') { players[1]->moves.left = true; }
        else if (PRESSED_KEY == 'D' or PRESSED_KEY == 'd') { players[1]->moves.right = true; }
        else if (PRESSED_KEY == 'W' or PRESSED_KEY == 'w') { players[1]->moves.up = true; }
        else if (PRESSED_KEY == 'S' or PRESSED_KEY == 's') { players[1]->moves.down = true; }
        break;

    case WM_DEADCHAR:
        PRESSED_KEY = (int)wParam;
        if (PRESSED_KEY == 'A' or PRESSED_KEY == 'a') { players[1]->moves.left = false; }
        else if (PRESSED_KEY == 'D' or PRESSED_KEY == 'd') { players[1]->moves.right = false; }
        else if (PRESSED_KEY == 'W' or PRESSED_KEY == 'w') { players[1]->moves.up = false; }
        else if (PRESSED_KEY == 'S' or PRESSED_KEY == 's') { players[1]->moves.down = false; }
        break;

    case WM_KEYDOWN:
        PRESSED_KEY = (int)wParam;
        if      (PRESSED_KEY == VK_LEFT)    { players[0]->moves.left    = true; }
        else if (PRESSED_KEY == VK_RIGHT)   { players[0]->moves.right   = true; }
        else if (PRESSED_KEY == VK_UP)      { players[0]->moves.up      = true; }
        else if (PRESSED_KEY == VK_DOWN)    { players[0]->moves.down    = true; }
        break;
    case WM_KEYUP:
        RELEASED_KEY = (int)wParam;
        if      (RELEASED_KEY == VK_LEFT)   { players[0]->moves.left    = false; }
        else if (RELEASED_KEY == VK_RIGHT)  { players[0]->moves.right   = false; }
        else if (RELEASED_KEY == VK_UP)     { players[0]->moves.up      = false; }
        else if (RELEASED_KEY == VK_DOWN)   { players[0]->moves.down    = false; }
        break;
    
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return(DefWindowProc(hWnd, uMsg, wParam, lParam));
    }

    return(0L);
}

start_game() 是我的主要功能,我在该功能中使用键的向上和向下消息。

我的问题是,如何处理 AD 等字符的按键和按键行为?


在我按下AW 后,程序无法处理这些字符的按键行为以及任何其他字符的按键行为,例如SD。但同时程序可以处理方向键的上下行为。


FULL CODE (Vs2019)

【问题讨论】:

  • 窗口上是否还有另一个窗口,例如可能窃取了焦点的编辑框或按钮?
  • 我在这里本地运行一些东西,基本上使用你的代码,没有任何问题。我确实看到您的部分代码使用players[1] 而另一部分使用players[0] 这是故意的吗?
  • 与其重复一个模糊的“不起作用”,您能描述一下您期望的行为和实际行为吗?
  • @lapestand 不确定您期望WM_DEADCHAR 在那里做什么,但它肯定与WM_KEYUP 无关,就像WM_CHARWM_KEYDOWN 一样。
  • @lapestand 你有WM_KEYDOWN/UP 来处理按下和释放的键,你有WM_CHAR 来处理翻译的字符。但是没有“char up”的概念(或消息)。将一些 printf 或其他日志添加到您的 WndProc,以便更好地了解正在发生的事情。

标签: c++ c winapi wndproc


【解决方案1】:

根据WM_DEADCHAR

WM_DEADCHAR 指定由死键生成的字符代码。一个死人 key 是生成字符的键,例如变音符号 (双点),即与另一个字符组合形成一个 复合字符。

所以WM_DEADCHAR 消息不是您认为对应WM_CHAR 消息的内容。

也可以使用WM_KEYDOWN/WM_KEYUP消息来处理字符键:

case WM_KEYDOWN:
    PRESSED_KEY = (int)wParam;
    if      (PRESSED_KEY == VK_LEFT)    { players[0]->moves.left    = true; }
    else if (PRESSED_KEY == VK_RIGHT)   { players[0]->moves.right   = true; }
    else if (PRESSED_KEY == VK_UP)      { players[0]->moves.up      = true; }
    else if (PRESSED_KEY == VK_DOWN)    { players[0]->moves.down    = true; }
    if (PRESSED_KEY == 'A' or PRESSED_KEY == 'a') { players[1]->moves.left = true; }
    else if (PRESSED_KEY == 'D' or PRESSED_KEY == 'd') { players[1]->moves.right = true; }
    else if (PRESSED_KEY == 'W' or PRESSED_KEY == 'w') { players[1]->moves.up = true; }
    else if (PRESSED_KEY == 'S' or PRESSED_KEY == 's') { players[1]->moves.down = true; }
    break;
case WM_KEYUP:
    RELEASED_KEY = (int)wParam;
    if      (RELEASED_KEY == VK_LEFT)   { players[0]->moves.left    = false; }
    else if (RELEASED_KEY == VK_RIGHT)  { players[0]->moves.right   = false; }
    else if (RELEASED_KEY == VK_UP)     { players[0]->moves.up      = false; }
    else if (RELEASED_KEY == VK_DOWN)   { players[0]->moves.down    = false; }
    if (RELEASED_KEY == 'A' or RELEASED_KEY == 'a') { players[1]->moves.left = false; }
    else if (RELEASED_KEY == 'D' or RELEASED_KEY == 'd') { players[1]->moves.right = false; }
    else if (RELEASED_KEY == 'W' or RELEASED_KEY == 'w') { players[1]->moves.up = false; }
    else if (RELEASED_KEY == 'S' or RELEASED_KEY == 's') { players[1]->moves.down = false; }
    break;

【讨论】:

  • 尝试此代码时,有时即使我释放角色,方向(代码中的player.move)也会卡住。因此,我必须再次按下并释放才能保存它。
  • @lapestand 刚才的代码有错误。我在发布时使用了PRESSED_KEY。我已经修改了代码,你可以参考一下。
  • 一个switch 比一堆ifs 更有意义。但更重要的是,请注意WM_KEY(DOWN|UP) 只处理virtual key codes。字母 A..Z 的虚拟键码在 0x41..0x5A 范围内,这与它们在 ASCII 中的大写字母的数值相同,因此这些消息中的键码永远不会是 'a'/'d'/'w'/'s',只有 A'/'D'/'W'/'S'。另一方面,WM_CHAR 处理文本字符,因此它会看到小写字母,如果这是用户实际键入的内容。
猜你喜欢
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多