Windows C++ GetKeyState 大写锁定检测器做相反的事情
Windows C++ GetKeyState caps lock detector does opposite
我编写了一个简单的程序来侦听大写锁定键,并显示一个消息框,说明大写锁定当前是打开还是关闭。
所以:用户按下大写锁定,程序确定大写锁定现在处于什么状态(打开或关闭)并显示一个消息框。
实际发生的是,当大写锁定打开 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
returns 在 处理当前按键并更新键盘状态之前的状态。例如,如果 CAPS LOCK 关闭并且您按下 CAPS LOCK 键,将调用挂钩并且 GetKeyState
报告当前状态为关闭,然后处理按键并打开 CAPS LOCK。
这在 LowLevelKeyboardProc callback function 中有间接暗示:
Note: When this callback function is called in response to a change in the state of a key, the callback function is called before the asynchronous state of the key is updated. Consequently, the asynchronous state of the key cannot be determined by calling GetAsyncKeyState from within the callback function.
由于 GetKeyState
反映的线程状态先于 GetAsyncKeyState
报告的物理状态,因此间接暗示对 GetKeyState
的调用会 return 上一个状态。
我编写了一个简单的程序来侦听大写锁定键,并显示一个消息框,说明大写锁定当前是打开还是关闭。 所以:用户按下大写锁定,程序确定大写锁定现在处于什么状态(打开或关闭)并显示一个消息框。 实际发生的是,当大写锁定打开 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
returns 在 处理当前按键并更新键盘状态之前的状态。例如,如果 CAPS LOCK 关闭并且您按下 CAPS LOCK 键,将调用挂钩并且 GetKeyState
报告当前状态为关闭,然后处理按键并打开 CAPS LOCK。
这在 LowLevelKeyboardProc callback function 中有间接暗示:
Note: When this callback function is called in response to a change in the state of a key, the callback function is called before the asynchronous state of the key is updated. Consequently, the asynchronous state of the key cannot be determined by calling GetAsyncKeyState from within the callback function.
由于 GetKeyState
反映的线程状态先于 GetAsyncKeyState
报告的物理状态,因此间接暗示对 GetKeyState
的调用会 return 上一个状态。