| 155 | |
| 156 | |
| 157 | LRESULT CALLBACK LowLevelKeybdProc(int aCode, WPARAM wParam, LPARAM lParam) |
| 158 | { |
| 159 | if (aCode != HC_ACTION) // MSDN docs specify that both LL keybd & mouse hook should return in this case. |
| 160 | return CallNextHookEx(g_KeybdHook, aCode, wParam, lParam); |
| 161 | |
| 162 | KBDLLHOOKSTRUCT &event = *(PKBDLLHOOKSTRUCT)lParam; // For convenience, maintainability, and possibly performance. |
| 163 | |
| 164 | // Change the event to be physical if that is indicated in its dwExtraInfo attribute. |
| 165 | // This is done for cases when the hook is installed multiple times and one instance of |
| 166 | // it wants to inform the others that this event should be considered physical for the |
| 167 | // purpose of updating modifier and key states: |
| 168 | if (event.dwExtraInfo == KEY_PHYS_IGNORE) |
| 169 | event.flags &= ~LLKHF_INJECTED; |
| 170 | else if (event.dwExtraInfo == KEY_BLOCK_THIS) |
| 171 | return TRUE; |
| 172 | |
| 173 | // Make all keybd events physical to try to fool the system into accepting CTRL-ALT-DELETE. |
| 174 | // This didn't work, which implies that Ctrl-Alt-Delete is trapped at a lower level than |
| 175 | // this hook (folks have said that it's trapped in the keyboard driver itself): |
| 176 | //event.flags &= ~LLKHF_INJECTED; |
| 177 | |
| 178 | // Note: Some scan codes are shared by more than one key (e.g. Numpad7 and NumpadHome). This is why |
| 179 | // the keyboard hook must be able to handle hotkeys by either their virtual key or their scan code. |
| 180 | // i.e. if sc were always used in preference to vk, we wouldn't be able to distinguish between such keys. |
| 181 | |
| 182 | bool key_up = (wParam == WM_KEYUP || wParam == WM_SYSKEYUP); |
| 183 | vk_type vk = (vk_type)event.vkCode; |
| 184 | sc_type sc = (sc_type)event.scanCode; |
| 185 | if (vk && !sc) // Might happen if another app calls keybd_event with a zero scan code. |
| 186 | sc = vk_to_sc(vk); |
| 187 | // MapVirtualKey() does *not* include 0xE0 in HIBYTE if key is extended. In case it ever |
| 188 | // does in the future (or if event.scanCode ever does), force sc to be an 8-bit value |
| 189 | // so that it's guaranteed consistent and to ensure it won't exceed SC_MAX (which might cause |
| 190 | // array indexes to be out-of-bounds). The 9th bit is later set to 1 if the key is extended: |
| 191 | sc &= 0xFF; |
| 192 | // Change sc to be extended if indicated. But avoid doing so for VK_RSHIFT, which is |
| 193 | // apparently considered extended by the API when it shouldn't be. Update: Well, it looks like |
| 194 | // VK_RSHIFT really is an extended key, at least on WinXP (and probably be extension on the other |
| 195 | // NT based OSes as well). What little info I could find on the 'net about this is contradictory, |
| 196 | // but it's clear that some things just don't work right if the non-extended scan code is sent. For |
| 197 | // example, the shift key will appear to get stuck down in the foreground app if the non-extended |
| 198 | // scan code is sent with VK_RSHIFT key-up event: |
| 199 | if ((event.flags & LLKHF_EXTENDED)) // && vk != VK_RSHIFT) |
| 200 | sc |= 0x100; |
| 201 | |
| 202 | // The below must be done prior to any returns that indirectly call UpdateKeybdState() to update |
| 203 | // modifier state. |
| 204 | // Update: It seems best to do the below unconditionally, even if the OS is Win2k or WinXP, |
| 205 | // since it seems like this translation will add value even in those cases: |
| 206 | // To help ensure consistency with Windows XP and 2k, for which this hook has been primarily |
| 207 | // designed and tested, translate neutral modifier keys into their left/right specific VKs, |
| 208 | // since beardboy's testing shows that NT4 receives the neutral keys like Win9x does: |
| 209 | switch (vk) |
| 210 | { |
| 211 | case VK_SHIFT: vk = (sc == SC_RSHIFT) ? VK_RSHIFT : VK_LSHIFT; break; |
| 212 | case VK_CONTROL: vk = (sc == SC_RCONTROL) ? VK_RCONTROL : VK_LCONTROL; break; |
| 213 | case VK_MENU: vk = (sc == SC_RALT) ? VK_RMENU : VK_LMENU; break; |
| 214 | } |
nothing calls this directly
no test coverage detected