如何区分 WM_KEYDOWN 事件中的 LSHIFT 和 RSHIFT?

问题描述 投票:0回答:4

根据 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。

c winapi
4个回答
19
投票

要区分 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 代码,就好像系统消息刚刚将它们提供给您一样。


9
投票

你的问题背后有古老的历史。最初的 IBM PC 键盘没有正确的 Alt 和 Ctrl 键。它们后来被添加到扩展键盘布局上,键盘控制器将它们与 0xe0 前缀一起发送到扫描码,以将它们区分为扩展键。但原始键盘布局始终有两个 Shift 键,因此它们有自己的非扩展扫描码。这就是为什么你的代码不起作用。

大卫的回答是解决您问题的好方法。但您实际上可以从消息中获取它,这些扫描代码是由 Windows 徽标要求 决定的。在lParam中可用,左Shift键的扫描码是42,右Shift键是54。不幸的是,它们的Windows标题中没有#define,这使得它很难看。


6
投票

致电

GetKeyState
经过
VK_LSHIFT
VK_RSHIFT


1
投票

“根据 MSDN”:

  • VK_LSHIFT
  • VK_RSHIFT
  • VK_LCONTROL
  • VK_RCONTROL
  • VK_LMENU
  • VK_R菜单

应用程序只能通过 GetKeyboardState、SetKeyboardState、GetAsyncKeyState、GetKeyState 和 MapVirtualKey 函数使用这些左右区分常量。

© www.soinside.com 2019 - 2024. All rights reserved.