We have a kiosk app where we would like to allow use of the Win H hotkey to bring up Voice Typing, but still filter out other Win ... hotkeys.
The hook is set with SetWindowsHookEx(WH_KEYBOARD_LL, callback, hInstance, 0);
Log from pressing Win H:
// w = bool, GetAsyncKeyState for left and right windows keys
// h = bool, ...for "h" key
// key = KBDLLHOOKSTRUCY* pkh->vkCode, 72 = h, 91 = left Windows key
// flags = KBDLLHOOKSTRUCT* pkh->flags
// pressed Windows, then H, then released
w=0 h=0 key= 91 flags = 1
w=-1 h=0 key= 91 flags = 1
... repeats ....
w=-1 h=0 key= 91 flags = 1
w=-1 h=0 key= 72 flags = 0
w=-1 h=-1 key= 72 flags = 80
w=-1 h=0 key= 91 flags = 81
What I'm finding while trying different permutations of code in the callback is, either I get no keypress, or I get a plain h
(so Voice Typing is not launched), or all other Win ... hotkeys get through not just Win H.
This treats the press as a plain h
, so apparently at least some of the Win key events before the h
events must be allowed past the filter:
if (nCode == HC_ACTION)
{
BOOL bWinKeyDown = (GetAsyncKeyState(VK_LWIN) >> 15) | (GetAsyncKeyState(VK_RWIN) >> 15);
if (pkh->vkCode == 'H')
{
// w=-1 h=0 key= 72 flags = 0
// w=-1 h=-1 key= 72 flags = 80
return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);
}
else if ((pkh->vkCode == VK_LWIN || pkh->vkCode == VK_RWIN))
{
// also just "h" if we allow through the w=-1 h=0 key= 91 flags = 1 events
// if ((bWinKeyDown && (pkh->flags == 1)) )
// return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);
// else
return -1;
}
}
return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);
This lets all Win ... hotkeys through, it seems like the first event acts as a "dead key" that gets applied to any next letter key:
if (nCode == HC_ACTION)
{
BOOL bWinKeyDown = (GetAsyncKeyState(VK_LWIN) >> 15) | (GetAsyncKeyState(VK_RWIN) >> 15);
if (pkh->vkCode == 'H')
{
// w=-1 h=0 key= 72 flags = 0
// w=-1 h=-1 key= 72 flags = 80
return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);
}
else if ((pkh->vkCode == VK_LWIN || pkh->vkCode == VK_RWIN))
{
if ((!bWinKeyDown && (pkh->flags == 1))) // // w=0 h=0 key= 91 flags = 1 - first event in log
return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);
else
return -1;
}
Is there any way to trap all Win ... hotkey except for Win H?
CodePudding user response:
You can just add a test for WM_KEYDOWN
and add test when Win
key is down and H
is pressed down.
Returning non-zero value is not recommended, and the code below ends up eating a message, which is no good. But this is only eating the message for key down state. So everything should be okay once that key is released.
LRESULT CALLBACK kbd_proc(int nCode, WPARAM wp, LPARAM lp)
{
if (nCode == HC_ACTION)
{
KBDLLHOOKSTRUCT* pkh = (KBDLLHOOKSTRUCT*)lp;
BOOL bWinKeyDown = (GetAsyncKeyState(VK_LWIN) >> 15) |
(GetAsyncKeyState(VK_RWIN) >> 15);
if (pkh->vkCode != 'H' && wp == WM_KEYDOWN && bWinKeyDown)
{
OutputDebugString(L"not Win H...\n");
return 1;
}
}
return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);
}
CodePudding user response:
According to my test, win h
produces four messages, Index 1 to 4.
You can trap them at the second message. The following code which traps all Win ...
hotkey except for win h
works for me.
LRESULT CALLBACK Proc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION)
{
KBDLLHOOKSTRUCT* s= (KBDLLHOOKSTRUCT*)lParam;
std::cout << " Index=" << nwinhooksdll << "wParam="<< wParam <<" s->vkCode=" << s->vkCode << " s->scanCode=" << s->scanCode << " s->flags=" << s->flags << " s->dwExtraInfo=" << s->dwExtraInfo << "\n";
if (GetAsyncKeyState(VK_LWIN))
{
if (s->vkCode == 'H')
{
}
else
{
return 1;
}
}
}
return CallNextHookEx(_hook, nCode, wParam, lParam);
}