如何区分左键和右键(CTRL和ALT)?

zpqajqem  于 2023-10-15  发布在  其他
关注(0)|答案(4)|浏览(97)

我开始使用Win32的原始输入功能来检测键盘上的所有键。到目前为止,一切都工作得很好!我可以区分最上面一行的数字和右边键盘上的数字。我甚至可以在左右换档键之间进行检测。但是,control和alt键不会返回唯一的扫描代码。控制键返回29,alt键返回56。
检查这些键的键状态的常用方法是GetAsyncKeyState。我已经使用VK_LCONTROLVK_RCONTROL测试了这个函数,它可以工作,但这只能帮助我捕获按键事件。我真的希望能够捕捉关键的事件以及。很明显,API以某种方式知道按下了哪个键;我怎样才能得到这些信息?
我目前正在从RAWKEYBOARD结构的MakeCode字段中提取扫描码。这给了我关于除了CTRL和ALT之外的每个键(及其左/右对齐)的信息。我该如何捕获键向上的事件(并知道它是左还是右)?是否可以只使用RAWKEYBOARD结构?还是我得编造一些变通办法?

6jygbczu

6jygbczu1#

如果你想获得足够低的级别来检测键起事件,你应该处理WM_KEYDOWN和WM_KEYUP事件:

  • http://msdn.microsoft.com/en-us/library/ms646267%28v=vs.85%29.aspx#_win32_Keystroke_Messages

按下某个键将导致WM_KEYDOWN或WM_SYSKEYDOWN消息被放置到附加到具有键盘焦点的窗口的线程消息队列中。释放键会导致WM_KEYUP或WM_SYSKEYUP消息被放入队列中。
键上和键下消息通常成对出现,但如果用户按住某个键足够长的时间以启动键盘的自动重复功能,系统将连续生成多个WM_KEYDOWN或WM_SYSKEYDOWN消息。然后,当用户释放密钥时,它生成一个WM_KEYUP或WM_SYSKEYUP消息。
要区分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;
}

如果传入的虚拟键码不是Map到左/右版本的键码,则原始键码将不作更改地传回。因此,只要需要区分左右变量,就可以通过函数运行WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP消息参数。

lnlaulya

lnlaulya2#

GetAsyncKeyState的文档说:
.如果最高有效位被设置,则键按下.
这也意味着如果MSB被清除,则密钥为up。

iq3niunx

iq3niunx3#

lParam中检查extended key flag是否为“right”键也可以这样做。
如果为真-它是正确的Ctrl或Alt,基于wParam == VK_CONTROL或VK_MENU
否则它的左Ctrl或Alt >

(HIWORD(lParam) & KF_EXTENDED) == KF_EXTENDED

扫码领取也可以这样做>

BYTE scan_code = LOBYTE(HIWORD(lParam));

使用

MapVirtualKey(scan_code, MAPVK_VSC_TO_VK_EX);

用于基于wParam == VK_R来检测VK_L或VK_R

r7knjye2

r7knjye24#

我为官方MS文档添加了一个示例代码:

case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
{
    WORD vkCode = LOWORD(wParam);
    WORD keyFlags = HIWORD(lParam);

    WORD scanCode = LOBYTE(keyFlags);
    BOOL isExtendedKey = (keyFlags & KF_EXTENDED) == KF_EXTENDED;
    
    if (isExtendedKey)
        scanCode = MAKEWORD(scanCode, 0xE0);

    // if we want to distinguish these keys:
    switch (vkCode)
    {
    case VK_SHIFT:   // converts to VK_LSHIFT or VK_RSHIFT
    case VK_CONTROL: // converts to VK_LCONTROL or VK_RCONTROL
    case VK_MENU:    // converts to VK_LMENU or VK_RMENU
        vkCode = LOWORD(MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK_EX));
        break;
    }

    // ...
}
break;

相关问题