GetKeyboardState一键延迟
我正在使用ToUnicodeEx
函数,它需要键盘状态作为输入参数。所以,我用GetKeyboardState
函数来做到这一点。但我注意到,当我输入组合键如SHIFT + A有一个字符延迟。这里是例子。GetKeyboardState一键延迟
AAA(控股SHIFT现在)AAAAAAAA(释放SHIFT)AAAA级
当我在调试这个我注意到GetKeyboardState
是造成这种延迟。我该如何处理或防止这种延迟?
这是我的整个键盘钩子程序。
void proc(KBDLLHOOKSTRUCT kbdStruct) {
fdebug = fopen("debug.txt", "a");
foutput= fopen("output.txt", "a");
WCHAR pwszBuff[9];
WCHAR key[9];
char str[8];
BOOL isDead = FALSE;
BYTE lpKeyState[256];
HWND currentHwnd = GetForegroundWindow();
LPDWORD currentProcessID = 0;
DWORD currentWindowThreadID = GetWindowThreadProcessId(currentHwnd, currentProcessID);
DWORD thisProgramThreadId = GetCurrentThreadId();
hkl = GetKeyboardLayout(thisProgramThreadId);
if (AttachThreadInput(thisProgramThreadId, currentWindowThreadID, TRUE))
{
GetKeyboardState(lpKeyState);
AttachThreadInput(thisProgramThreadId, currentWindowThreadID, FALSE);
}
else
{
GetKeyboardState(lpKeyState);
}
int ret = ToUnicodeEx(kbdStruct.vkCode, kbdStruct.scanCode, lpKeyState, pwszBuff, 8, 0, hkl);
fprintf(fdebug, "vkCode: %d\n", (int)kbdStruct.vkCode);
fprintf(fdebug, "ret: %d\n", (int)ret);
fprintf(fdebug, "lastIsDead: %d\n", (int)lastIsDead);
fprintf(fdebug, "lastIsMod: %d\n", (int)lastIsMod);
fprintf(fdebug, "lastVKCode: %d\n", (int)lastVKCode);
if (ret == -1) {
isDead = TRUE;
ClearKeyboardBuffer(kbdStruct.vkCode, kbdStruct.scanCode, hkl);
}
else if (ret == 0) {
}
else {
memcpy(&key, &pwszBuff, sizeof(pwszBuff));
WideCharToMultiByte(CP_UTF8, 0, key, -1, str, sizeof(str), NULL, NULL);
fprintf(fdebug, "str: %s\n", str);
}
if (lastVKCode != 0 && lastIsDead == TRUE) {
ToUnicodeEx(lastVKCode, lastScanCode, lastKeyState, pwszBuff, 4, 0, hkl);
memcpy(&key, &pwszBuff, sizeof(pwszBuff));
WideCharToMultiByte(CP_UTF8, 0, key, -1, str, sizeof(str), NULL, NULL);
fprintf(fdebug, "str: %s\n", str);
lastVKCode = 0;
}
fprintf(fdebug, "%s", "---------------------------------------------------\n");
fprintf(foutput, "LSHIFT: %d\n", (int)lpKeyState[160]);
fprintf(foutput, "RSHIFT: %d\n", (int)lpKeyState[161]);
fprintf(foutput, "%s", "---------------------------------------------------\n\n");
lastVKCode = kbdStruct.vkCode;
lastScanCode = kbdStruct.scanCode;
lastIsDead = isDead;
fclose(fdebug);
fclose(foutput);
}
这里是更新版本hookcallback
感谢Ton Plooij。但是,我仍然有同样的问题。
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = CallNextHookEx(_hook, nCode, wParam, lParam);
if (nCode >= 0)
{
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
{
hookStruct = *((KBDLLHOOKSTRUCT*)lParam);
proc(hookStruct);
}
}
return ret;
}
AttachThreadInput(thisProgramThreadId, currentWindowThreadID, FALSE);
这不符合你希望的。有时。当您调用GetKeyboardState()时,获得适当的值是一种勇敢和必要的努力。花了我一段时间才找到失败模式,这根本不明显,我也无法让代码以同样的方式失败。当GUI进程处于前台时,它可以正常工作,例如使用记事本或VS进行尝试。
但是不是当它是一个控制台模式的过程。
解释说有点复杂,它实际上是GetWindowThreadProcessId(),它返回误导性信息。它试图保持幻想,认为它是拥有控制台窗口的控制台进程。它并不是,它实际上是拥有它的相关conhost.exe进程。它是旧版本Windows上的csrss.exe,在Windows 7中添加了conhost.exe来解决UIPI(aka UAC)造成的拖放问题。
但没有任何体面的方式来发现拥有该窗口的特定conhost.exe进程,更不用说线程ID了。 this Q+A的主题。相当怀疑它会帮助你。
只有体面的建议是众所周知的不愉快的建议:如果您需要可靠地翻译按键,那么您需要使用WH_KEYBOARD钩子而不是WH_KEYBOARD_LL。所以GetKeyboardState()总是准确的,钩子回调在进程中运行。
我用一个简单的GUI过程试过这段代码,当它不在前台时它仍然不工作。 说实话,我不明白GetWindowThreadProcessId函数有什么问题。这是一个全局钩子为什么返回值影响线程ID?最后我不想让我的程序DLL依赖,所以我不能使用WH_KEYBOARD。感谢这个伟大的答案。 –
LowLevelKeyboardProc在其wParam中接收WM_KEYUP和WM_KEYDOWN消息。你可以简单地跟踪自己按下的修饰键,在这种情况下,检测到向下和向上移动。将关键状态信息存储在一个静态变量中,并使用它来测试在处理其他键而不是使用GetKeyState时是否按下了shift。
我试过这一个,但我认为ToUnicodeEx函数requries 255关键状态为lpKeyState参数。所以只有移位或者按键对我来说是不够的。 https://msdn.microsoft.com/en-us/library/windows/desktop/ms646322(v=vs.85).aspx –
确定,然后使用GetKeyboardState _after_处理您的代码并在下一次使用返回的信息呼叫? –
我修改了我的hookcallback并添加了问题,但仍然有同样的问题。现在我先调用下一个钩子,然后处理代码,但同样的事情。我说错了吗? –
您可以尝试GetAsyncKeyState()。 这个功能在我的键盘钩子模块中工作完美。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx
看来,这个功能可以捕捉硬件中断,当你按下键。
而你的GetKeyboardState与Windows注册表有关。 它似乎有事情做与初级讲座:
“HKEY_USERS \ DEFAULT \ ControlPanel控制面板\键盘”,修改“KeyboardDelay”的值改为0(默认为1) 变“KeyboardSpeed”值48(dafault 31)。
“HKEY_USERS \ DEFAULT是一个UAC保护区域,但我在HKCU中找到了相同的密钥并根据您的说法改变了值,并且它正在工作。我可以在程序加载这些值,并以编程方式更改它。接受这个答案:) –
我不知道Windows有什么问题,但它工作时,我只是修改了值,现在它不工作。我检查了注册表值仍然是0和48. –
这很奇怪,我无法解释造成这种现象的原因。 –
据汉斯帕桑特的回答我搜索我怎样才能从GetWindowThreadProcessId()
正确的值和,而不是让每一次hWnd
和windowThreadID
在钩子回调,我只是程序启动后获取这些值到全局变量成功和使用变量钩回调。
这似乎没有回答这个问题。也许你打算接受汉斯的回答。 –
@DavidHeffernan,汉斯的回答解释了你需要做些什么才能使它起作用,但表明它可能是不可能的。这个答案解释说,至少在OP的特定情况下是可能的,他是如何做到的。绝对是一个答案的尝试,如果不是十分清楚的话。 –
键盘状态在低级键盘挂钩返回后更新。我不知道在低级键盘钩子中查询同步键盘状态的方法。 – IInspectable
有什么方法可以解决这个问题吗?我尝试了GetAsyncKetSatate函数,但它仍然需要钩子返回来更新缓冲键状态。 –