Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

561 lines
14 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. IgnoreAltTab.cpp
  5. Abstract:
  6. This DLL installs a low level keyboard hook to eat Alt-Tab, Left Win,
  7. Right Win and Apps combinations.
  8. This is accomplished by creating a seperate thread, installing a WH_KEYBOARD_LL hook
  9. and starting a message loop in that thread.
  10. This shim needs to force DInput to use windows hooks instead of WM_INPUT,
  11. since WM_INPUT messages force all WH_KEYBOARD_LL to be ignored.
  12. Notes:
  13. We intentionally try to stay at the *end* of the hook chain
  14. by hooking as early as we can. If we are at the end of the
  15. hook chain, we allow all previous hookers (DInput especially)
  16. their chance at the key event before we toss it out.
  17. History:
  18. 05/25/2001 robkenny Created
  19. 11/27/2001 mnikkel Added sticky and filter keys to shim.
  20. --*/
  21. #include "precomp.h"
  22. #include "CharVector.h"
  23. IMPLEMENT_SHIM_BEGIN(IgnoreAltTab)
  24. #include "ShimHookMacro.h"
  25. APIHOOK_ENUM_BEGIN
  26. APIHOOK_ENUM_ENTRY(RegisterRawInputDevices)
  27. APIHOOK_ENUM_END
  28. // Forward declarations
  29. LRESULT CALLBACK KeyboardProcLL(int nCode, WPARAM wParam, LPARAM lParam);
  30. class CThreadKeyboardHook;
  31. // Global variables
  32. CThreadKeyboardHook *g_cKeyboardHook = NULL;
  33. BOOL g_bFilterKeyInit = FALSE;
  34. BOOL g_bStickyKeyInit = FALSE;
  35. BOOL g_bCatchKeys = TRUE;
  36. STICKYKEYS g_OldStickyKeyValue;
  37. FILTERKEYS g_OldFilterKeyValue;
  38. class CThreadKeyboardHook
  39. {
  40. protected:
  41. HHOOK hKeyboardHook;
  42. HANDLE hMessageThread;
  43. DWORD dwMessageThreadId;
  44. public:
  45. CThreadKeyboardHook();
  46. void AddHook();
  47. void RemoveHook();
  48. LRESULT HandleKeyLL(int code, WPARAM wParam, LPARAM lParam);
  49. static DWORD WINAPI MessageLoopThread(LPVOID lpParameter);
  50. };
  51. /*++
  52. This routine runs in a seperate thread.
  53. MSDN says: "This hook is called in the context of the thread that installed it.
  54. The call is made by sending a message to the thread that installed
  55. the hook. Therefore, the thread that installed the hook must have a message loop."
  56. --*/
  57. DWORD WINAPI CThreadKeyboardHook::MessageLoopThread(LPVOID lpParameter)
  58. {
  59. CThreadKeyboardHook * pThreadHookList = (CThreadKeyboardHook *)lpParameter;
  60. pThreadHookList->AddHook();
  61. DPFN(eDbgLevelSpew, "Starting message loop");
  62. BOOL bRet;
  63. MSG msg;
  64. while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
  65. {
  66. DPFN(eDbgLevelSpew, "MessageLoopThread: Msg(0x%08x) wParam(0x%08x) lParam(0x%08x)",
  67. msg.message, msg.wParam, msg.lParam);
  68. if (bRet == -1)
  69. {
  70. // handle the error and possibly exit
  71. }
  72. else
  73. {
  74. TranslateMessage(&msg);
  75. DispatchMessage(&msg);
  76. }
  77. }
  78. // We are exiting the thread
  79. pThreadHookList->hMessageThread = 0;
  80. pThreadHookList->dwMessageThreadId = 0;
  81. return 0;
  82. }
  83. CThreadKeyboardHook::CThreadKeyboardHook()
  84. {
  85. hMessageThread = CreateThread(NULL, 0, MessageLoopThread, this, 0, &dwMessageThreadId);
  86. }
  87. void CThreadKeyboardHook::AddHook()
  88. {
  89. // Do not add duplicates to the list
  90. if (!hKeyboardHook)
  91. {
  92. hKeyboardHook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardProcLL, g_hinstDll, 0);
  93. if (hKeyboardHook)
  94. {
  95. DPFN(eDbgLevelSpew, "Adding WH_KEYBOARD_LL hook(0x%08x)", hKeyboardHook);
  96. }
  97. }
  98. }
  99. void CThreadKeyboardHook::RemoveHook()
  100. {
  101. if (hKeyboardHook)
  102. {
  103. UnhookWindowsHookEx(hKeyboardHook);
  104. DPFN(eDbgLevelSpew, "Removing hook(0x%08x)", hKeyboardHook);
  105. hKeyboardHook = NULL;
  106. }
  107. }
  108. LRESULT CThreadKeyboardHook::HandleKeyLL(int code, WPARAM wParam, LPARAM lParam)
  109. {
  110. DWORD dwKey = 0;
  111. BOOL bAltDown = 0;
  112. BOOL bCtlDown = GetKeyState(VK_CONTROL) < 0;
  113. if (lParam)
  114. {
  115. KBDLLHOOKSTRUCT * pllhs = (KBDLLHOOKSTRUCT*)lParam;
  116. dwKey = pllhs->vkCode;
  117. bAltDown = (pllhs->flags & LLKHF_ALTDOWN) != 0;
  118. }
  119. //if (code >= 0) // Despite what MSDN says, we need to muck with the values even if nCode == 0
  120. {
  121. if (bAltDown && dwKey == VK_TAB) // Alt-Tab
  122. {
  123. // Do not process this event
  124. LOGN(eDbgLevelInfo, "Eating Key: Alt-Tab");
  125. return TRUE;
  126. }
  127. else if (bAltDown && dwKey == VK_ESCAPE) // Alt-Escape
  128. {
  129. // Do not process this event
  130. LOGN(eDbgLevelInfo, "Eating Key: Alt-Escape");
  131. return TRUE;
  132. }
  133. else if (bCtlDown && dwKey == VK_ESCAPE) // Ctrl-Escape
  134. {
  135. // Do not process this event
  136. LOGN(eDbgLevelInfo, "Eating Key: Ctrl-Escape");
  137. return TRUE;
  138. }
  139. else if (dwKey == VK_RWIN || dwKey == VK_LWIN) // Windows key
  140. {
  141. // Do not process this event
  142. LOGN(eDbgLevelInfo, "Eating Key: Windows Key");
  143. return TRUE;
  144. }
  145. else if (dwKey == VK_APPS) // Menu key
  146. {
  147. // Do not process this event
  148. LOGN(eDbgLevelInfo, "Eating Key: Apps key");
  149. return TRUE;
  150. }
  151. }
  152. DPFN(eDbgLevelSpew, "LL Key event: code(0x%08x) dwKey(0x%08x) bits(0x%08x) Alt(%d) Ctrl(%d)",
  153. code, dwKey, lParam, bAltDown, bCtlDown);
  154. return CallNextHookEx(hKeyboardHook, code, wParam, lParam);
  155. }
  156. /*++
  157. This function intercepts special codes and eats them so that
  158. the app is not switched out of.
  159. --*/
  160. LRESULT CALLBACK
  161. KeyboardProcLL(
  162. int nCode,
  163. WPARAM wParam,
  164. LPARAM lParam
  165. )
  166. {
  167. if (g_cKeyboardHook)
  168. {
  169. return g_cKeyboardHook->HandleKeyLL(nCode, wParam, lParam);
  170. }
  171. return 1; // this is an error...
  172. }
  173. /*++
  174. Determine if there are any accelerated pixel formats available. This is done
  175. by enumerating the pixel formats and testing for acceleration.
  176. --*/
  177. BOOL
  178. IsGLAccelerated()
  179. {
  180. HMODULE hMod = NULL;
  181. HDC hdc = NULL;
  182. int i;
  183. PIXELFORMATDESCRIPTOR pfd;
  184. _pfn_wglDescribePixelFormat pfnDescribePixelFormat;
  185. int iFormat = -1;
  186. //
  187. // Load original opengl
  188. //
  189. hMod = LoadLibraryA("opengl32");
  190. if (!hMod)
  191. {
  192. LOGN(eDbgLevelError, "Failed to load OpenGL32");
  193. goto Exit;
  194. }
  195. //
  196. // Get wglDescribePixelFormat so we can enumerate pixel formats
  197. //
  198. pfnDescribePixelFormat = (_pfn_wglDescribePixelFormat) GetProcAddress(
  199. hMod, "wglDescribePixelFormat");
  200. if (!pfnDescribePixelFormat)
  201. {
  202. LOGN(eDbgLevelError, "API wglDescribePixelFormat not found in OpenGL32");
  203. goto Exit;
  204. }
  205. //
  206. // Get a Display DC for enumeration
  207. //
  208. hdc = GetDC(NULL);
  209. if (!hdc)
  210. {
  211. LOGN(eDbgLevelError, "GetDC(NULL) Failed");
  212. goto Exit;
  213. }
  214. //
  215. // Run the list of pixel formats looking for any that are non-generic,
  216. // i.e. accelerated by an ICD
  217. //
  218. i = 1;
  219. iFormat = 0;
  220. while ((*pfnDescribePixelFormat)(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd))
  221. {
  222. if ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) &&
  223. (pfd.dwFlags & PFD_SUPPORT_OPENGL) &&
  224. (!(pfd.dwFlags & PFD_GENERIC_FORMAT)))
  225. {
  226. iFormat = i;
  227. break;
  228. }
  229. i++;
  230. }
  231. Exit:
  232. if (hdc)
  233. {
  234. ReleaseDC(NULL, hdc);
  235. }
  236. if (hMod)
  237. {
  238. FreeLibrary(hMod);
  239. }
  240. return (iFormat > 0);
  241. }
  242. /*++
  243. WM_INPUT messages force WH_KEYBOARD_LL hooks to be ignored, therefore
  244. we need to fail this call.
  245. --*/
  246. BOOL
  247. APIHOOK(RegisterRawInputDevices)(
  248. PCRAWINPUTDEVICE /*pRawInputDevices*/,
  249. UINT /*uiNumDevices*/,
  250. UINT /*cbSize*/
  251. )
  252. {
  253. LOGN(eDbgLevelError, "RegisterRawInputDevices: failing API with bogus ERROR_INVALID_PARAMETER");
  254. SetLastError(ERROR_INVALID_PARAMETER);
  255. return FALSE;
  256. }
  257. /*++
  258. DisableStickyKeys saves the current value for LPSTICKYKEYS and then disables the option.
  259. --*/
  260. VOID
  261. DisableStickyKeys()
  262. {
  263. if (!g_bStickyKeyInit )
  264. {
  265. STICKYKEYS NewStickyKeyValue;
  266. // Initialize the current and new Stickykey structures
  267. g_OldStickyKeyValue.cbSize = sizeof(STICKYKEYS);
  268. NewStickyKeyValue.cbSize = sizeof(STICKYKEYS);
  269. NewStickyKeyValue.dwFlags = 0;
  270. // retrieve the current Stickykey structure
  271. if (SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &g_OldStickyKeyValue, 0))
  272. {
  273. // if retrieval of current Stickykey structure was successful then change the settings
  274. // with the new structure.
  275. if (SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &NewStickyKeyValue, SPIF_SENDCHANGE))
  276. {
  277. g_bStickyKeyInit = TRUE;
  278. LOGN( eDbgLevelInfo, "[DisableStickyKeys] Stickykeys disabled.");
  279. }
  280. else
  281. {
  282. LOGN( eDbgLevelError, "[DisableStickyKeys] Unable to change Stickykey settings!");
  283. }
  284. }
  285. else
  286. {
  287. LOGN( eDbgLevelError, "[DisableStickyKeys] Unable to retrieve current Stickykey settings!");
  288. }
  289. }
  290. }
  291. /*++
  292. EnableStickyKeys uses the save value for STICKYKEYS and resets the option to the original setting.
  293. --*/
  294. VOID
  295. EnableStickyKeys()
  296. {
  297. if (g_bStickyKeyInit )
  298. {
  299. g_bStickyKeyInit = FALSE;
  300. // Restore Stickykey original state
  301. if (SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &g_OldStickyKeyValue, SPIF_SENDCHANGE))
  302. {
  303. LOGN( eDbgLevelInfo, "[DisableStickyKeys] Sticky key state restored");
  304. }
  305. else
  306. {
  307. LOGN( eDbgLevelError, "[DisableStickyKeys] Unable to restore Sticky key settings!");
  308. }
  309. }
  310. }
  311. /*++
  312. DisableFilterKeys saves the current value for LPFILTERKEYS and then disables the option.
  313. --*/
  314. VOID
  315. DisableFilterKeys()
  316. {
  317. if (!g_bFilterKeyInit)
  318. {
  319. FILTERKEYS NewFilterKeyValue;
  320. // Initialize the current and new Filterkey structures
  321. g_OldFilterKeyValue.cbSize = sizeof(FILTERKEYS);
  322. NewFilterKeyValue.cbSize = sizeof(FILTERKEYS);
  323. NewFilterKeyValue.dwFlags = 0;
  324. // retrieve the current stickykey structure
  325. if (SystemParametersInfo(SPI_GETFILTERKEYS, sizeof(FILTERKEYS), &g_OldFilterKeyValue, 0))
  326. {
  327. // if retrieval of current Filterkey structure was successful then change the settings
  328. // with the new structure.
  329. if (SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &NewFilterKeyValue, SPIF_SENDCHANGE))
  330. {
  331. g_bFilterKeyInit = TRUE;
  332. LOGN( eDbgLevelInfo, "[DisableFilterKeys] Filterkeys disabled.");
  333. }
  334. else
  335. {
  336. LOGN( eDbgLevelError, "[DisableFilterKeys] Unable to change Filterkey settings!");
  337. }
  338. }
  339. else
  340. {
  341. LOGN( eDbgLevelError, "[DisableFilterKeys] Unable to retrieve current Filterkey settings!");
  342. }
  343. }
  344. }
  345. /*++
  346. EnableFilterKeys uses the save value for FILTERKEYS and resets the option to the original setting.
  347. --*/
  348. VOID
  349. EnableFilterKeys()
  350. {
  351. if (g_bFilterKeyInit)
  352. {
  353. g_bFilterKeyInit = FALSE;
  354. // Restore Filterkey original state
  355. if (SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &g_OldFilterKeyValue, SPIF_SENDCHANGE))
  356. {
  357. LOGN( eDbgLevelInfo, "[DisableStickyKeys] Filterkey state restored");
  358. }
  359. else
  360. {
  361. LOGN( eDbgLevelError, "[DisableStickyKeys] Unable to restore Filterkey settings!");
  362. }
  363. }
  364. }
  365. /*++
  366. Handle Shim notifications.
  367. --*/
  368. BOOL
  369. NOTIFY_FUNCTION(
  370. DWORD fdwReason
  371. )
  372. {
  373. if (fdwReason == DLL_PROCESS_ATTACH)
  374. {
  375. CSTRING_TRY
  376. {
  377. CString csCl(COMMAND_LINE);
  378. if (csCl.CompareNoCase(L"NOKEYS") == 0)
  379. {
  380. g_bCatchKeys = FALSE;
  381. }
  382. }
  383. CSTRING_CATCH
  384. {
  385. // no action
  386. }
  387. }
  388. else if (fdwReason == SHIM_STATIC_DLLS_INITIALIZED)
  389. {
  390. if (g_bCatchKeys)
  391. {
  392. DisableStickyKeys();
  393. DisableFilterKeys();
  394. }
  395. #if DBG
  396. static bool bTest = FALSE;
  397. if (bTest)
  398. {
  399. delete g_cKeyboardHook;
  400. g_cKeyboardHook = NULL;
  401. return TRUE;
  402. }
  403. #endif
  404. CSTRING_TRY
  405. {
  406. CString csCl(COMMAND_LINE);
  407. if (csCl.CompareNoCase(L"OPENGL") == 0)
  408. {
  409. // This must be called *after* the dll's have been initialized
  410. if (IsGLAccelerated())
  411. {
  412. return TRUE;
  413. }
  414. }
  415. g_cKeyboardHook = new CThreadKeyboardHook;
  416. if (!g_cKeyboardHook)
  417. {
  418. return FALSE;
  419. }
  420. }
  421. CSTRING_CATCH
  422. {
  423. // Do nothing
  424. }
  425. }
  426. else if (fdwReason == DLL_PROCESS_DETACH)
  427. {
  428. if (g_bCatchKeys)
  429. {
  430. EnableFilterKeys();
  431. EnableStickyKeys();
  432. }
  433. }
  434. return TRUE;
  435. }
  436. HOOK_BEGIN
  437. CALL_NOTIFY_FUNCTION
  438. APIHOOK_ENTRY(USER32.DLL, RegisterRawInputDevices)
  439. HOOK_END
  440. IMPLEMENT_SHIM_END