C++ Windows C++;GetKeyState caps锁检测器执行相反的操作

C++ Windows C++;GetKeyState caps锁检测器执行相反的操作,c++,winapi,keyboard,hook,keylogger,C++,Winapi,Keyboard,Hook,Keylogger,我已经编写了一个简单的程序来监听caps lock键,并显示一个消息框,告诉您caps lock当前是打开还是关闭。 所以:用户按下caps lock,程序确定caps lock现在处于什么状态(打开或关闭),并显示一个消息框。 实际发生的情况是,当caps lock打开时,程序会显示消息框,说明它已关闭,反之亦然 我已经阅读了函数的文档,但仍然不理解这种不需要的(相反的)行为,我想知道如何(以及是否)修复它 这是我的密码: #include <Windows.h> // Res

我已经编写了一个简单的程序来监听caps lock键,并显示一个消息框,告诉您caps lock当前是打开还是关闭。 所以:用户按下caps lock,程序确定caps lock现在处于什么状态(打开或关闭),并显示一个消息框。 实际发生的情况是,当caps lock打开时,程序会显示消息框,说明它已关闭,反之亦然

我已经阅读了函数的文档,但仍然不理解这种不需要的(相反的)行为,我想知道如何(以及是否)修复它

这是我的密码:


#include <Windows.h>

// Research/credits/references
// https://www.unknowncheats.me/forum/c-and-c-/83707-setwindowshookex-example.html
// http://www.rohitab.com/discuss/topic/38617-get-the-state-of-capslock/

HHOOK _hook;

// This struct contains the data received by the hook callback. As you see in the callback function
// it contains the thing you will need: vkCode = virtual key code.
KBDLLHOOKSTRUCT kbdStruct;

// This is the callback function. Consider it the event that is raised when, in this case, 
// a key is pressed.
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        // the action is valid: HC_ACTION.
        if (wParam == WM_KEYDOWN)
        {
            // lParam is the pointer to the struct containing the data needed, so cast and assign it to kdbStruct.
            kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
            // a key (non-system) is pressed.
            if (kbdStruct.vkCode == VK_CAPITAL)
            {
                if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0)
                    MessageBox(NULL, "Caps Lock ON!", "Caps Lock", MB_ICONINFORMATION);
                else
                    MessageBox(NULL, "Caps Lock OFF!", "Caps Lock", MB_ICONINFORMATION);
            }
        }
    }

    // call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

void SetHook()
{
    // Set the hook and set it to use the callback function above
    // WH_KEYBOARD_LL means it will set a low level keyboard hook. More information about it at MSDN.
    // The last 2 parameters are NULL, 0 because the callback function is in the same thread and window as the
    // function that sets and releases the hook. If you create a hack you will not need the callback function 
    // in another place than your own code file anyway. Read more about it at MSDN.
    if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0)))
    {
        MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
    }
}

void ReleaseHook()
{
    UnhookWindowsHookEx(_hook);
}

int main()
{
    // Set the hook
    SetHook();

    // Don't mind this, it is a meaningless loop to keep a console application running.
    // I used this to test the keyboard hook functionality.
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {

    }
    
    return 0;
}


#包括
//研究/学分/参考
// https://www.unknowncheats.me/forum/c-and-c-/83707-setwindowshookex-example.html
// http://www.rohitab.com/discuss/topic/38617-get-the-state-of-capslock/
HHOOK_hook;
//此结构包含钩子回调接收的数据。正如您在回调函数中看到的
//它包含您需要的东西:vkCode=虚拟密钥代码。
KBDLLHOOKSTRUCT kbdStruct;
//这是回调函数。在这种情况下,将其视为引发的事件。
//按下一个键。
LRESULT uu stdcall HookCallback(int-nCode、WPARAM-WPARAM、LPARAM-LPARAM)
{
如果(nCode>=0)
{
//该操作有效:HC_操作。
if(wParam==WM_KEYDOWN)
{
//lParam是指向包含所需数据的结构的指针,因此强制转换并将其分配给kdbStruct。
kbdStruct=*((KBDLLHOOKSTRUCT*)lParam);
//按下一个键(非系统)。
if(kbdStruct.vkCode==VK_大写)
{
如果((GetKeyState(VK_CAPITAL)&0x0001)!=0)
MessageBox(空,“Caps Lock ON!”,“Caps Lock”,MB_图标信息);
其他的
MessageBox(空,“Caps Lock OFF!”,“Caps Lock”,MB_图标信息);
}
}
}
//呼叫钩链中的下一个钩。这是nessecary,否则您的钩链将断裂,钩停止
返回CallNextHookEx(_hook,nCode,wParam,lParam);
}
void SetHook()
{
//设置钩子并将其设置为使用上面的回调函数
//WH_KEYBOARD_LL意味着它将设置一个低级键盘挂钩。有关详细信息,请访问MSDN。
//最后2个参数为NULL,0,因为回调函数与
//设置和释放钩子的函数。如果创建一个hack,则不需要回调函数
//在你自己的代码文件之外的其他地方。请在MSDN上阅读更多关于它的信息。
if(!(_hook=setWindowshookx(WH_KEYBOARD,HookCallback,NULL,0)))
{
MessageBox(NULL,“安装钩子失败!”,“错误”,MB_ICONERROR);
}
}
无效释放挂钩()
{
解开钩(_钩);
}
int main()
{
//上钩
SetHook();
//不要介意,保持控制台应用程序运行是一个毫无意义的循环。
//我用它来测试键盘钩子的功能。
味精;
while(GetMessage(&msg,NULL,0,0))
{
}
返回0;
}

GetKeyState
返回处理当前按键和更新键盘状态之前的状态。例如,如果CAPS LOCK处于关闭状态,并且您按下CAPS LOCK键,则会调用挂钩,并且
GetKeyState
会将当前状态报告为关闭,然后会处理按键并打开CAPS LOCK

这是间接暗示在:

注意:当调用此回调函数以响应密钥状态的更改时,将在更新密钥的异步状态之前调用回调函数。因此,无法通过在回调函数中调用GetAsyncKeyState来确定键的异步状态


由于
GetKeyState
反映的线程状态先于
GetAsyncKeyState
报告的物理线程状态,因此间接暗示调用
GetKeyState
将返回以前的状态。

GetKeyState
反映上次从队列检索输入消息时的键盘状态
GetAsyncKeyState
反映调用函数时的键盘状态。您的钩子在消息发布到消息队列之前被调用,因此从那里调用
GetKeyState
将始终落后于实际状态。+1感谢您的回答。你知道我怎样才能修改我的代码,使它按预期工作吗?我的结论是我不能在钩子回调中使用GetKeyState。@user2190492当按下caps lock键时,代码会报告当前的切换状态。它不会也无法预测caps lock切换的未来状态,因为这尚未生效(事实上,如果caps lock已被禁用或以其他方式自定义,则可能永远不会生效)。您可以稍后通过发布消息而不是立即弹出消息框,或者捕捉
WM_KEYUP
,或者运行计时器来检查状态。