【问题标题】:Windows C++ GetKeyState caps lock detector does oppositeWindows C++ GetKeyState 大写锁定检测器的作用相反
【发布时间】:2021-06-05 05:18:49
【问题描述】:

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

我已经阅读了函数的文档,但仍然不理解这种不需要的(相反的)行为,并且想知道如何(以及是否)可以解决这个问题。

这是我的代码:


#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;
}

【问题讨论】:

  • GetKeyState 反映上次从队列中检索输入消息时的键盘状态。 GetAsyncKeyState 反映了调用函数时的键盘状态。你的钩子在消息发布到消息队列之前被调用,所以从那里调用GetKeyState总是落后于真实状态。

标签: c++ winapi keyboard hook keylogger


【解决方案1】:

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

这是在LowLevelKeyboardProc callback function中间接暗示的:

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

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

【讨论】:

  • +1 感谢您的回答。您知道如何更改我的代码以使其按预期工作吗?我得出结论,我不能在钩子回调中使用 GetKeyState。
  • @user2190492 代码正在报告大写锁定键被按下的时间,以及切换的当前状态。它不能也不能预测大写锁定切换的 future 状态,因为这尚未生效(事实上,如果大写锁定已被禁用或以其他方式定制)。您可以稍后通过发布消息而不是立即弹出消息框来检查状态,或者捕获WM_KEYUP,或者运行计时器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 2017-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多