c - 在 WM_KEYDOWN 事件中如何区分 LSHIFT 和 RSHIFT?

标签 c winapi

根据 MSDN wparam 应该保存关键代码。问题是,当按下 shift 时,代码是 16(VK_SHIFT),但我需要区分 VK_LSHIFT 和 VK_RSHIFT。

对于 VK_CONTROL,似乎有一个解决方法:

if(wParam == VK_CONTROL) {
    if ( lParam&EXTENDED_KEYMASK )
        wParam = VK_RCONTROL;
    else
        wParam = VK_LCONTROL;
}

但是,这对 VK_SHIFT 不起作用:

if(wparam == VK_SHIFT) {
    if ( lParam&EXTENDED_KEYMASK )
        wParam = VK_RSHIFT;
    else
        wParam = VK_LSHIFT;
}

在后一个示例中,它将始终假设为 LSHIFT。

最佳答案

要区分 Shift、Ctrl 或 Alt 键的左右版本,您必须使用 MapVirtualKey() 函数或 lParam 中的“扩展键”位虚拟键的消息。以下函数将为您执行该转换 - 只需从消息中传入虚拟键码和 lParam,您将根据需要取回左/右特定虚拟键码:

WPARAM MapLeftRightKeys( WPARAM vk, LPARAM lParam)
{
    WPARAM new_vk = vk;
    UINT scancode = (lParam & 0x00ff0000) >> 16;
    int extended  = (lParam & 0x01000000) != 0;

    switch (vk) {
    case VK_SHIFT:
        new_vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);
        break;
    case VK_CONTROL:
        new_vk = extended ? VK_RCONTROL : VK_LCONTROL;
        break;
    case VK_MENU:
        new_vk = extended ? VK_RMENU : VK_LMENU;
        break;
    default:
        // not a key we map from generic to left/right specialized
        //  just return it.
        new_vk = vk;
        break;    
    }

    return new_vk;
}

如果传入的虚拟键码不是映射到左/右版本的键码,则原始键码将原样传回。因此,您可以在需要时通过函数运行 WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP 消息参数区分左右变体。

通过使用 MapVirtualKey(),您无需了解有关左移和右移扫描码为 0x2a 和 0x36 的知识 - API 会处理这些细节。如果它们碰巧发生了不同(不会真的发生),Windows 将负责处理它,而不是你。

因此,在您的 WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP 处理程序中,您只需添加一行看起来像的代码:

wparam = MapLeftRightKeys(wparam, lparam);

您的其余代码可以对左/右特定 VK 代码执行操作,就好像系统消息首先将它们提供给您一样。

关于c - 在 WM_KEYDOWN 事件中如何区分 LSHIFT 和 RSHIFT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15966642/

相关文章:

c++ - 如何使用 WaitForMultipleObjects 来平衡竞争工作?

c++ - 使用点积计算两个 vector 之间的角度

c - `something'的多重定义

c - 这个数字是否有超过 D 位小数?

c - Valgrind 结果干净但分配多于释放

windows - Win32 应用程序的自动更新解决方案?

c - 从左到右、从上到下翻转图像

c - 用于查找数字阶乘的递归函数

c++ - 为什么不能访问自 Windows 95 以来另一个进程的地址空间?

c++ - 在内联汇编中调用函数时如何保留堆栈?