你怎么告诉LSHIFT在WM_KEYDOWN事件中与RSHIFT分开?

时间:2013-04-12 08:34:06

标签: 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。

4 个答案:

答案 0 :(得分:14)

要区分Shift,Ctrl或Alt键的左右版本,必须使用随虚拟键消息传递的lParam中的MapVirtualKey()函数或“扩展键”位。以下函数将为您执行该转换 - 只需从消息中传入虚拟键代码和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代码执行操作,就好像系统消息首先将它们提供给您一样。

答案 1 :(得分:8)

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

大卫的答案是解决问题的好方法。但实际上你可以从消息中得到它,那些扫描代码由Windows logo requirements一成不变。在lParam中可用,左移键具有扫描码42,右移键为54.不幸的是,在它们的窗口标题中没有#define,这使得它很难看。

答案 2 :(得分:6)

通过VK_LSHIFTVK_RSHIFT致电GetKeyState

答案 3 :(得分:1)

“根据MSDN”:

  
      
  • VK_LSHIFT
  •   
  • VK_RSHIFT
  •   
  • VK_LCONTROL
  •   
  • VK_RCONTROL
  •   
  • VK_LMENU
  •   
  • VK_RMENU   
  •   
     

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