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.

4831 lines
197 KiB

  1. /****************************************************************************/
  2. // ihint.cpp
  3. //
  4. // IH internal code
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. extern "C" {
  10. #define TRC_GROUP TRC_GROUP_CORE
  11. #define TRC_FILE "aihint"
  12. #include <atrcapi.h>
  13. #include <adcgfsm.h>
  14. }
  15. #include "objs.h"
  16. #include "ih.h"
  17. #include "autil.h"
  18. #include "sl.h"
  19. #include "aco.h"
  20. #include "wui.h"
  21. #ifdef OS_WINCE
  22. #include "cd.h"
  23. #include "op.h"
  24. #include <ceconfig.h>
  25. #endif
  26. #include "cc.h"
  27. #ifndef VK_KANA
  28. #define VK_KANA 0x15
  29. #endif
  30. #ifndef VK_HANGUL
  31. #define VK_HANGUL 0x15
  32. #endif
  33. #ifndef VK_HANJA
  34. #define VK_HANJA 0x19
  35. #endif
  36. #define VK_l 'l'
  37. #define VK_L 'L'
  38. //
  39. // Special VK value to ignore
  40. //
  41. #define VK_IGNORE_VALUE 0xFF
  42. /****************************************************************************/
  43. /* Dummy hotkey table. This is used until the UI passes the real hotkey */
  44. /* table to the core. An entry of -1 is an invalid hotkey, hence will not */
  45. /* match any key sequence. */
  46. /****************************************************************************/
  47. DCHOTKEY ihDummyHotkey = {(DCUINT)-1, (DCUINT)-1, (DCUINT)-1,
  48. (DCUINT)-1, (DCUINT)-1, (DCUINT)-1, (DCUINT)-1};
  49. /****************************************************************************/
  50. /* Input Handler FSM */
  51. /* */
  52. /* State | 0:Reset 1:Init 2:Active 3:Suspend 4: PendAct */
  53. /* Input | */
  54. /* ===================+================================================== */
  55. /* IH_Init | 1 a / / / / */
  56. /* IH_Enable | / 2 g / / / */
  57. /* IH_Disable | / - 1 c 1 c 1 c */
  58. /* IH_Term | / 0 h 0 h 0 h 0 h */
  59. /* Focus lost (+) | - (*) - 3 i - - */
  60. /* Focus regained | / - - b 2 b - */
  61. /* Input/Timer Event | / - - d - e - j */
  62. /* IH_BufferAvailable | / - - f - 2 g */
  63. /* IH_FSM_NOBUFFER | / / 4 / / */
  64. /* */
  65. /* / invalid input/state combination */
  66. /* - no state change */
  67. /* (*) can occur during shutdown on Win16 (as window is not destroyed) */
  68. /* (+) this event may not be passed through to the FSM (see WM_KILLFOCUS) */
  69. /* */
  70. /* Note that when allowBackgroundInput is enabled the we don't go into */
  71. /* suspend..this would cause a bug because when focus is regained the FSM */
  72. /* did not fire an ACT_B to resync even though it needed to...So the FSM was*/
  73. /* changed to make that fix (if you are in ACTIVE and receive focus gain an */
  74. /* ACT_B is sent */
  75. /****************************************************************************/
  76. const FSM_ENTRY ihFSM[IH_FSM_INPUTS][IH_FSM_STATES] =
  77. {
  78. { {IH_STATE_INIT, ACT_A },
  79. {STATE_INVALID, ACT_NO},
  80. {STATE_INVALID, ACT_NO},
  81. {STATE_INVALID, ACT_NO},
  82. {STATE_INVALID, ACT_NO} },
  83. { {STATE_INVALID, ACT_NO},
  84. {IH_STATE_ACTIVE, ACT_G },
  85. {STATE_INVALID, ACT_NO},
  86. {STATE_INVALID, ACT_NO},
  87. {STATE_INVALID, ACT_NO} },
  88. { {STATE_INVALID, ACT_NO},
  89. {IH_STATE_INIT, ACT_NO},
  90. {IH_STATE_INIT, ACT_C },
  91. {IH_STATE_INIT, ACT_C },
  92. {IH_STATE_INIT, ACT_C } },
  93. { {STATE_INVALID, ACT_NO},
  94. {IH_STATE_RESET, ACT_H },
  95. {IH_STATE_RESET, ACT_H },
  96. {IH_STATE_RESET, ACT_H },
  97. {IH_STATE_RESET, ACT_H } },
  98. { {IH_STATE_INIT, ACT_NO},
  99. {IH_STATE_INIT, ACT_NO},
  100. {IH_STATE_SUSPENDED, ACT_I },
  101. {IH_STATE_SUSPENDED, ACT_NO},
  102. {IH_STATE_PENDACTIVE,ACT_NO} },
  103. { {STATE_INVALID, ACT_NO},
  104. {IH_STATE_INIT, ACT_NO},
  105. {IH_STATE_ACTIVE, ACT_B},
  106. {IH_STATE_ACTIVE, ACT_B },
  107. {IH_STATE_PENDACTIVE,ACT_NO} },
  108. { {STATE_INVALID, ACT_NO},
  109. {IH_STATE_INIT, ACT_NO},
  110. {IH_STATE_ACTIVE, ACT_D },
  111. {IH_STATE_SUSPENDED, ACT_E },
  112. {IH_STATE_PENDACTIVE,ACT_J } },
  113. { {STATE_INVALID, ACT_NO},
  114. {IH_STATE_INIT, ACT_NO},
  115. {IH_STATE_ACTIVE, ACT_F },
  116. {IH_STATE_SUSPENDED, ACT_NO},
  117. {IH_STATE_ACTIVE, ACT_G } },
  118. { {STATE_INVALID, ACT_NO},
  119. {STATE_INVALID, ACT_NO},
  120. {IH_STATE_PENDACTIVE,ACT_NO},
  121. {STATE_INVALID, ACT_NO},
  122. {STATE_INVALID, ACT_NO} }
  123. };
  124. /****************************************************************************/
  125. /* Debug FSM state and event strings */
  126. /****************************************************************************/
  127. #ifdef DC_DEBUG
  128. static const PDCTCHAR ihFSMStates[IH_FSM_STATES] =
  129. {
  130. _T("IH_STATE_RESET"),
  131. _T("IH_STATE_INIT"),
  132. _T("IH_STATE_ACTIVE"),
  133. _T("IH_STATE_SUSPENDED"),
  134. _T("IH_STATE_PENDACTIVE")
  135. };
  136. static const PDCTCHAR ihFSMInputs[IH_FSM_INPUTS] =
  137. {
  138. _T("IH_FSM_INIT"),
  139. _T("IH_FSM_ENABLE"),
  140. _T("IH_FSM_DISABLE"),
  141. _T("IH_FSM_TERM"),
  142. _T("IH_FSM_FOCUS_LOSE"),
  143. _T("IH_FSM_FOCUS_GAIN"),
  144. _T("IH_FSM_INPUT"),
  145. _T("IH_FSM_BUFFERAVAILABLE")
  146. };
  147. #endif /* DC_DEBUG */
  148. //
  149. // A thread local variable so the keyboard hook can find the IH for this
  150. // thread
  151. //
  152. // Hey, what's the hungarian for thread local storage?
  153. //
  154. DWORD CIH::TlsIndex = 0xFFFFFFFF;
  155. /****************************************************************************/
  156. /* Name: IHFSMProc */
  157. /* */
  158. /* Purpose: Run the IH FSM */
  159. /* */
  160. /* Returns: Process input event TRUE / FALSE */
  161. /* */
  162. /* Params: IN event - FSM input */
  163. /****************************************************************************/
  164. DCBOOL DCINTERNAL CIH::IHFSMProc(DCUINT32 event, ULONG_PTR data)
  165. {
  166. DCBOOL rc = TRUE;
  167. DCUINT8 action;
  168. MSG nextMsg;
  169. DCUINT32 newEvents;
  170. DCSIZE desktopSize;
  171. WNDCLASS tmpWndClass;
  172. DC_BEGIN_FN("IHFSMProc");
  173. /************************************************************************/
  174. /* Run the FSM */
  175. /************************************************************************/
  176. EXECUTE_FSM(ihFSM, event, _IH.fsmState, action, ihFSMInputs, ihFSMStates);
  177. switch (action)
  178. {
  179. case ACT_A:
  180. {
  181. TRC_NRM((TB, _T("Initialization")));
  182. /****************************************************************/
  183. /* Create a dummy hotkey table */
  184. /****************************************************************/
  185. _IH.pHotkey = &ihDummyHotkey;
  186. /****************************************************************/
  187. /* Register the IH window class */
  188. /****************************************************************/
  189. if(!GetClassInfo(_pUi->UI_GetInstanceHandle(), IH_CLASS_NAME, &tmpWndClass))
  190. {
  191. _IH.wndClass.style = CS_HREDRAW | CS_VREDRAW;
  192. _IH.wndClass.lpfnWndProc = IHStaticInputCaptureWndProc;
  193. _IH.wndClass.cbClsExtra = 0;
  194. _IH.wndClass.cbWndExtra = sizeof(void*); //store this pointer
  195. _IH.wndClass.hInstance = _pUi->UI_GetInstanceHandle();
  196. _IH.wndClass.hIcon = NULL;
  197. _IH.wndClass.hCursor = NULL;
  198. _IH.wndClass.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
  199. _IH.wndClass.lpszMenuName = NULL;
  200. _IH.wndClass.lpszClassName = IH_CLASS_NAME;
  201. if (RegisterClass(&_IH.wndClass) == 0)
  202. {
  203. TRC_ALT((TB, _T("Failed to register IH window class")));
  204. _pUi->UI_FatalError(DC_ERR_WINDOWCREATEFAILED);
  205. }
  206. }
  207. /****************************************************************/
  208. /* Create the Input Capture Window. We don't want this window */
  209. /* to try to send WM_PARENTNOTIFY to the UI containder wnd on */
  210. /* create/destroy (since this can cause deadlocks) so we */
  211. /* specify WS_EX_NOPARENTNOTIFY. WM_PARENTNOTIFY doesn't exist */
  212. /* on WinCE so it's not a problem there. */
  213. /****************************************************************/
  214. _IH.inputCaptureWindow =
  215. CreateWindowEx(
  216. #ifndef OS_WINCE
  217. WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT,
  218. #else
  219. 0, /* extended style */
  220. #endif
  221. IH_CLASS_NAME, /* window class name */
  222. _T("Input Capture Window"), /* window caption */
  223. WS_CHILD, /* window style */
  224. 0, /* initial x position */
  225. 0, /* initial y position */
  226. 1, /* initial x size */
  227. 1, /* initial y size */
  228. _pUi->UI_GetUIContainerWindow(),/* parent window */
  229. NULL, /* window menu handle */
  230. _pUi->UI_GetInstanceHandle(), /* program inst handle */
  231. this); /* creation parameters */
  232. _IH.hCurrentCursor = LoadCursor(NULL, IDC_ARROW);
  233. if (_IH.inputCaptureWindow == NULL)
  234. {
  235. TRC_ERR((TB, _T("Failed to create Input Capture Window")));
  236. /************************************************************/
  237. /* Fatal error - cannot continue. */
  238. /************************************************************/
  239. _pUi->UI_FatalError(DC_ERR_WINDOWCREATEFAILED);
  240. }
  241. TRC_DBG((TB, _T("Capture Window handle %p"), _IH.inputCaptureWindow));
  242. /********************************************************************/
  243. /* Disable IME */
  244. /********************************************************************/
  245. _pUi->DisableIME(_IH.inputCaptureWindow);
  246. /****************************************************************/
  247. /* Read the registry to get the configuration information. */
  248. /****************************************************************/
  249. _IH.maxEventCount = _pUi->_UI.maxEventCount;
  250. if (_IH.maxEventCount > IH_INPUTPDU_MAX_EVENTS)
  251. {
  252. /************************************************************/
  253. /* Limit InputPDU size */
  254. /************************************************************/
  255. _IH.maxEventCount = IH_INPUTPDU_MAX_EVENTS;
  256. }
  257. TRC_DBG((TB, _T("InputPDU max events %d"), _IH.maxEventCount));
  258. _IH.eventsAtOnce = _pUi->_UI.eventsAtOnce;
  259. TRC_DBG((TB, _T("%d events at once"), _IH.eventsAtOnce));
  260. #ifdef OS_WINCE
  261. _IH.maxMouseMove = _pUt->UT_ReadRegistryInt(
  262. UTREG_SECTION,
  263. UTREG_IH_MAX_MOUSEMOVE,
  264. UTREG_IH_MAX_MOUSEMOVE_DFLT);
  265. TRC_DBG((TB, _T("Max Mouse Move %u"),_IH.maxMouseMove));
  266. /************************************************************************/
  267. /* If the INK feature is enabled, min send interval must be zero. Don't*/
  268. /* change the registry value so the original value is in place if the */
  269. /* INK feature is disabled. */
  270. /************************************************************************/
  271. if (_IH.maxMouseMove)
  272. {
  273. _IH.minSendInterval = 0;
  274. }
  275. else
  276. {
  277. _IH.minSendInterval = _pUt->UT_ReadRegistryInt(
  278. UTREG_SECTION,
  279. UTREG_IH_MIN_SEND_INTERVAL,
  280. UTREG_IH_MIN_SEND_INTERVAL_DFLT);
  281. TRC_DBG((TB, _T("Min send interval %d ms"), _IH.minSendInterval));
  282. }
  283. #else
  284. _IH.minSendInterval = _pUi->_UI.minSendInterval;
  285. TRC_DBG((TB, _T("Min send interval %d ms"), _IH.minSendInterval));
  286. #endif
  287. _IH.keepAliveInterval = 1000 * _pUi->_UI.keepAliveInterval;
  288. TRC_DBG((TB, _T("Keepalive interval %d ms"), _IH.keepAliveInterval));
  289. //
  290. // Allow background input (Reg only setting)
  291. //
  292. _IH.allowBackgroundInput = _pUt->UT_ReadRegistryInt(
  293. UTREG_SECTION,
  294. UTREG_IH_ALLOWBACKGROUNDINPUT,
  295. _pUi->_UI.allowBackgroundInput);
  296. TRC_DBG((TB, _T("Allow background input %u"),
  297. _IH.allowBackgroundInput));
  298. _IH.lastInputPDUSendTime = _pUt->UT_GetCurrentTimeMS();
  299. _IH.lastFlowPDUSendTime = _pUt->UT_GetCurrentTimeMS();
  300. _IH.timerTickRate = IH_TIMER_TICK_RATE;
  301. _IH.pInputPDU = NULL;
  302. _IH.visibleArea.top = 0;
  303. _IH.visibleArea.left = 0;
  304. _IH.visibleArea.right = 1;
  305. _IH.visibleArea.bottom = 1;
  306. /************************************************************************/
  307. /* Initialize the sendZeroScanCode */
  308. /************************************************************************/
  309. _IH.sendZeroScanCode = (_pUt->UT_IsNEC98platform() && (_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95));
  310. #ifdef OS_WINCE
  311. /************************************************************************/
  312. /* In order to work around a problem with some input techniques (like */
  313. /* the default keyboard driver and CalliGrapher) that have a nasty */
  314. /* habit of not providing a scan-code with their WM_KEYDOWN and */
  315. /* WM_KEYUP messages, we need to allow scan-codes of 0 to pass through */
  316. /* IHFSMProc's ACT_D check against them. They'll be patched-up in */
  317. /* IHAddEventToPDU anyway, so there's nothing to worry about... :) */
  318. /************************************************************************/
  319. if (!g_CEUseScanCodes)
  320. {
  321. _IH.sendZeroScanCode = TRUE;
  322. _IH.vkEatMe = 0;
  323. }
  324. else
  325. {
  326. _IH.sendZeroScanCode = FALSE;
  327. }
  328. #else // OS_WINCE
  329. #if defined(OS_WIN32)
  330. _IH.sendZeroScanCode |= _pUt->UT_IsKorean101LayoutForWin9x();
  331. #endif
  332. #endif // OS_WINCE
  333. }
  334. break;
  335. case ACT_B:
  336. {
  337. /****************************************************************/
  338. /* Regained focus - synchronize. First try to send any */
  339. /* outstanding events. */
  340. /* Must pend sync until an input event is received, as */
  341. /* otherwise we may get the Caps Lock state wrong. */
  342. /****************************************************************/
  343. IHMaybeSendPDU();
  344. _IH.focusSyncRequired = TRUE;
  345. //
  346. // Work around a nasty problem caused because win32k doesn't sync the keystate
  347. // immediately after a desktop switch by force injecting a dummy key
  348. // that we only process locally.
  349. //
  350. // Injecting the key forces win32k to handle any pending keyevent updates
  351. // (QEVENT_UPDATEKEYSTATE) and so when we receive the key back in our msg
  352. // queue we know it's then safe to do the actual sync since modifier
  353. // key states will be correct.
  354. //
  355. //
  356. if (IHIsForegroundWindow()) {
  357. TRC_DBG((TB,_T("Fake N on sync DN. focus:0x%x IH:0x%x"),
  358. GetFocus(), _IH.inputCaptureWindow));
  359. //
  360. // Self inject a fake key
  361. //
  362. _IH.fDiscardSyncDownKey = TRUE;
  363. keybd_event(VK_IGNORE_VALUE, 0,
  364. 0, IH_EXTRAINFO_IGNOREVALUE);
  365. //
  366. // Self inject a fake key
  367. //
  368. _IH.fDiscardSyncUpKey = TRUE;
  369. keybd_event(VK_IGNORE_VALUE, 0,
  370. KEYEVENTF_KEYUP,
  371. IH_EXTRAINFO_IGNOREVALUE);
  372. }
  373. else {
  374. TRC_DBG((TB,_T("Fake N on sync. Did not have fore DN. focus:0x%x IH:0x%x"),
  375. GetFocus(), _IH.inputCaptureWindow));
  376. }
  377. //
  378. // Gaining focus -> Disable Cicero (keyboard/IME) toolbar
  379. //
  380. _pCd->CD_DecoupleSimpleNotification(CD_UI_COMPONENT,
  381. _pUi,
  382. CD_NOTIFICATION_FUNC(CUI,UI_OnInputFocusGained),
  383. 0);
  384. }
  385. break;
  386. case ACT_C:
  387. {
  388. ShowWindow(_IH.inputCaptureWindow, SW_HIDE);
  389. /****************************************************************/
  390. /* Stop the timer */
  391. /****************************************************************/
  392. KillTimer(_IH.inputCaptureWindow, _IH.timerID);
  393. _IH.timerID = 0;
  394. /****************************************************************/
  395. /* Ensure no cursor is selected in the window */
  396. /****************************************************************/
  397. IHSetCursorShape(NULL);
  398. /****************************************************************/
  399. /* Release the InputPDU back to the Network Layer */
  400. /****************************************************************/
  401. if (_IH.pInputPDU != NULL)
  402. {
  403. TRC_DBG((TB, _T("Free the inputPDU")));
  404. _pSl->SL_FreeBuffer(_IH.bufHandle);
  405. }
  406. _IH.pInputPDU = NULL;
  407. }
  408. break;
  409. case ACT_D:
  410. {
  411. /****************************************************************/
  412. /* Process the event - copy to nextMsg to simplify loop. */
  413. /****************************************************************/
  414. DC_MEMCPY(&nextMsg, (PMSG)data, sizeof(MSG));
  415. /****************************************************************/
  416. /* If the PDU is already full, try to send it, as we would like */
  417. /* to send this new event at least */
  418. /****************************************************************/
  419. if (_IH.pInputPDU->numberEvents >= _IH.maxEventCount)
  420. {
  421. IHMaybeSendPDU();
  422. }
  423. if (_IH.pInputPDU->numberEvents >= _IH.maxEventCount)
  424. {
  425. /************************************************************/
  426. /* The send failed and the buffer is full. Discard this */
  427. /* event. */
  428. /************************************************************/
  429. IHDiscardMsg(&nextMsg);
  430. /************************************************************/
  431. /* No point in scanning ahead on the queue. */
  432. /************************************************************/
  433. break;
  434. }
  435. /****************************************************************/
  436. /* Check if we need to sync due to regaining the focus. If we */
  437. /* do, and the message that brought us in here is a CapsLock, */
  438. /* NumLock or ScrollLock keydown, we do the sync but don't send */
  439. /* the keydown, otherwise it will result in the server syncing */
  440. /* to the new key state, then receiving a keydown that reverses */
  441. /* that state. */
  442. /* */
  443. /* It's OK to let the corresponding keyup go through, since */
  444. /* this won't affect any toggle states. */
  445. /* */
  446. /* Only do a 'focus regained' sync if this is an input message */
  447. /* (not a timer) otherwise GetKeyState won't have up-to-date */
  448. /* information. */
  449. /****************************************************************/
  450. if (_IH.focusSyncRequired && (nextMsg.message != WM_TIMER))
  451. {
  452. TRC_NRM((TB, _T("Focus regained - attempt to sync (%#x)"),
  453. nextMsg.message));
  454. IHGatherKeyState();
  455. IHSync();
  456. if ((nextMsg.message == WM_KEYDOWN) &&
  457. ((nextMsg.wParam == VK_CAPITAL) ||
  458. (nextMsg.wParam == VK_NUMLOCK) ||
  459. (nextMsg.wParam == VK_SCROLL)))
  460. {
  461. /********************************************************/
  462. /* Ignore this message because it will override the */
  463. /* sync message we've just sent. This is not an error */
  464. /* condition, so set rc = TRUE. */
  465. /********************************************************/
  466. TRC_ALT((TB,
  467. _T("Not sending keydown that caused sync (VK %#x)"),
  468. nextMsg.wParam));
  469. rc = TRUE;
  470. DC_QUIT;
  471. }
  472. }
  473. /****************************************************************/
  474. /* Do a sync if required, as we may have just done a successful */
  475. /* send. */
  476. /****************************************************************/
  477. if (_IH.syncRequired)
  478. {
  479. TRC_NRM((TB, _T("Attempt to Sync (%#x)"), nextMsg.message));
  480. IHSync();
  481. }
  482. /****************************************************************/
  483. /* Pull off remaining events until the PDU is full, or we have */
  484. /* pulled off more than eventsAtOnce events. */
  485. /****************************************************************/
  486. for (newEvents = 0;
  487. ((_IH.pInputPDU->numberEvents < _IH.maxEventCount) &&
  488. (newEvents < _IH.eventsAtOnce)); )
  489. {
  490. if (IH_IS_INPUTEVENT(nextMsg.message))
  491. {
  492. if ((nextMsg.message == WM_KEYDOWN || nextMsg.message == WM_KEYUP) &&
  493. IHMassageZeroScanCode(&nextMsg))
  494. {
  495. TRC_NRM((TB, _T("Discarding input message: 0x%04x sc: 0x%04x"),
  496. nextMsg.message, (((nextMsg.lParam >> 16) & 0xff))));
  497. }
  498. else
  499. {
  500. TRC_DBG((TB, _T("Add message %x"), nextMsg.message));
  501. newEvents++;
  502. if ((nextMsg.message >= WM_KEYFIRST) &&
  503. (nextMsg.message <= WM_KEYLAST))
  504. {
  505. TRC_DBG((TB, _T("Keyboard event")));
  506. rc = IHProcessKeyboardEvent(&nextMsg);
  507. }
  508. else
  509. {
  510. TRC_DBG((TB, _T("Mouse event")));
  511. rc = IHProcessMouseEvent(&nextMsg);
  512. }
  513. /****************************************************/
  514. /* If the handler indicates, force end of loop */
  515. /****************************************************/
  516. if (!rc)
  517. {
  518. TRC_NRM((TB, _T("Force end of loop")));
  519. break;
  520. }
  521. }
  522. }
  523. else
  524. {
  525. DefWindowProc(nextMsg.hwnd,
  526. nextMsg.message,
  527. nextMsg.wParam,
  528. nextMsg.lParam);
  529. }
  530. /************************************************************/
  531. /* We may have hit the limit of maxEventCount or */
  532. /* eventsAtOnce at this point. Jump out of the loop if so. */
  533. /************************************************************/
  534. if ((_IH.pInputPDU->numberEvents >= _IH.maxEventCount) ||
  535. (newEvents >= _IH.eventsAtOnce))
  536. {
  537. TRC_NRM((TB,
  538. _T("Limit hit: not pulling off any more events")));
  539. break;
  540. }
  541. /************************************************************/
  542. /* Pull the next input event off the message queue. Note */
  543. /* that this also pulls off some other events - but can't */
  544. /* split this into separate mouse / keyboard Peeks, as this */
  545. /* could get the message order wrong. */
  546. /************************************************************/
  547. #if (WM_KEYFIRST > WM_MOUSELAST)
  548. TRC_ABORT((TB, _T("Internal Error")));
  549. #endif
  550. /************************************************************/
  551. /* If there are more input or timer messages in the queue, */
  552. /* we would like to pull them out. First see if the next */
  553. /* message is one we want without taking it off the queue. */
  554. /************************************************************/
  555. if (PeekMessage(&nextMsg,
  556. _IH.inputCaptureWindow,
  557. WM_KEYFIRST,
  558. WM_MOUSELAST,
  559. PM_NOREMOVE) == 0)
  560. {
  561. TRC_DBG((TB, _T("No more messages")));
  562. break;
  563. }
  564. /************************************************************/
  565. /* If the message found in the peek with NOREMOVE set was */
  566. /* one we want, peek again but this time remove it. */
  567. /* Otherwise the message is not one we want so send the */
  568. /* current buffer. */
  569. /************************************************************/
  570. if (IH_IS_INPUTEVENT(nextMsg.message) ||
  571. (nextMsg.message == WM_TIMER))
  572. {
  573. #ifdef DC_DEBUG
  574. UINT msgPeeked = nextMsg.message;
  575. #endif
  576. if (PeekMessage(&nextMsg,
  577. _IH.inputCaptureWindow,
  578. WM_KEYFIRST,
  579. WM_MOUSELAST,
  580. PM_REMOVE) == 0)
  581. {
  582. /****************************************************/
  583. /* We should find the message we found when we */
  584. /* peeked without removing - however this can fail */
  585. /* if a higher priority (non-input) message is */
  586. /* added to the queue in between the two */
  587. /* PeekMessage calls. */
  588. /****************************************************/
  589. TRC_ALT((TB, _T("No messages on queue (did have %#x)"),
  590. msgPeeked));
  591. break;
  592. }
  593. else
  594. {
  595. TRC_DBG((TB,_T("Found a message (type %#x)"),
  596. nextMsg.message));
  597. /****************************************************/
  598. /* If this is a message the main window is */
  599. /* interested in then Post it and send the current */
  600. /* buffer. */
  601. /****************************************************/
  602. if (IHPostMessageToMainWindow(nextMsg.message,
  603. nextMsg.wParam,
  604. nextMsg.lParam))
  605. {
  606. TRC_NRM((TB, _T("Message passed to main window")));
  607. break;
  608. }
  609. }
  610. }
  611. else
  612. {
  613. TRC_NRM((TB, _T("Found blocker message")));
  614. break;
  615. }
  616. }
  617. /****************************************************************/
  618. /* Send the PDU */
  619. /****************************************************************/
  620. IHMaybeSendPDU();
  621. rc = TRUE;
  622. }
  623. break;
  624. case ACT_E:
  625. {
  626. /****************************************************************/
  627. /* Input / timer event with no focus - just discard this event. */
  628. /****************************************************************/
  629. TRC_ASSERT((data != 0), (TB, _T("No message")));
  630. TRC_DBG((TB, _T("Ignore event %x"), ((PMSG)data)->message));
  631. /****************************************************************/
  632. /* But send keepalives if required. */
  633. /****************************************************************/
  634. IHMaybeSendPDU();
  635. }
  636. break;
  637. case ACT_F:
  638. {
  639. /****************************************************************/
  640. /* A buffer available event has been received. Try to send the */
  641. /* packet, and sync if required. */
  642. /****************************************************************/
  643. IHMaybeSendPDU();
  644. if (_IH.syncRequired)
  645. {
  646. TRC_NRM((TB, _T("Attempt to sync")));
  647. IHSync();
  648. }
  649. }
  650. break;
  651. case ACT_G:
  652. {
  653. TRC_DBG((TB, _T("Enabling")));
  654. //Init keyboard hooking settings
  655. switch( _pUi->_UI.keyboardHookMode)
  656. {
  657. case UTREG_UI_KEYBOARD_HOOK_ALWAYS:
  658. {
  659. TRC_DBG((TB, _T("Set keyboard hook to ALWAYS ON")));
  660. _fUseHookBypass = _fCanUseKeyboardHook;
  661. }
  662. break;
  663. case UTREG_UI_KEYBOARD_HOOK_FULLSCREEN:
  664. {
  665. _fUseHookBypass = _pUi->UI_IsFullScreen() &&
  666. _fCanUseKeyboardHook;
  667. }
  668. break;
  669. case UTREG_UI_KEYBOARD_HOOK_NEVER: //FALLTHRU
  670. default:
  671. {
  672. TRC_DBG((TB, _T("Set keyboard hook to ALWAYS OFF")));
  673. _fUseHookBypass = FALSE;
  674. }
  675. break;
  676. }
  677. /****************************************************************/
  678. /* Get a buffer for the input PDU and initialize it. */
  679. /****************************************************************/
  680. TRC_ASSERT((_IH.pInputPDU == NULL), (TB, _T("Non-NULL InputPDU")));
  681. if (!_pSl->SL_GetBuffer(IH_INPUTPDU_BUFSIZE,
  682. (PPDCUINT8)&_IH.pInputPDU,
  683. &_IH.bufHandle))
  684. {
  685. TRC_ALT((TB, _T("Failed to get an InputPDU buffer")));
  686. /************************************************************/
  687. /* Call the FSM to enter Pending Active state. Exit the */
  688. /* Pending Active state when a buffer is available. */
  689. /************************************************************/
  690. IHFSMProc(IH_FSM_NOBUFFER, 0);
  691. break;
  692. }
  693. /****************************************************************/
  694. /* Initialize the InputPDU packet header */
  695. /****************************************************************/
  696. IHInitPacket();
  697. /****************************************************************/
  698. /* Synchronize */
  699. /****************************************************************/
  700. IHSync();
  701. /****************************************************************/
  702. /* Start the IH Timer */
  703. /****************************************************************/
  704. _IH.timerID = SetTimer(_IH.inputCaptureWindow,
  705. IH_TIMER_ID,
  706. _IH.timerTickRate,
  707. NULL);
  708. /****************************************************************/
  709. /* We show the window last because we've seen this call end up */
  710. /* processing an input message in ACT_D. That's safe at this */
  711. /* point because the input PDU is initialized now. */
  712. /* */
  713. /* Note that on Windows CE this is the output window. */
  714. /****************************************************************/
  715. _pUi->UI_GetDesktopSize(&desktopSize);
  716. SetWindowPos( _IH.inputCaptureWindow,
  717. NULL,
  718. 0, 0,
  719. desktopSize.width,
  720. desktopSize.height,
  721. SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOMOVE |
  722. SWP_NOACTIVATE | SWP_NOOWNERZORDER );
  723. }
  724. break;
  725. case ACT_H:
  726. {
  727. TRC_DBG((TB, _T("Terminating")));
  728. /****************************************************************/
  729. /* Stop the timer if it is active */
  730. /****************************************************************/
  731. if (_IH.timerID != 0)
  732. {
  733. KillTimer(_IH.inputCaptureWindow, _IH.timerID);
  734. _IH.timerID = 0;
  735. }
  736. /****************************************************************/
  737. /* Ensure no cursor is selected in the window */
  738. /****************************************************************/
  739. IHSetCursorShape(NULL);
  740. //#ifdef DESTROY_WINDOWS
  741. /****************************************************************/
  742. /* Destroy the Input Capture window. */
  743. /****************************************************************/
  744. TRC_ASSERT((_IH.inputCaptureWindow != NULL), (TB, _T("no window")));
  745. TRC_NRM((TB, _T("Destroy IH window")));
  746. DestroyWindow(_IH.inputCaptureWindow);
  747. TRC_NRM((TB, _T("Destroyed IH window")));
  748. /****************************************************************/
  749. /* Unregister the window class */
  750. /****************************************************************/
  751. TRC_DBG((TB, _T("Unregister IH window class")));
  752. if (!UnregisterClass(IH_CLASS_NAME, _pUi->UI_GetInstanceHandle()))
  753. {
  754. //Failure to unregister could happen if another instance is still running
  755. //that's ok...unregistration will happen when the last instance exits.
  756. TRC_ERR((TB, _T("Failed to unregister IH window class")));
  757. }
  758. //#endif
  759. }
  760. break;
  761. case ACT_I:
  762. {
  763. /****************************************************************/
  764. /* Release the mouse capture in case we have it. */
  765. /****************************************************************/
  766. TRC_DBG((TB, _T("Losing focus: Release mouse capture")));
  767. ReleaseCapture();
  768. }
  769. break;
  770. case ACT_J:
  771. {
  772. /****************************************************************/
  773. /* Input event before IH has an InputPDU buffer. */
  774. /****************************************************************/
  775. TRC_DBG((TB, _T("Discard Input Event - no InputPDU buffer")));
  776. IHDiscardMsg((PMSG)data);
  777. }
  778. break;
  779. case ACT_NO:
  780. {
  781. TRC_DBG((TB, _T("Nothing to do here.")));
  782. }
  783. break;
  784. default:
  785. {
  786. rc = FALSE;
  787. TRC_ABORT((TB, _T("Invalid Action!")));
  788. }
  789. break;
  790. }
  791. DC_EXIT_POINT:
  792. DC_END_FN();
  793. return(rc);
  794. } /* IHFSMProc */
  795. /****************************************************************************/
  796. /* Name: IHMassageZeroScanCode (Named by TrevorFo) */
  797. /* */
  798. /* Purpose: Fix up or discard zero scan code input */
  799. /* */
  800. /* Returns: TRUE - Scan code was zero and couldn't be fixed, discard */
  801. /* FALSE - Scan code was not zero or fixable, process */
  802. /* */
  803. /* Params: pMsg - message from Windows */
  804. /****************************************************************************/
  805. DCBOOL DCINTERNAL CIH::IHMassageZeroScanCode(PMSG pMsg)
  806. {
  807. WORD lParamLo, lParamHi;
  808. WORD scancode, flags;
  809. DC_BEGIN_FN("CIH::IHMassageZeroScanCode");
  810. lParamLo = LOWORD(pMsg->lParam);
  811. lParamHi = HIWORD(pMsg->lParam);
  812. scancode = (WORD)(lParamHi & 0x00FF);
  813. flags = (WORD)(lParamHi & 0xFF00);
  814. //
  815. // VK_Packets can have '0' 'scancodes' when the lowbyte
  816. // of the unicode character is 0.
  817. //
  818. if (VK_PACKET == pMsg->wParam) {
  819. return FALSE;
  820. }
  821. //
  822. // Self-injected sync keys have 0 scancode
  823. //
  824. if (VK_IGNORE_VALUE == pMsg->wParam) {
  825. return FALSE;
  826. }
  827. #ifndef OS_WINCE
  828. if (scancode == 0) {
  829. switch (pMsg->wParam) {
  830. case VK_BROWSER_BACK:
  831. case VK_BROWSER_FORWARD:
  832. case VK_BROWSER_REFRESH:
  833. case VK_BROWSER_STOP:
  834. case VK_BROWSER_SEARCH:
  835. case VK_BROWSER_FAVORITES:
  836. case VK_BROWSER_HOME:
  837. case VK_VOLUME_MUTE:
  838. case VK_VOLUME_DOWN:
  839. case VK_VOLUME_UP:
  840. case VK_MEDIA_NEXT_TRACK:
  841. case VK_MEDIA_PREV_TRACK:
  842. case VK_MEDIA_STOP:
  843. case VK_MEDIA_PLAY_PAUSE:
  844. case VK_LAUNCH_MAIL:
  845. case VK_LAUNCH_MEDIA_SELECT:
  846. case VK_LAUNCH_APP1:
  847. case VK_LAUNCH_APP2:
  848. TRC_NRM((TB, _T("Fix up Speed Racer key")));
  849. scancode = (DCUINT16)MapVirtualKey(pMsg->wParam, 0);
  850. }
  851. }
  852. #endif
  853. // Fix up the lParam with the new scancode
  854. lParamHi = (WORD)(scancode | flags);
  855. pMsg->lParam = MAKELONG(lParamLo, lParamHi);
  856. DC_END_FN();
  857. return (scancode == 0) && !_IH.sendZeroScanCode;
  858. }
  859. /****************************************************************************/
  860. /* Name: IHStaticInputCaptureWndProc */
  861. /* */
  862. /* Purpose: STATIC delegates to appropriate instance */
  863. /* */
  864. /* Returns: Windows return code */
  865. /* */
  866. /* Params: IN hwnd - window handle */
  867. /* IN message - message id */
  868. /* IN wParam - parameter */
  869. /* IN lParam - parameter */
  870. /****************************************************************************/
  871. LRESULT CALLBACK CIH::IHStaticInputCaptureWndProc(HWND hwnd,
  872. UINT message,
  873. WPARAM wParam,
  874. LPARAM lParam)
  875. {
  876. CIH* pIH = (CIH*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  877. if(WM_CREATE == message)
  878. {
  879. //pull out the this pointer and stuff it in the window class
  880. LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
  881. pIH = (CIH*)lpcs->lpCreateParams;
  882. SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pIH);
  883. }
  884. //
  885. // Delegate the message to the appropriate instance
  886. //
  887. if(pIH)
  888. {
  889. return pIH->IHInputCaptureWndProc(hwnd, message, wParam, lParam);
  890. }
  891. else
  892. {
  893. return DefWindowProc(hwnd, message, wParam, lParam);
  894. }
  895. }
  896. /****************************************************************************/
  897. /* Name: IHInputCaptureWndProc */
  898. /* */
  899. /* Purpose: Input Handler window callback procedure */
  900. /* */
  901. /* Returns: Windows return code */
  902. /* */
  903. /* Params: IN hwnd - window handle */
  904. /* IN message - message id */
  905. /* IN wParam - parameter */
  906. /* IN lParam - parameter */
  907. /****************************************************************************/
  908. LRESULT CALLBACK CIH::IHInputCaptureWndProc(HWND hwnd,
  909. UINT message,
  910. WPARAM wParam,
  911. LPARAM lParam)
  912. {
  913. LRESULT rc = 0;
  914. MSG copyMsg;
  915. DC_BEGIN_FN("IHInputCaptureWndProc");
  916. TRC_ASSERT(((hwnd == _IH.inputCaptureWindow) ||
  917. (_IH.inputCaptureWindow == NULL)),
  918. (TB, _T("Wrong window handle %p"), hwnd));
  919. TRC_DBG((TB, _T("Message id %#x hwnd %p wParam %p lParam %p"),
  920. message, hwnd, wParam, lParam));
  921. #ifdef OS_WINCE
  922. if(!g_CEUseScanCodes && (0 != _IH.vkEatMe) && (wParam == _IH.vkEatMe))
  923. {
  924. /********************************************************************/
  925. /* This key has been marked for ignoring. Do so now. */
  926. /* On configs where g_CEUseScanCodes = 1, _IH.vkEatMe always = 0 */
  927. /********************************************************************/
  928. _IH.vkEatMe = 0;
  929. DC_QUIT;
  930. }
  931. #endif // OS_WINCE
  932. if (IHPostMessageToMainWindow(message, wParam, lParam))
  933. {
  934. DC_QUIT;
  935. }
  936. #ifdef PERF
  937. if ((message == WM_KEYUP) && (wParam == VK_CONTROL))
  938. {
  939. OUTPUT_COUNTERS;
  940. RESET_COUNTERS;
  941. }
  942. #endif // PERF
  943. /************************************************************************/
  944. /* Pass input events and timer events to the FSM */
  945. /************************************************************************/
  946. if (IH_IS_INPUTEVENT(message) || (message == WM_TIMER))
  947. {
  948. #ifdef DC_DEBUG
  949. if (IH_IS_INPUTEVENT(message)) {
  950. TRC_NRM((TB, _T("Pass input to FSM hwnd:%p msg:%#x wP:%p lp:%p"),
  951. hwnd, message, wParam, lParam));
  952. }
  953. #endif
  954. TRC_DBG((TB, _T("Pass input/timer to FSM")));
  955. copyMsg.hwnd = hwnd;
  956. copyMsg.message = message;
  957. copyMsg.wParam = wParam;
  958. copyMsg.lParam = lParam;
  959. IHFSMProc(IH_FSM_INPUT, (ULONG_PTR)&copyMsg);
  960. }
  961. else
  962. {
  963. switch (message)
  964. {
  965. case WM_CREATE:
  966. {
  967. #ifdef OS_WIN32
  968. #ifndef OS_WINCE
  969. if (!AttachThreadInput(
  970. GetCurrentThreadId(),
  971. GetWindowThreadProcessId(_pUi->UI_GetUIContainerWindow(),
  972. NULL),
  973. TRUE ))
  974. {
  975. TRC_ALT((TB, _T("Failed AttachThreadInput")));
  976. }
  977. #endif
  978. //
  979. // Set up some Thread Local Storage so we can have a low
  980. // level keyboard hook
  981. //
  982. #ifdef OS_WINCE
  983. if (g_CEConfig == CE_CONFIG_WBT)
  984. {
  985. _pUi->UI_SetEnableWindowsKey(TRUE);
  986. break;
  987. }
  988. #endif
  989. if (CIH::TlsIndex != 0xFFFFFFFF) {
  990. if (TlsSetValue(CIH::TlsIndex, this)) {
  991. TRC_NRM((TB, _T("Set TlsIndex with CIH 0x%p"), this));
  992. //
  993. // Install a low level keyboard hook to catch key sequences
  994. // typically intercepted by the OS and allow us to pass them
  995. // to the Terminal Server. Only install it for this thread
  996. //
  997. #if (!defined(OS_WINCE)) || (!defined(WINCE_SDKBUILD))
  998. _hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,
  999. IHStaticLowLevelKeyboardProc, GetModuleHandle(NULL), 0);
  1000. #endif
  1001. if (_hKeyboardHook == NULL) {
  1002. TRC_SYSTEM_ERROR("Creating low level keyboard hook.");
  1003. _fUseHookBypass = FALSE;
  1004. }
  1005. else
  1006. {
  1007. _fCanUseKeyboardHook = TRUE;
  1008. }
  1009. } else {
  1010. TRC_SYSTEM_ERROR("Unable to TlsSetValue");
  1011. _fUseHookBypass = FALSE;
  1012. }
  1013. } else {
  1014. TRC_ALT((TB, _T("Can't use hooks without Tls, disabling")));
  1015. _fUseHookBypass = FALSE;
  1016. }
  1017. //
  1018. // Whether we say to send the Windows key is now determined
  1019. // by whether we support hooking it.
  1020. //
  1021. _pUi->UI_SetEnableWindowsKey(_hKeyboardHook != NULL);
  1022. #endif
  1023. }
  1024. break;
  1025. case WM_SETCURSOR:
  1026. {
  1027. SetCursor(_IH.hCurrentCursor);
  1028. rc = DefWindowProc(hwnd, message, wParam, lParam);
  1029. }
  1030. break;
  1031. case WM_DESTROY:
  1032. {
  1033. if (_hKeyboardHook != NULL) {
  1034. #if (!defined(OS_WINCE)) || (!defined(WINCE_SDKBUILD))
  1035. if (!UnhookWindowsHookEx(_hKeyboardHook)) {
  1036. TRC_SYSTEM_ERROR("UnhookWindowsHookEx");
  1037. }
  1038. #endif
  1039. _hKeyboardHook = NULL;
  1040. }
  1041. }
  1042. break;
  1043. #ifdef OS_WINNT
  1044. case IH_WM_HANDLE_LOCKDESKTOP:
  1045. {
  1046. TRC_NRM((TB,_T("Defered handling of IHHandleLocalLockDesktop")));
  1047. IHHandleLocalLockDesktop();
  1048. }
  1049. break;
  1050. #endif //OS_WINNT
  1051. case WM_KILLFOCUS:
  1052. {
  1053. /************************************************************/
  1054. /* Losing the focus. No action - we won't get any more */
  1055. /* keystroke events. The exception here is if we actually */
  1056. /* want to keep on passing messages through (e.g. mouse) */
  1057. /* when we haven't got the focus. */
  1058. /************************************************************/
  1059. TRC_DBG((TB, _T("Kill focus")));
  1060. if (!_IH.allowBackgroundInput)
  1061. {
  1062. IHFSMProc(IH_FSM_FOCUS_LOSE, (ULONG_PTR) 0);
  1063. }
  1064. //
  1065. // Losing focus -> Enable Cicero (keyboard/IME) toolbar
  1066. // NOTE: it is important to fire this notification regardless
  1067. // of w/not allowBackground input is set
  1068. //
  1069. _pCd->CD_DecoupleSimpleNotification(CD_UI_COMPONENT,
  1070. _pUi,
  1071. CD_NOTIFICATION_FUNC(CUI,UI_OnInputFocusLost),
  1072. 0);
  1073. #ifdef OS_WINCE
  1074. if (_hKeyboardHook != NULL) {
  1075. #if !defined(WINCE_SDKBUILD)
  1076. if (!UnhookWindowsHookEx(_hKeyboardHook)) {
  1077. TRC_SYSTEM_ERROR("UnhookWindowsHookEx");
  1078. }
  1079. #endif
  1080. _hKeyboardHook = NULL;
  1081. _fUseHookBypass = _fCanUseKeyboardHook = FALSE;
  1082. _pUi->UI_SetEnableWindowsKey(_fUseHookBypass);
  1083. }
  1084. #endif
  1085. }
  1086. break;
  1087. case WM_SETFOCUS:
  1088. {
  1089. #ifdef OS_WINCE //CE allows only one system wide hook. Install it when we get focus and uninstall it when we loose focus
  1090. if (g_CEConfig != CE_CONFIG_WBT) {
  1091. if ((CIH::TlsIndex != 0xFFFFFFFF) && (TlsSetValue(CIH::TlsIndex, this)) && (_hKeyboardHook == NULL)) {
  1092. #if !defined(WINCE_SDKBUILD)
  1093. _hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,
  1094. IHStaticLowLevelKeyboardProc, GetModuleHandle(NULL), 0);
  1095. #endif
  1096. _fCanUseKeyboardHook = (_hKeyboardHook != NULL);
  1097. }
  1098. _fUseHookBypass = (_pUi->_UI.keyboardHookMode != UTREG_UI_KEYBOARD_HOOK_NEVER) && (_fCanUseKeyboardHook);
  1099. _pUi->UI_SetEnableWindowsKey(_fUseHookBypass);
  1100. }
  1101. #endif
  1102. /************************************************************/
  1103. /* Regaining the focus - need to resync */
  1104. /************************************************************/
  1105. TRC_DBG((TB, _T("Set focus")));
  1106. IHFSMProc(IH_FSM_FOCUS_GAIN, (ULONG_PTR) 0);
  1107. }
  1108. break;
  1109. case WM_PAINT:
  1110. {
  1111. #ifndef OS_WINCE
  1112. HDC hdc;
  1113. PAINTSTRUCT ps;
  1114. #endif // OS_WINCE
  1115. TRC_NRM((TB, _T("WM_PAINT")));
  1116. #ifdef OS_WINCE
  1117. /************************************************************/
  1118. /* Handle drawing in OP. This is a workaround for the */
  1119. /* WS_CLIPSIBLINGS problem. */
  1120. /************************************************************/
  1121. _pCd->CD_DecoupleSyncNotification(CD_RCV_COMPONENT,
  1122. _pOp,
  1123. CD_NOTIFICATION_FUNC(COP,OP_DoPaint),
  1124. (ULONG_PTR)hwnd);
  1125. #else
  1126. /************************************************************/
  1127. /* Don't do any painting - just validate the invalid region */
  1128. /* by calling BeginPaint/EndPaint. */
  1129. /************************************************************/
  1130. hdc = BeginPaint(hwnd, &ps);
  1131. EndPaint(hwnd, &ps);
  1132. #endif
  1133. }
  1134. break;
  1135. case WM_SYSCHAR:
  1136. case WM_CHAR:
  1137. case WM_DEADCHAR:
  1138. case WM_SYSDEADCHAR:
  1139. case WM_SYSCOMMAND:
  1140. {
  1141. /************************************************************/
  1142. /* Discard these messages */
  1143. /************************************************************/
  1144. TRC_NRM((TB, _T("Ignore message %#x"), message));
  1145. }
  1146. break;
  1147. default:
  1148. {
  1149. /************************************************************/
  1150. /* Ignore all other messages. */
  1151. /************************************************************/
  1152. rc = DefWindowProc(hwnd, message, wParam, lParam);
  1153. }
  1154. break;
  1155. }
  1156. }
  1157. DC_EXIT_POINT:
  1158. DC_END_FN();
  1159. return(rc);
  1160. } /* IHInputCaptureWndProc */
  1161. /****************************************************************************/
  1162. /* Name: IHAddEventToPDU */
  1163. /* */
  1164. /* Purpose: Add an input event to the T.Share InputPDU packet */
  1165. /* */
  1166. /* Returns: Success TRUE / FALSE */
  1167. /* */
  1168. /* Params: IN inputMsg - pointer to input event */
  1169. /* */
  1170. /* Operation: No conversion to Ascii/Unicode: keystrokes are sent as */
  1171. /* virtual keys. */
  1172. /****************************************************************************/
  1173. DCBOOL DCINTERNAL CIH::IHAddEventToPDU(PMSG inputMsg)
  1174. {
  1175. DCBOOL rc = FALSE;
  1176. UINT message = inputMsg->message;
  1177. LPARAM lParam = inputMsg->lParam;
  1178. WPARAM wParam = inputMsg->wParam;
  1179. PTS_INPUT_EVENT pEvent;
  1180. POINT mouse;
  1181. DCUINT16 scancode = 0;
  1182. #if !defined(OS_WINCE)
  1183. WORD xButton = 0;
  1184. #endif
  1185. #ifdef OS_WINCE
  1186. static BOOL fIgnoreMenuDown = FALSE;
  1187. BOOL addanother = FALSE;
  1188. MSG tmpmsg;
  1189. #endif // OS_WINCE
  1190. #ifdef OS_WINCE
  1191. BOOL bAddMultiple = FALSE;
  1192. UINT cpt = 128;
  1193. POINT apt[128];
  1194. #endif // OS_WINCE
  1195. DC_BEGIN_FN("IHAddEventToPDU");
  1196. TRC_DBG((TB, _T("Event: %x (%x,%x)"), message, wParam, lParam));
  1197. /************************************************************************/
  1198. /* Don't try to add to the PDU if it's already full. */
  1199. /************************************************************************/
  1200. if (_IH.pInputPDU->numberEvents >= _IH.maxEventCount)
  1201. {
  1202. TRC_ALT((TB, _T("No room for new event")));
  1203. DC_QUIT;
  1204. }
  1205. /************************************************************************/
  1206. /* Translate event and add to the queue */
  1207. /************************************************************************/
  1208. pEvent = &(_IH.pInputPDU->eventList[_IH.pInputPDU->numberEvents]);
  1209. DC_MEMSET(pEvent, 0, sizeof(TS_INPUT_EVENT));
  1210. switch (message)
  1211. {
  1212. case WM_KEYDOWN:
  1213. case WM_SYSKEYDOWN:
  1214. case WM_KEYUP:
  1215. case WM_SYSKEYUP:
  1216. {
  1217. #ifdef OS_WINCE
  1218. /****************************************************************/
  1219. /* Some input techrniques don't send scan-codes in the WM_*KEY* */
  1220. /* messages they generate. So we'll try to cover for them by */
  1221. /* adding a scan-code based on the virtual-key code contained */
  1222. /* within the wParam of such messages. */
  1223. /****************************************************************/
  1224. // Translate the virtual-key to a scan code if necessary
  1225. if(!g_CEUseScanCodes)
  1226. {
  1227. lParam &= 0xFF00FFFF;
  1228. lParam |= MAKELPARAM(0, VKeyToScanCode[wParam & 0xFF]);
  1229. }
  1230. #endif // OS_WINCE
  1231. /****************************************************************/
  1232. /* Just send the VK. Set 'priority events queued' flag. */
  1233. /****************************************************************/
  1234. _IH.priorityEventsQueued = TRUE;
  1235. TRC_NRM((TB, _T("vkey %#hx %s flags %#hx scan %#hx"),
  1236. (DCUINT16)wParam,
  1237. (message == WM_KEYUP) || (message == WM_SYSKEYUP) ?
  1238. _T("up") : _T("down"),
  1239. (DCUINT16)(HIWORD(lParam) & 0xFF00),
  1240. (DCUINT16)(HIWORD(lParam) & 0x00FF) ));
  1241. if (wParam != VK_PACKET && _IH.useScancodes)
  1242. {
  1243. /************************************************************/
  1244. /* Extract scancode from the LPARAM. */
  1245. /************************************************************/
  1246. scancode = (DCUINT16)(HIWORD(lParam) & 0x00FF);
  1247. TRC_DBG((TB, _T("aetp vk: 0x%04x sc: 0x%04x A/E/U: %d%d%d"), wParam,
  1248. scancode, (HIWORD(lParam) & KF_ALTDOWN) != 0,
  1249. (HIWORD(lParam) & KF_EXTENDED) != 0,
  1250. (HIWORD(lParam) & KF_UP) != 0));
  1251. pEvent->messageType = TS_INPUT_EVENT_SCANCODE;
  1252. pEvent->u.key.keyCode = scancode;
  1253. TRC_DBG((TB, _T("Send scancode %#hx"), scancode));
  1254. }
  1255. else if (VK_PACKET == wParam)
  1256. {
  1257. if (_IH.fUseVKPacket)
  1258. {
  1259. //
  1260. // Injected unicode character is contained in the scancode
  1261. //
  1262. scancode = (DCUINT16)(HIWORD(lParam) & 0xFFFF);
  1263. TRC_DBG((TB, _T("aetp vk: 0x%04x sc: 0x04x A/E/U: %d%d%d"),
  1264. wParam,
  1265. scancode, (HIWORD(lParam) & KF_ALTDOWN) != 0,
  1266. (HIWORD(lParam) & KF_EXTENDED) != 0,
  1267. (HIWORD(lParam) & KF_UP) != 0));
  1268. pEvent->messageType = TS_INPUT_EVENT_VKPACKET;
  1269. pEvent->u.key.keyCode = scancode; //really a unicode character
  1270. TRC_DBG((TB, _T("Send unicode character (in scancode) %#hx"),
  1271. scancode));
  1272. }
  1273. else
  1274. {
  1275. // VK_PACKET not supported, must discard it
  1276. TRC_DBG((TB,_T("Discarding VK_PACKET")));
  1277. DC_QUIT;
  1278. }
  1279. }
  1280. else
  1281. {
  1282. pEvent->messageType = TS_INPUT_EVENT_VIRTUALKEY;
  1283. pEvent->u.key.keyCode = (DCUINT16)wParam;
  1284. TRC_DBG((TB, _T("Send VK %#hx"), (DCUINT16)wParam ));
  1285. }
  1286. /****************************************************************/
  1287. /* Check if key was down or up before this event. */
  1288. /****************************************************************/
  1289. if (HIWORD(lParam) & KF_REPEAT)
  1290. {
  1291. TRC_DBG((TB, _T("Key was down")));
  1292. pEvent->u.key.keyboardFlags = TS_KBDFLAGS_DOWN;
  1293. }
  1294. /****************************************************************/
  1295. /* Set 'release' flag for key up. */
  1296. /****************************************************************/
  1297. if ((message == WM_KEYUP) || (message == WM_SYSKEYUP))
  1298. {
  1299. TRC_DBG((TB, _T("Key up message")));
  1300. pEvent->u.key.keyboardFlags |= TS_KBDFLAGS_RELEASE;
  1301. #ifdef OS_WINCE
  1302. /****************************************************************/
  1303. /* fIgnoreMuneDown = FALSE always if g_CEUseScanCodes = 1 */
  1304. /****************************************************************/
  1305. if (fIgnoreMenuDown && wParam == VK_MENU)
  1306. {
  1307. fIgnoreMenuDown = FALSE;
  1308. DC_QUIT;
  1309. }
  1310. #endif // OS_WINCE
  1311. }
  1312. /****************************************************************/
  1313. /* Set the 'extended' flag */
  1314. /****************************************************************/
  1315. if (HIWORD(lParam) & KF_EXTENDED)
  1316. {
  1317. TRC_DBG((TB, _T("Extended flag set")));
  1318. pEvent->u.key.keyboardFlags |= TS_KBDFLAGS_EXTENDED;
  1319. }
  1320. /****************************************************************/
  1321. /* Set the 'extended1' flag */
  1322. /****************************************************************/
  1323. if (HIWORD(lParam) & IH_KF_EXTENDED1)
  1324. {
  1325. TRC_DBG((TB, _T("Extended1 flag set")));
  1326. pEvent->u.key.keyboardFlags |= TS_KBDFLAGS_EXTENDED1;
  1327. }
  1328. #ifdef OS_WINCE
  1329. if (!g_CEUseScanCodes &&
  1330. ((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN)))
  1331. {
  1332. if ( !((wParam == VK_SHIFT) && _IH.useScancodes) &&
  1333. fIgnoreMenuDown && wParam == VK_MENU &&
  1334. (HIWORD(lParam) & KF_REPEAT))
  1335. {
  1336. // Bail out now if we are ignoring this key.
  1337. DC_QUIT;
  1338. }
  1339. }
  1340. #endif // OS_WINCE
  1341. }
  1342. break;
  1343. case WM_MOUSEMOVE:
  1344. {
  1345. TRC_DBG((TB, _T("Mousemove")));
  1346. pEvent->messageType = TS_INPUT_EVENT_MOUSE;
  1347. pEvent->u.mouse.pointerFlags = TS_FLAG_MOUSE_MOVE;
  1348. #ifdef OS_WINCE
  1349. /****************************************************************/
  1350. /* if this feature is enabled && the mouse button is down, */
  1351. /* then the user is drawing/writing -- grab all mousemove data */
  1352. /****************************************************************/
  1353. if( (_IH.bLMouseButtonDown) && (_IH.maxMouseMove))
  1354. {
  1355. if (!GetMouseMovePoints(apt, cpt, &cpt))
  1356. {
  1357. TRC_DBG((TB, _T("GetMouseMovePoints() failed")));
  1358. }
  1359. else
  1360. {
  1361. /****************************************************************/
  1362. /* If we only have single point, don't use addmultiple, just */
  1363. /* fall through, otherwise call the multi-event handler */
  1364. /****************************************************************/
  1365. if(cpt > 1)
  1366. {
  1367. bAddMultiple = IHAddMultipleEventsToPDU(apt, cpt);
  1368. }
  1369. }
  1370. /****************************************************************/
  1371. /* If API fails, or IHAddMultipleEventsToPDU fails, fall through*/
  1372. /* to process the original mouse move event that got us in here */
  1373. /****************************************************************/
  1374. if(bAddMultiple)
  1375. break;
  1376. }
  1377. #endif // OS_WINCE
  1378. /****************************************************************/
  1379. /* Clip the mouse co-ordinates to the client area. */
  1380. /* Take care with sign extension here. */
  1381. /****************************************************************/
  1382. mouse.x = (DCINT)((DCINT16)LOWORD(lParam));
  1383. mouse.y = (DCINT)((DCINT16)HIWORD(lParam));
  1384. if (mouse.x < _IH.visibleArea.left)
  1385. {
  1386. mouse.x = _IH.visibleArea.left;
  1387. }
  1388. else if (mouse.x > _IH.visibleArea.right)
  1389. {
  1390. mouse.x = _IH.visibleArea.right;
  1391. }
  1392. if (mouse.y < _IH.visibleArea.top)
  1393. {
  1394. mouse.y = _IH.visibleArea.top;
  1395. }
  1396. else if (mouse.y > _IH.visibleArea.bottom)
  1397. {
  1398. mouse.y = _IH.visibleArea.bottom;
  1399. }
  1400. /****************************************************************/
  1401. /* Check for repeated WM_MOUSEMOVE with the same position - */
  1402. /* seen on NT4.0 under certain (unknown) conditions. */
  1403. /****************************************************************/
  1404. if ((mouse.x == _IH.lastMousePos.x) &&
  1405. (mouse.y == _IH.lastMousePos.y))
  1406. {
  1407. TRC_NRM((TB, _T("MouseMove to the same position - ignore!")));
  1408. DC_QUIT;
  1409. }
  1410. _IH.lastMousePos = mouse;
  1411. #ifdef SMART_SIZING
  1412. if (_pUi->UI_GetSmartSizing()) {
  1413. DCSIZE desktopSize;
  1414. _pUi->UI_GetDesktopSize(&desktopSize);
  1415. if (_scaleSize.width != 0 && _scaleSize.height != 0) {
  1416. pEvent->u.mouse.x = (DCINT16)(mouse.x * desktopSize.width / _scaleSize.width);
  1417. pEvent->u.mouse.y = (DCINT16)(mouse.y * desktopSize.height / _scaleSize.height);
  1418. } else {
  1419. pEvent->u.mouse.x = 0;
  1420. pEvent->u.mouse.y = 0;
  1421. }
  1422. } else {
  1423. #endif // SMART_SIZING
  1424. pEvent->u.mouse.x = (DCINT16)mouse.x;
  1425. pEvent->u.mouse.y = (DCINT16)mouse.y;
  1426. #ifdef SMART_SIZING
  1427. }
  1428. #endif // SMART_SIZING
  1429. }
  1430. break;
  1431. case WM_MOUSEWHEEL:
  1432. {
  1433. TRC_DBG((TB, _T("Mousewheel")));
  1434. pEvent->messageType = TS_INPUT_EVENT_MOUSE;
  1435. /****************************************************************/
  1436. /* Magellan Mouse - the high word of the wParam field */
  1437. /* represents the number of clicks the wheel has just turned. */
  1438. /****************************************************************/
  1439. pEvent->u.mouse.pointerFlags = TS_FLAG_MOUSE_WHEEL;
  1440. /****************************************************************/
  1441. /* Check for overflows. If the wheel delta is outside the */
  1442. /* values that can be sent by the protocol, send the maximum */
  1443. /* values. */
  1444. /****************************************************************/
  1445. if ((DCINT16)HIWORD(wParam) >
  1446. (TS_FLAG_MOUSE_ROTATION_MASK - TS_FLAG_MOUSE_DIRECTION))
  1447. {
  1448. TRC_ERR((TB, _T("Mouse wheel overflow %hd"), HIWORD(wParam)));
  1449. pEvent->u.mouse.pointerFlags |=
  1450. (TS_FLAG_MOUSE_ROTATION_MASK - TS_FLAG_MOUSE_DIRECTION);
  1451. }
  1452. else if ((DCINT16)HIWORD(wParam) < -TS_FLAG_MOUSE_DIRECTION)
  1453. {
  1454. TRC_ERR((TB, _T("Mouse wheel underflow %hd"), HIWORD(wParam)));
  1455. pEvent->u.mouse.pointerFlags |= TS_FLAG_MOUSE_DIRECTION;
  1456. }
  1457. else
  1458. {
  1459. pEvent->u.mouse.pointerFlags |=
  1460. (HIWORD(wParam) & TS_FLAG_MOUSE_ROTATION_MASK);
  1461. }
  1462. /****************************************************************/
  1463. /* Also send the middle mouse button status. */
  1464. /****************************************************************/
  1465. if ((LOWORD(wParam) & MK_MBUTTON) != 0)
  1466. {
  1467. pEvent->u.mouse.pointerFlags |= TS_FLAG_MOUSE_DOWN;
  1468. }
  1469. }
  1470. break;
  1471. case WM_LBUTTONDOWN:
  1472. case WM_LBUTTONUP:
  1473. case WM_RBUTTONDOWN:
  1474. case WM_RBUTTONUP:
  1475. case WM_MBUTTONDOWN:
  1476. case WM_MBUTTONUP:
  1477. #if !defined(OS_WINCE)
  1478. case WM_XBUTTONDOWN:
  1479. case WM_XBUTTONUP:
  1480. #endif
  1481. {
  1482. /****************************************************************/
  1483. /* Set 'priority event queued' flag. */
  1484. /****************************************************************/
  1485. TRC_DBG((TB, _T("Buttonclick")));
  1486. _IH.priorityEventsQueued = TRUE;
  1487. pEvent->messageType = TS_INPUT_EVENT_MOUSE;
  1488. /****************************************************************/
  1489. /* Clip the mouse co-ordinates to the client area. */
  1490. /* Take care with sign extension here. */
  1491. /****************************************************************/
  1492. mouse.x = (DCINT)((DCINT16)LOWORD(lParam));
  1493. mouse.y = (DCINT)((DCINT16)HIWORD(lParam));
  1494. if (mouse.x < _IH.visibleArea.left)
  1495. {
  1496. mouse.x = _IH.visibleArea.left;
  1497. }
  1498. else if (mouse.x > _IH.visibleArea.right)
  1499. {
  1500. mouse.x = _IH.visibleArea.right;
  1501. }
  1502. if (mouse.y < _IH.visibleArea.top)
  1503. {
  1504. mouse.y = _IH.visibleArea.top;
  1505. }
  1506. else if (mouse.y > _IH.visibleArea.bottom)
  1507. {
  1508. mouse.y = _IH.visibleArea.bottom;
  1509. }
  1510. /****************************************************************/
  1511. /* Save the last sent mouse position */
  1512. /****************************************************************/
  1513. _IH.lastMousePos = mouse;
  1514. #ifdef SMART_SIZING
  1515. if (_pUi->UI_GetSmartSizing()) {
  1516. DCSIZE desktopSize;
  1517. _pUi->UI_GetDesktopSize(&desktopSize);
  1518. if (_scaleSize.width != 0 && _scaleSize.height != 0) {
  1519. pEvent->u.mouse.x = (DCINT16)(mouse.x * desktopSize.width / _scaleSize.width);
  1520. pEvent->u.mouse.y = (DCINT16)(mouse.y * desktopSize.height / _scaleSize.height);
  1521. } else {
  1522. pEvent->u.mouse.x = 0;
  1523. pEvent->u.mouse.y = 0;
  1524. }
  1525. } else {
  1526. #endif // SMART_SIZING
  1527. pEvent->u.mouse.x = (DCINT16)mouse.x;
  1528. pEvent->u.mouse.y = (DCINT16)mouse.y;
  1529. #ifdef SMART_SIZING
  1530. }
  1531. #endif // SMART_SIZING
  1532. #ifdef OS_WINCE
  1533. if (!g_CEUseScanCodes)
  1534. {
  1535. // Special handling for touch screens to simulate right mouse clicks
  1536. // when the Alt key is held down. This is semi-bogus because the Alt
  1537. // key down and key up are stil sent to the terminal server.
  1538. if ((message == WM_LBUTTONDOWN ||
  1539. message == WM_LBUTTONUP ||
  1540. message == WM_LBUTTONDBLCLK) &&
  1541. (GetKeyState(VK_MENU) & 0x8000))
  1542. {
  1543. // Change the message to a RBUTTON
  1544. message += 3;
  1545. // Inject an an Alt-Up or the menu won't stay up.
  1546. tmpmsg = *inputMsg;
  1547. tmpmsg.message = WM_SYSKEYUP;
  1548. tmpmsg.wParam = VK_MENU;
  1549. tmpmsg.lParam = MAKELONG(0, MapVirtualKey(VK_MENU, 0));
  1550. addanother = TRUE;
  1551. }
  1552. }
  1553. #endif // OS_WINCE
  1554. switch (message)
  1555. {
  1556. case WM_LBUTTONDOWN:
  1557. {
  1558. pEvent->u.mouse.pointerFlags =
  1559. (TSUINT16)(_IH.leftButton | TS_FLAG_MOUSE_DOWN);
  1560. #ifdef OS_WINCE
  1561. /****************************************************************/
  1562. /* if this feature is enabled && the mouse button was down, */
  1563. /* go see if any points are available and add them to the queue */
  1564. /****************************************************************/
  1565. if( (_IH.bLMouseButtonDown) && (_IH.maxMouseMove))
  1566. {
  1567. /************************************************************************/
  1568. /* No matter what, we will always skip adding the event at the */
  1569. /* end of the loop cause we're adding it next */
  1570. /************************************************************************/
  1571. bAddMultiple = TRUE;
  1572. /************************************************************************/
  1573. /* Finish adding the WM_LBUTTONDOWN event to the pdu */
  1574. /************************************************************************/
  1575. pEvent->eventTime = _pUt->UT_GetCurrentTimeMS();
  1576. _IH.pInputPDU->numberEvents++;
  1577. TS_DATAPKT_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  1578. TS_UNCOMP_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  1579. if (!GetMouseMovePoints(apt, cpt, &cpt))
  1580. {
  1581. TRC_DBG((TB, _T("GetMouseMovePoints() failed")));
  1582. }
  1583. else
  1584. {
  1585. /****************************************************************/
  1586. /* If we only have single point, don't use addmultiple, just */
  1587. /* fall through, otherwise call the multi-event handler */
  1588. /****************************************************************/
  1589. if(cpt > 1)
  1590. {
  1591. IHAddMultipleEventsToPDU(apt, cpt);
  1592. }
  1593. }
  1594. }
  1595. #endif // OS_WINCE
  1596. }
  1597. break;
  1598. case WM_LBUTTONUP:
  1599. {
  1600. pEvent->u.mouse.pointerFlags = _IH.leftButton;
  1601. }
  1602. break;
  1603. case WM_RBUTTONDOWN:
  1604. {
  1605. pEvent->u.mouse.pointerFlags =
  1606. (TSUINT16)(_IH.rightButton | TS_FLAG_MOUSE_DOWN);
  1607. }
  1608. break;
  1609. case WM_RBUTTONUP:
  1610. {
  1611. pEvent->u.mouse.pointerFlags = _IH.rightButton;
  1612. }
  1613. break;
  1614. case WM_MBUTTONDOWN:
  1615. {
  1616. pEvent->u.mouse.pointerFlags = TS_FLAG_MOUSE_BUTTON3 |
  1617. TS_FLAG_MOUSE_DOWN;
  1618. }
  1619. break;
  1620. case WM_MBUTTONUP:
  1621. {
  1622. pEvent->u.mouse.pointerFlags = TS_FLAG_MOUSE_BUTTON3;
  1623. }
  1624. break;
  1625. #if !defined(OS_WINCE)
  1626. case WM_XBUTTONDOWN:
  1627. pEvent->u.mouse.pointerFlags = TS_FLAG_MOUSEX_DOWN;
  1628. /********************************************************/
  1629. /* Note that we drop through here */
  1630. /********************************************************/
  1631. case WM_XBUTTONUP:
  1632. {
  1633. /********************************************************/
  1634. /* For button-down, we've initialized pointerFlags in */
  1635. /* the case clause above. For button-up, pointerFlags */
  1636. /* was initialized to zero by the memset at the top of */
  1637. /* this function. */
  1638. /********************************************************/
  1639. if (!_IH.useXButtons)
  1640. {
  1641. TRC_NRM((TB, _T("Can't send this extended buttonclick")));
  1642. DC_QUIT;
  1643. }
  1644. TRC_DBG((TB, _T("Sending extended buttonclick")));
  1645. pEvent->messageType = TS_INPUT_EVENT_MOUSEX;
  1646. xButton = GET_XBUTTON_WPARAM(wParam);
  1647. switch (xButton)
  1648. {
  1649. case XBUTTON1:
  1650. {
  1651. pEvent->u.mouse.pointerFlags |=
  1652. TS_FLAG_MOUSEX_BUTTON1;
  1653. }
  1654. break;
  1655. case XBUTTON2:
  1656. {
  1657. pEvent->u.mouse.pointerFlags |=
  1658. TS_FLAG_MOUSEX_BUTTON2;
  1659. }
  1660. break;
  1661. default:
  1662. {
  1663. TRC_ALT((TB, _T("Unknown XButton %#hx"), xButton));
  1664. DC_QUIT;
  1665. }
  1666. break;
  1667. }
  1668. }
  1669. break;
  1670. #endif
  1671. }
  1672. }
  1673. break;
  1674. default:
  1675. {
  1676. /****************************************************************/
  1677. /* Invalid event */
  1678. /****************************************************************/
  1679. TRC_ALT((TB, _T("Unknown input event %#x"), message));
  1680. DC_QUIT;
  1681. }
  1682. break;
  1683. }
  1684. #ifdef OS_WINCE
  1685. /************************************************************************/
  1686. /* bAddMultiple = 1 only when IHAddMultipleEventsToPDU() is called and */
  1687. /* return true OR pEvent data is already added to the pdu */
  1688. /************************************************************************/
  1689. if(!bAddMultiple)
  1690. {
  1691. #endif
  1692. pEvent->eventTime = _pUt->UT_GetCurrentTimeMS();
  1693. /************************************************************************/
  1694. /* Bump up the packet size. */
  1695. /************************************************************************/
  1696. _IH.pInputPDU->numberEvents++;
  1697. TS_DATAPKT_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  1698. TS_UNCOMP_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  1699. #ifdef OS_WINCE
  1700. }
  1701. #endif
  1702. #ifdef OS_WINCE
  1703. /************************************************************************/
  1704. /* addanother = 1 only when g_CEUseScanCodes = 0. Needed to workaround */
  1705. /* a touch screen problem. */
  1706. /************************************************************************/
  1707. if (addanother)
  1708. {
  1709. TRC_DBG((TB, _T("Add second message")));
  1710. IHAddEventToPDU(&tmpmsg);
  1711. // If we're injecting the VK_MENU up, start ignoring the down keys.
  1712. if (tmpmsg.message == WM_SYSKEYUP && tmpmsg.wParam == VK_MENU)
  1713. {
  1714. fIgnoreMenuDown = TRUE;
  1715. }
  1716. }
  1717. #endif
  1718. DC_EXIT_POINT:
  1719. DC_END_FN();
  1720. return(rc);
  1721. } /* IHAddEventToPDU */
  1722. #ifdef OS_WINCE
  1723. /****************************************************************************/
  1724. /* Name: IHAddMultipleEventsToPDU */
  1725. /* */
  1726. /* Purpose: Add multiple mouse move events to the T.Share InputPDU packet */
  1727. /* */
  1728. /* Returns: Success TRUE / FALSE */
  1729. /* */
  1730. /* Params: IN *ppt - pointer to an array of points to send */
  1731. /* cpu - number of points to add */
  1732. /* */
  1733. /* Operation: */
  1734. /* */
  1735. /****************************************************************************/
  1736. DCBOOL DCINTERNAL CIH::IHAddMultipleEventsToPDU(POINT *ppt, int cpt)
  1737. {
  1738. PTS_INPUT_EVENT pEvent;
  1739. POINT mouse;
  1740. POINT *pptEnd, *pptTo;
  1741. DCBOOL bRet;
  1742. DC_BEGIN_FN("IHAddMultipleEventsToPDU");
  1743. bRet = TRUE;
  1744. if(cpt > 0)
  1745. {
  1746. /************************************************************************/
  1747. /* If the number of events don't fit, just abort for now */
  1748. /************************************************************************/
  1749. if( cpt > (int)(_IH.maxEventCount - _IH.pInputPDU->numberEvents))
  1750. {
  1751. /************************************************************************/
  1752. /* Send what we have and get a new buffer */
  1753. /************************************************************************/
  1754. IHMaybeSendPDU();
  1755. /************************************************************************/
  1756. /* if we have more than a full PDU Buffer, hmmm */
  1757. /************************************************************************/
  1758. if( cpt > (int)(_IH.maxEventCount))
  1759. {
  1760. /************************************************************************/
  1761. /* This will rarely, if ever, happen. When it does. clip the points to */
  1762. /* the maximum size of an empty PDU Buffer */
  1763. /************************************************************************/
  1764. cpt = (int)(_IH.maxEventCount);
  1765. }
  1766. }
  1767. pptEnd = ppt + cpt;
  1768. for (pptTo = ppt; ppt < pptEnd; ppt++)
  1769. {
  1770. mouse = *ppt;
  1771. mouse.x >>= 2;
  1772. mouse.y >>= 2;
  1773. /****************************************************************/
  1774. /* Clip the mouse co-ordinates to the client area. */
  1775. /* Take care with sign extension here. */
  1776. /****************************************************************/
  1777. if (mouse.x < _IH.visibleArea.left)
  1778. {
  1779. mouse.x = _IH.visibleArea.left;
  1780. }
  1781. else if (mouse.x > _IH.visibleArea.right)
  1782. {
  1783. mouse.x = _IH.visibleArea.right;
  1784. }
  1785. if (mouse.y < _IH.visibleArea.top)
  1786. {
  1787. mouse.y = _IH.visibleArea.top;
  1788. }
  1789. else if (mouse.y > _IH.visibleArea.bottom)
  1790. {
  1791. mouse.y = _IH.visibleArea.bottom;
  1792. }
  1793. /****************************************************************/
  1794. /* Check for repeated WM_MOUSEMOVE with the same position. */
  1795. /****************************************************************/
  1796. if ((mouse.x == _IH.lastMousePos.x) &&
  1797. (mouse.y == _IH.lastMousePos.y))
  1798. {
  1799. TRC_DBG((TB, _T("Add Multiple MouseMove to the same position - ignore!")));
  1800. }
  1801. else
  1802. {
  1803. _IH.lastMousePos = mouse;
  1804. /************************************************************************/
  1805. /* Get pointer into PDU to hold this event */
  1806. /************************************************************************/
  1807. pEvent = &(_IH.pInputPDU->eventList[_IH.pInputPDU->numberEvents]);
  1808. DC_MEMSET(pEvent, 0, sizeof(TS_INPUT_EVENT));
  1809. /************************************************************************/
  1810. /* Store the event and time */
  1811. /************************************************************************/
  1812. pEvent->u.mouse.x = (DCINT16)mouse.x;
  1813. pEvent->u.mouse.y = (DCINT16)mouse.y;
  1814. pEvent->eventTime = _pUt->UT_GetCurrentTimeMS();
  1815. pEvent->messageType = TS_INPUT_EVENT_MOUSE;
  1816. pEvent->u.mouse.pointerFlags = TS_FLAG_MOUSE_MOVE;
  1817. /************************************************************************/
  1818. /* Bump up the packet size. */
  1819. /************************************************************************/
  1820. _IH.pInputPDU->numberEvents++;
  1821. TS_DATAPKT_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  1822. TS_UNCOMP_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  1823. }
  1824. } /* end for */
  1825. }
  1826. DC_END_FN();
  1827. return bRet;
  1828. } /* IHAddMultipleEventsToPDU */
  1829. #endif //OS_WINCE
  1830. /****************************************************************************/
  1831. /* Name: IHMaybeSendPDU */
  1832. /* */
  1833. /* Purpose: Send the InputPDU packet if criteria matched */
  1834. /* */
  1835. /* Operation: Send PDU if any of the following is true: */
  1836. /* - packet is full OR */
  1837. /* - priority events (button / key /sync) are queued */
  1838. /* - the minimum send interval has elapsed */
  1839. /****************************************************************************/
  1840. DCVOID DCINTERNAL CIH::IHMaybeSendPDU(DCVOID)
  1841. {
  1842. DCUINT32 delta;
  1843. DCUINT32 timeNow;
  1844. PDCUINT8 pNewPacket;
  1845. SL_BUFHND newHandle;
  1846. POINT mousePos;
  1847. MSG msg;
  1848. DC_BEGIN_FN("IHMaybeSendPDU");
  1849. timeNow = _pUt->UT_GetCurrentTimeMS();
  1850. delta = timeNow - _IH.lastInputPDUSendTime;
  1851. TRC_DBG((TB, _T("time delta %d"), delta));
  1852. #ifdef OS_WIN32
  1853. /************************************************************************/
  1854. /* If we're pending a button-down, we have to wait until */
  1855. /* IH_PENDMOUSE_DELAY has elapsed before sending. However, we override */
  1856. /* this and send the packet if it is full (we don't want to throw */
  1857. /* events away). */
  1858. /************************************************************************/
  1859. if ((_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95) &&
  1860. _IH.pendMouseDown)
  1861. {
  1862. if (((timeNow - _IH.mouseDownTime) < IH_PENDMOUSE_DELAY) &&
  1863. (_IH.pInputPDU->numberEvents < _IH.maxEventCount))
  1864. {
  1865. TRC_DBG((TB, _T("Not sending input - pendMouseDown is set")));
  1866. DC_QUIT;
  1867. }
  1868. else
  1869. {
  1870. TRC_DBG((TB, _T("Clearing pendMouseDown")));
  1871. _IH.pendMouseDown = FALSE;
  1872. if (_IH.pendMouseTimer != 0)
  1873. {
  1874. KillTimer(_IH.inputCaptureWindow, _IH.pendMouseTimer);
  1875. }
  1876. }
  1877. }
  1878. #endif
  1879. /************************************************************************/
  1880. /* See if we need to send a keep-alive. */
  1881. /************************************************************************/
  1882. if ((_IH.keepAliveInterval != 0) && !_IH.priorityEventsQueued &&
  1883. (delta > _IH.keepAliveInterval))
  1884. {
  1885. TRC_NRM((TB, _T("Keep-alive required")));
  1886. /********************************************************************/
  1887. /* Send a move move to the current mouse co-ordinate. */
  1888. /********************************************************************/
  1889. GetCursorPos(&mousePos);
  1890. #ifdef OS_WIN32
  1891. if (!ScreenToClient(_IH.inputCaptureWindow, &mousePos))
  1892. {
  1893. TRC_ERR((TB, _T("Cannot convert mouse coordinates!")));
  1894. }
  1895. #else
  1896. ScreenToClient(_IH.inputCaptureWindow, &mousePos);
  1897. #endif /* OS_WIN32 */
  1898. /********************************************************************/
  1899. /* Prevent the 'same as last time' mouse position check from */
  1900. /* kicking in. */
  1901. /********************************************************************/
  1902. _IH.lastMousePos.x = mousePos.x + 1;
  1903. msg.message = WM_MOUSEMOVE;
  1904. msg.lParam = MAKELONG(mousePos.x, mousePos.y);
  1905. IHAddEventToPDU(&msg);
  1906. /********************************************************************/
  1907. /* Set the priority flag to force the send - also set the last send */
  1908. /* time, as if the send fails we don't want to keep adding more */
  1909. /* keepalive messages to the buffer. */
  1910. /********************************************************************/
  1911. _IH.priorityEventsQueued = TRUE;
  1912. _IH.lastInputPDUSendTime = timeNow;
  1913. }
  1914. else if (_IH.pInputPDU->numberEvents == 0)
  1915. {
  1916. TRC_DBG((TB, _T("Nothing to send")));
  1917. DC_QUIT;
  1918. }
  1919. /************************************************************************/
  1920. /* Try to send if the buffer is full, or any priority events are */
  1921. /* queued, or a minimum time has elapsed. */
  1922. /************************************************************************/
  1923. if ((_IH.pInputPDU->numberEvents >= _IH.maxEventCount) ||
  1924. (_IH.priorityEventsQueued) ||
  1925. (delta > _IH.minSendInterval))
  1926. {
  1927. /********************************************************************/
  1928. /* Only try to send if we can get another packet */
  1929. /********************************************************************/
  1930. if (_pSl->SL_GetBuffer(IH_INPUTPDU_BUFSIZE, &pNewPacket, &newHandle))
  1931. {
  1932. TRC_DBG((TB, _T("Got new buffer - send old one")));
  1933. //Flag that input was sent, for the Idle notification
  1934. //event. See UI_SetMinsToIdleTimeout()
  1935. IH_SetInputWasSentFlag(TRUE);
  1936. if (_IH.bUseFastPathInput) {
  1937. unsigned PktSize, NumEvents;
  1938. PktSize = IHTranslateInputToFastPath(&NumEvents);
  1939. _pSl->SL_SendFastPathInputPacket((BYTE FAR *)_IH.pInputPDU,
  1940. PktSize, NumEvents, _IH.bufHandle);
  1941. }
  1942. else {
  1943. _pSl->SL_SendPacket((PDCUINT8)_IH.pInputPDU,
  1944. TS_DATAPKT_LEN(_IH.pInputPDU),
  1945. RNS_SEC_ENCRYPT,
  1946. _IH.bufHandle,
  1947. _pUi->UI_GetClientMCSID(),
  1948. _pUi->UI_GetChannelID(),
  1949. TS_HIGHPRIORITY);
  1950. }
  1951. TRC_NRM((TB, _T("Sending %h messages"), _IH.pInputPDU->numberEvents));
  1952. /****************************************************************/
  1953. /* Now set the new packet up. */
  1954. /****************************************************************/
  1955. _IH.pInputPDU = (PTS_INPUT_PDU)pNewPacket;
  1956. _IH.bufHandle = newHandle;
  1957. IHInitPacket();
  1958. _IH.lastInputPDUSendTime = timeNow;
  1959. _IH.priorityEventsQueued = FALSE;
  1960. }
  1961. else
  1962. {
  1963. /****************************************************************/
  1964. /* Keep this buffer - can't get a new one. */
  1965. /****************************************************************/
  1966. TRC_ALT((TB, _T("Cannot get buffer - no Send")));
  1967. }
  1968. }
  1969. else
  1970. {
  1971. TRC_NRM((TB, _T("Don't try to send")));
  1972. }
  1973. DC_EXIT_POINT:
  1974. DC_END_FN();
  1975. } /* IHMaybeSendPDU */
  1976. /****************************************************************************/
  1977. // IHTranslateInputToFastPath
  1978. //
  1979. // Treats an InputPDU as an intermediate format and in-place translates to
  1980. // the fast-path packet format. Returns the size in bytes of the resulting
  1981. // packet and, through pNumEvents, the number of events to encode in the
  1982. // header byte (see notes on packet format in at128.h).
  1983. // TODO: Change IH to encode faster to this format if it's in use, and
  1984. // shorten path lengths for input to reduce latency.
  1985. /****************************************************************************/
  1986. unsigned DCINTERNAL CIH::IHTranslateInputToFastPath(unsigned *pNumEvents)
  1987. {
  1988. unsigned i, NumEvents;
  1989. unsigned PktLen;
  1990. BYTE FAR *pCurEncode;
  1991. DC_BEGIN_FN("IHTranslateInputToFastPath");
  1992. pCurEncode = (BYTE FAR *)_IH.pInputPDU;
  1993. PktLen = 0;
  1994. // To encode in-place over the current contents of the InputPDU, we need
  1995. // to pull needed info from the header which will be the first
  1996. // overwritten.
  1997. NumEvents = _IH.pInputPDU->numberEvents;
  1998. TRC_ASSERT((NumEvents < 256),(TB,_T("Too many input events for byte size")));
  1999. // First, if we have only 4 bits' worth for the number of events, we get
  2000. // to encode the number of events into TS_INPUT_FASTPATH_NUMEVENTS_MASK
  2001. // in the first byte, saving a byte very often. Otherwise, we need to
  2002. // encode 0 in those bits, and create a NumEvents byte as the only input
  2003. // header byte.
  2004. if (NumEvents < 16) {
  2005. *pNumEvents = NumEvents;
  2006. }
  2007. else {
  2008. *pCurEncode++ = (BYTE)NumEvents;
  2009. PktLen++;
  2010. *pNumEvents = 0;
  2011. }
  2012. // Next, re-encode each event into its bytestream format (see at128.h).
  2013. for (i = 0; i < NumEvents; i++) {
  2014. switch (_IH.pInputPDU->eventList[i].messageType) {
  2015. case TS_INPUT_EVENT_SCANCODE:
  2016. // Use a mask, shift, and OR to avoid branches for the
  2017. // extended flags.
  2018. *pCurEncode = (BYTE)(TS_INPUT_FASTPATH_EVENT_KEYBOARD |
  2019. ((_IH.pInputPDU->eventList[i].u.key.keyboardFlags &
  2020. (TS_KBDFLAGS_EXTENDED | TS_KBDFLAGS_EXTENDED1)) >> 7));
  2021. if (_IH.pInputPDU->eventList[i].u.key.keyboardFlags &
  2022. TS_KBDFLAGS_RELEASE)
  2023. *pCurEncode |= TS_INPUT_FASTPATH_KBD_RELEASE;
  2024. pCurEncode++;
  2025. *pCurEncode++ = (BYTE)_IH.pInputPDU->eventList[i].u.key.keyCode;
  2026. PktLen += 2;
  2027. break;
  2028. case TS_INPUT_EVENT_VKPACKET:
  2029. // Use a mask, shift, and OR to avoid branches for the
  2030. // extended flags.
  2031. *pCurEncode = (BYTE)(TS_INPUT_FASTPATH_EVENT_VKPACKET |
  2032. ((_IH.pInputPDU->eventList[i].u.key.keyboardFlags &
  2033. (TS_KBDFLAGS_EXTENDED | TS_KBDFLAGS_EXTENDED1)) >> 7));
  2034. if (_IH.pInputPDU->eventList[i].u.key.keyboardFlags &
  2035. TS_KBDFLAGS_RELEASE)
  2036. *pCurEncode |= TS_INPUT_FASTPATH_KBD_RELEASE;
  2037. pCurEncode++;
  2038. //
  2039. // Need two bytes for the unicode character
  2040. //
  2041. memcpy(pCurEncode, &_IH.pInputPDU->eventList[i].u.key.keyCode,
  2042. sizeof(TSUINT16));
  2043. pCurEncode+=2;
  2044. PktLen += 3;
  2045. break;
  2046. case TS_INPUT_EVENT_MOUSE:
  2047. case TS_INPUT_EVENT_MOUSEX:
  2048. *pCurEncode++ = (BYTE)(_IH.pInputPDU->eventList[i].messageType ==
  2049. TS_INPUT_EVENT_MOUSE ? TS_INPUT_FASTPATH_EVENT_MOUSE :
  2050. TS_INPUT_FASTPATH_EVENT_MOUSEX);
  2051. memcpy(pCurEncode, &_IH.pInputPDU->eventList[i].u.mouse,
  2052. sizeof(TS_POINTER_EVENT));
  2053. pCurEncode += sizeof(TS_POINTER_EVENT);
  2054. PktLen += 1 + sizeof(TS_POINTER_EVENT);
  2055. break;
  2056. case TS_INPUT_EVENT_SYNC:
  2057. *pCurEncode++ = (BYTE)(TS_INPUT_FASTPATH_EVENT_SYNC |
  2058. (_IH.pInputPDU->eventList[i].u.sync.toggleFlags &
  2059. TS_INPUT_FASTPATH_FLAGS_MASK));
  2060. PktLen++;
  2061. break;
  2062. }
  2063. }
  2064. DC_END_FN();
  2065. return PktLen;
  2066. }
  2067. /****************************************************************************/
  2068. /* Name: IHSync */
  2069. /* */
  2070. /* Purpose: Synchronize Input Handler */
  2071. /* */
  2072. /* Operation: Only sync if the packet is empty. */
  2073. /* Query the keyboard and mouse state. */
  2074. /****************************************************************************/
  2075. DCVOID DCINTERNAL CIH::IHSync(DCVOID)
  2076. {
  2077. TS_INPUT_EVENT * pEvent;
  2078. MSG msg;
  2079. POINT mousePos;
  2080. DC_BEGIN_FN("IHSync");
  2081. TRC_DBG((TB,_T("IHSync dwMod: 0x%x"), _IH.dwModifierKeyState));
  2082. /************************************************************************/
  2083. /* Only send a sync if the packet is empty (i.e. any outstanding */
  2084. /* packet has been sent successfully). */
  2085. /************************************************************************/
  2086. if (_IH.pInputPDU->numberEvents > 0)
  2087. {
  2088. TRC_NRM((TB, _T("Cannot sync as the packet is not empty")));
  2089. _IH.syncRequired = TRUE;
  2090. DC_QUIT;
  2091. }
  2092. //
  2093. // Inject a Tab-up (the official clear-menu highlighting key because it
  2094. // happens normally when alt-tabbing) before we sync. That way if
  2095. // we thought the alt key was down when we sync, the server injected
  2096. // alt up won't highlight the menu
  2097. //
  2098. IHInjectVKey(WM_SYSKEYUP, VK_TAB);
  2099. /************************************************************************/
  2100. /* Add the Sync event, setting toggles for CapsLock, NumLock and */
  2101. /* ScrollLock. */
  2102. /************************************************************************/
  2103. TRC_DBG((TB, _T("Add sync event")));
  2104. pEvent = &(_IH.pInputPDU->eventList[_IH.pInputPDU->numberEvents]);
  2105. DC_MEMSET(pEvent, 0, sizeof(TS_INPUT_EVENT));
  2106. pEvent->messageType = TS_INPUT_EVENT_SYNC;
  2107. pEvent->eventTime = _pUt->UT_GetCurrentTimeMS();
  2108. pEvent->u.sync.toggleFlags = 0;
  2109. if (GetKeyState(VK_CAPITAL) & IH_KEYSTATE_TOGGLED)
  2110. {
  2111. TRC_DBG((TB, _T("Sync Event: set CapsLock flag")));
  2112. pEvent->u.sync.toggleFlags |= TS_SYNC_CAPS_LOCK;
  2113. }
  2114. _IH.NumLock = FALSE;
  2115. if (GetKeyState(VK_NUMLOCK) & IH_KEYSTATE_TOGGLED)
  2116. {
  2117. TRC_DBG((TB, _T("Sync Event: set Numlock flag")));
  2118. pEvent->u.sync.toggleFlags |= TS_SYNC_NUM_LOCK;
  2119. _IH.NumLock = TRUE;
  2120. }
  2121. if (GetKeyState(VK_SCROLL) & IH_KEYSTATE_TOGGLED)
  2122. {
  2123. TRC_DBG((TB, _T("Sync Event: set ScrollLock flag")));
  2124. pEvent->u.sync.toggleFlags |= TS_SYNC_SCROLL_LOCK;
  2125. }
  2126. #if defined(OS_WIN32)
  2127. if (JAPANESE_KBD_LAYOUT(_pCc->_ccCombinedCapabilities.inputCapabilitySet.keyboardLayout))
  2128. {
  2129. if (GetKeyState(VK_KANA) & IH_KEYSTATE_TOGGLED)
  2130. {
  2131. TRC_DBG((TB, _T("Sync Event: set KanaLock flag")));
  2132. pEvent->u.sync.toggleFlags |= TS_SYNC_KANA_LOCK;
  2133. }
  2134. }
  2135. #endif // OS_WIN32
  2136. _IH.pInputPDU->numberEvents++;
  2137. TS_DATAPKT_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  2138. TS_UNCOMP_LEN(_IH.pInputPDU) += sizeof(TS_INPUT_EVENT);
  2139. /************************************************************************/
  2140. /* Construct dummy message for IHAddEventToPDU. */
  2141. /************************************************************************/
  2142. msg.hwnd = NULL;
  2143. msg.lParam = 0;
  2144. msg.wParam = 0;
  2145. #ifdef OS_WINNT
  2146. /************************************************************************/
  2147. /* Initialize the state of the Shift, Win, Alt & Ctrl keys to up. */
  2148. /************************************************************************/
  2149. TRC_DBG((TB,_T("IHSync reset modifier pre:0x%x"), _IH.dwModifierKeyState));
  2150. _IH.dwModifierKeyState = 0;
  2151. #endif
  2152. /************************************************************************/
  2153. // Send the current state of left and right Ctrl, Alt, and Shift keys.
  2154. // Because MapVirtualKey() returns the same scancode for right-Ctrl and
  2155. // right-Alt as for the left keys, we map right-Ctrl and Alt keys using
  2156. // the left-side key scancodes and set the Extended flag. Right-Shift
  2157. // has a distinct scancode, 0x36, which we use directly since CE and
  2158. // Win9x don't map that value. Win16 does not allow querying of
  2159. // left and right states at all, so at the top of this file we define
  2160. // the left-keys to be the "both" keys, and do not send distinct
  2161. // codes to the server. We're stuck with a keystate bug for that client.
  2162. //
  2163. // Win9x doesn't support querying for L/Rkeys so we just check for
  2164. // Ctrl,Alt,Shift wihtout distinguishing L/R versions
  2165. // There is a single outer branch for the platform check...this means
  2166. // the code is duplicated but the single branch is better for performance.
  2167. //
  2168. /************************************************************************/
  2169. if(_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_NT)
  2170. {
  2171. #define IH_RSHIFT_SCANCODE 0x36
  2172. if (GetKeyState(VK_LSHIFT) & IH_KEYSTATE_DOWN) {
  2173. TRC_DBG((TB, _T("Add left-Shift down event")));
  2174. IHInjectVKey(WM_KEYDOWN, VK_SHIFT);
  2175. _IH.dwModifierKeyState |= IH_LSHIFT_DOWN;
  2176. }
  2177. if (GetKeyState(VK_RSHIFT) & IH_KEYSTATE_DOWN) {
  2178. TRC_DBG((TB, _T("Add right-Shift down event")));
  2179. IHInjectKey(WM_KEYDOWN, VK_RSHIFT, (UINT16)IH_RSHIFT_SCANCODE);
  2180. _IH.dwModifierKeyState |= IH_RSHIFT_DOWN;
  2181. }
  2182. if (GetKeyState(VK_LCONTROL) & IH_KEYSTATE_DOWN) {
  2183. TRC_DBG((TB, _T("Add left-Ctrl down event")));
  2184. IHInjectVKey(WM_KEYDOWN, VK_CONTROL);
  2185. #ifdef OS_WINNT
  2186. _IH.dwModifierKeyState |= IH_LCTRL_DOWN;
  2187. #endif
  2188. }
  2189. if (GetKeyState(VK_RCONTROL) & IH_KEYSTATE_DOWN) {
  2190. TRC_DBG((TB, _T("Add right-Ctrl down event")));
  2191. IHInjectKey(WM_KEYDOWN, VK_RCONTROL,
  2192. (UINT16)(MapVirtualKey(VK_CONTROL, 0) | KF_EXTENDED));
  2193. #ifdef OS_WINNT
  2194. _IH.dwModifierKeyState |= IH_RCTRL_DOWN;
  2195. #endif
  2196. }
  2197. if (GetKeyState(VK_LMENU) & IH_KEYSTATE_DOWN) {
  2198. TRC_DBG((TB, _T("Add left-ALT down event")));
  2199. IHInjectVKey(WM_KEYDOWN, VK_MENU);
  2200. #ifdef OS_WINNT
  2201. _IH.dwModifierKeyState |= IH_LALT_DOWN;
  2202. #endif
  2203. }
  2204. if (GetKeyState(VK_RMENU) & IH_KEYSTATE_DOWN) {
  2205. TRC_DBG((TB, _T("Add right-ALT down event")));
  2206. IHInjectKey(WM_KEYDOWN, VK_RMENU,
  2207. (UINT16)(MapVirtualKey(VK_MENU, 0) | KF_EXTENDED));
  2208. #ifdef OS_WINNT
  2209. _IH.dwModifierKeyState |= IH_RALT_DOWN;
  2210. #endif
  2211. }
  2212. }
  2213. else
  2214. {
  2215. //Win9X version
  2216. if (GetKeyState(VK_SHIFT) & IH_KEYSTATE_DOWN) {
  2217. TRC_DBG((TB, _T("Add Shift down event")));
  2218. IHInjectVKey(WM_KEYDOWN, VK_SHIFT);
  2219. _IH.dwModifierKeyState |= IH_LSHIFT_DOWN;
  2220. }
  2221. if (GetKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN) {
  2222. TRC_DBG((TB, _T("Add Ctrl down event")));
  2223. IHInjectVKey(WM_KEYDOWN, VK_CONTROL);
  2224. #ifdef OS_WINNT
  2225. //
  2226. // Can't distinguish on 9x so assume left
  2227. // logic keeps every self-consistent with
  2228. // our assumption
  2229. //
  2230. _IH.dwModifierKeyState |= IH_LCTRL_DOWN;
  2231. #endif
  2232. }
  2233. if (GetKeyState(VK_MENU) & IH_KEYSTATE_DOWN) {
  2234. TRC_DBG((TB, _T("Add ALT down event")));
  2235. IHInjectVKey(WM_KEYDOWN, VK_MENU);
  2236. #ifdef OS_WINNT
  2237. //
  2238. // Can't distinguish on 9x so assume left
  2239. // logic keeps every self-consistent with
  2240. // our assumption
  2241. //
  2242. _IH.dwModifierKeyState |= IH_LALT_DOWN;
  2243. #endif
  2244. }
  2245. }
  2246. // Inject a tab up to prevent menu highlighting
  2247. // in case the user switches to mstsc with the key down and
  2248. // immediately releases it
  2249. TRC_DBG((TB, _T("Add Tab up event")));
  2250. IHInjectVKey(WM_SYSKEYUP, VK_TAB);
  2251. #if defined(OS_WIN32)
  2252. if (JAPANESE_KBD_LAYOUT(_pCc->_ccCombinedCapabilities.inputCapabilitySet.keyboardLayout))
  2253. {
  2254. if (GetKeyState(VK_KANA) & IH_KEYSTATE_TOGGLED)
  2255. {
  2256. TRC_DBG((TB, _T("Add Kana down event")));
  2257. IHInjectVKey(WM_KEYDOWN, VK_KANA);
  2258. }
  2259. }
  2260. #endif // OS_WIN32
  2261. /************************************************************************/
  2262. /* Get the mouse position; convert to window coordinates. */
  2263. /************************************************************************/
  2264. GetCursorPos(&mousePos);
  2265. #ifdef OS_WIN32
  2266. if (!ScreenToClient(_IH.inputCaptureWindow, &mousePos))
  2267. {
  2268. TRC_ERR((TB, _T("Cannot convert mouse coordinates!")));
  2269. }
  2270. #else
  2271. ScreenToClient(_IH.inputCaptureWindow, &mousePos);
  2272. #endif /* OS_WIN32 */
  2273. /************************************************************************/
  2274. /* Get the mouse position. */
  2275. /* NOTE: do not send the mouse button state - when the focus is */
  2276. /* regained we will either get a mouse click message immediately after */
  2277. /* the focus change, or we do not want to send a down click. */
  2278. /************************************************************************/
  2279. TRC_DBG((TB, _T("Add mouse move event")));
  2280. msg.message = WM_MOUSEMOVE;
  2281. msg.lParam = MAKELONG(mousePos.x, mousePos.y);
  2282. IHAddEventToPDU(&msg);
  2283. /************************************************************************/
  2284. /* Sets the mouse to ignore the client handedness settings. */
  2285. /************************************************************************/
  2286. IHSetMouseHandedness();
  2287. /************************************************************************/
  2288. /* Send them. Ignore failure - this will be sent later. */
  2289. /************************************************************************/
  2290. _IH.priorityEventsQueued = TRUE;
  2291. IHMaybeSendPDU();
  2292. _IH.syncRequired = FALSE;
  2293. _IH.focusSyncRequired = FALSE;
  2294. DC_EXIT_POINT:
  2295. DC_END_FN();
  2296. } /* IHSync */
  2297. /****************************************************************************/
  2298. /* Name: IHInitPacket */
  2299. /* */
  2300. /* Purpose: Initialize an InputPDU packet */
  2301. /****************************************************************************/
  2302. DCVOID DCINTERNAL CIH::IHInitPacket(DCVOID)
  2303. {
  2304. DC_BEGIN_FN("IHInitPacket");
  2305. /************************************************************************/
  2306. /* Initialize the InputPDU packet header (with 0 events) */
  2307. /************************************************************************/
  2308. DC_MEMSET(_IH.pInputPDU, 0, TS_INPUTPDU_SIZE);
  2309. _IH.pInputPDU->shareDataHeader.shareControlHeader.pduType =
  2310. TS_PROTOCOL_VERSION | TS_PDUTYPE_DATAPDU;
  2311. _IH.pInputPDU->shareDataHeader.shareControlHeader.pduSource =
  2312. _pUi->UI_GetClientMCSID();
  2313. /************************************************************************/
  2314. /* Note: this packet contains zero input events. */
  2315. /************************************************************************/
  2316. TS_DATAPKT_LEN(_IH.pInputPDU) = TS_INPUTPDU_SIZE;
  2317. _IH.pInputPDU->shareDataHeader.shareID = _pUi->UI_GetShareID();
  2318. _IH.pInputPDU->shareDataHeader.streamID = TS_STREAM_LOW;
  2319. TS_UNCOMP_LEN(_IH.pInputPDU) = TS_INPUTPDU_UNCOMP_LEN;
  2320. _IH.pInputPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_INPUT;
  2321. _IH.pInputPDU->numberEvents = 0;
  2322. DC_END_FN();
  2323. } /* IHInitPacket */
  2324. /****************************************************************************/
  2325. /* Name: IHDiscardMsg */
  2326. /* */
  2327. /* Purpose: Discard an input event */
  2328. /* */
  2329. /* Params: IN pMsg - input event */
  2330. /* */
  2331. /* Operation: Called either when the InputPDU is full, or when IH has not */
  2332. /* yet allocated an InputPDU. */
  2333. /* Beep and flash the window if a key/button press is discarded. */
  2334. /****************************************************************************/
  2335. DCVOID DCINTERNAL CIH::IHDiscardMsg(PMSG pMsg)
  2336. {
  2337. DC_BEGIN_FN("IHDiscardMsg");
  2338. if(!pMsg)
  2339. {
  2340. return;
  2341. }
  2342. switch (pMsg->message)
  2343. {
  2344. case WM_MOUSEMOVE:
  2345. case WM_MOUSEWHEEL:
  2346. {
  2347. /****************************************************************/
  2348. /* Don't set 'sync required' as the keyboard state is OK and */
  2349. /* the mouse position doesn't matter. */
  2350. /****************************************************************/
  2351. TRC_NRM((TB, _T("Discard mouse move (message %#x)"), pMsg->message));
  2352. }
  2353. break;
  2354. case WM_LBUTTONDOWN:
  2355. case WM_RBUTTONDOWN:
  2356. case WM_MBUTTONDOWN:
  2357. case WM_KEYDOWN:
  2358. case WM_SYSKEYDOWN:
  2359. {
  2360. /****************************************************************/
  2361. /* Flash the window and Beep. Set the sync required flag. */
  2362. /****************************************************************/
  2363. TRC_ERR((TB, _T("Discard button/key press (message %#x)"),
  2364. pMsg->message));
  2365. #ifndef OS_WINCE
  2366. FlashWindow(_pUi->UI_GetUIMainWindow(), TRUE);
  2367. #endif // OS_WINCE
  2368. MessageBeep((UINT)-1);
  2369. #ifndef OS_WINCE
  2370. FlashWindow(_pUi->UI_GetUIMainWindow(), FALSE);
  2371. #endif // OS_WINCE
  2372. _IH.syncRequired = TRUE;
  2373. }
  2374. break;
  2375. case WM_LBUTTONUP:
  2376. case WM_RBUTTONUP:
  2377. case WM_MBUTTONUP:
  2378. case WM_KEYUP:
  2379. case WM_SYSKEYUP:
  2380. {
  2381. /****************************************************************/
  2382. /* Don't beep, but set the sync required flag. */
  2383. /****************************************************************/
  2384. TRC_ERR((TB, _T("Discard button/key release (message %#x)"),
  2385. pMsg->message));
  2386. _IH.syncRequired = TRUE;
  2387. }
  2388. break;
  2389. case WM_TIMER:
  2390. {
  2391. // Ignore - no need to trace
  2392. }
  2393. break;
  2394. default:
  2395. {
  2396. /****************************************************************/
  2397. /* Should only get input and timer messages here. */
  2398. /****************************************************************/
  2399. TRC_ASSERT(IH_IS_INPUTEVENT(pMsg->message),
  2400. (TB, _T("Internal Error: %#x should be an input message"),
  2401. pMsg->message));
  2402. }
  2403. break;
  2404. }
  2405. DC_END_FN();
  2406. } /* IHDiscardMsg */
  2407. /****************************************************************************/
  2408. /* Name: IHSetMouseHandedness */
  2409. /* */
  2410. /* Purpose: Ensures that mouse handedness is independent from client */
  2411. /* setting. */
  2412. /* */
  2413. /* Operation: Calls GetSystemMetrics to see if mouse buttons are "swapped" */
  2414. /* and sets the values of leftButton and rightButton accordingly */
  2415. /****************************************************************************/
  2416. DCVOID DCINTERNAL CIH::IHSetMouseHandedness(DCVOID)
  2417. {
  2418. DC_BEGIN_FN("IHSetMouseHandedness");
  2419. TRC_NRM((TB, _T("Attempting to set mouse handedness")));
  2420. #ifndef OS_WINCE
  2421. if ((GetSystemMetrics(SM_SWAPBUTTON)) != 0)
  2422. {
  2423. TRC_DBG((TB, _T("Mouse set to left handedness")));
  2424. _IH.leftButton = TS_FLAG_MOUSE_BUTTON2;
  2425. _IH.rightButton = TS_FLAG_MOUSE_BUTTON1;
  2426. }
  2427. else
  2428. #endif // OS_WINCE
  2429. {
  2430. TRC_DBG((TB, _T("Mouse set to right handedness")));
  2431. _IH.leftButton = TS_FLAG_MOUSE_BUTTON1;
  2432. _IH.rightButton = TS_FLAG_MOUSE_BUTTON2;
  2433. }
  2434. DC_END_FN();
  2435. } /* IHSetMouseHandeness */
  2436. /****************************************************************************/
  2437. /* Name: IHCheckForHotkey */
  2438. /* */
  2439. /* Purpose: Handle hotkey sequences */
  2440. /* */
  2441. /* Returns: TRUE - hotkey sequence found and processed */
  2442. /* FALSE - not a hotkey sequence */
  2443. /* */
  2444. /* Params: pMsg - the message received */
  2445. /****************************************************************************/
  2446. DCBOOL DCINTERNAL CIH::IHCheckForHotkey(PMSG pMsg)
  2447. {
  2448. DCBOOL rc = TRUE;
  2449. DCBOOL isExtended;
  2450. DC_BEGIN_FN("IHCheckForHotkey");
  2451. //
  2452. // Handle hotkeys. On entry to this function
  2453. // - we have determined that
  2454. // - this is a SYSKEYDOWN message
  2455. // - the Alt key is down
  2456. // - an Alt-down message has been sent to the Server
  2457. //
  2458. TRC_DBG((TB, _T("Check VK %#x for hotkey"), pMsg->wParam));
  2459. if (! _pUt->UT_IsNEC98platform())
  2460. {
  2461. isExtended = HIWORD(pMsg->lParam) & KF_EXTENDED;
  2462. }
  2463. else
  2464. {
  2465. isExtended = TRUE;
  2466. }
  2467. //
  2468. // Always check for the Ctrl-Alt-Del sequence, even if keyboard hooking
  2469. //
  2470. if (isExtended && (GetKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN) &&
  2471. (pMsg->wParam == _IH.pHotkey->ctlrAltdel))
  2472. {
  2473. //
  2474. // Ctrl-Alt-Del hotkey
  2475. //
  2476. DCUINT16 scancode;
  2477. TRC_NRM((TB, _T("Ctrl-Alt-Del hotkey")));
  2478. scancode = (DCUINT16)MapVirtualKey(VK_DELETE, 0);
  2479. if (_pUt->UT_IsNEC98platform() &&
  2480. _pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_NT)
  2481. {
  2482. scancode |= KF_EXTENDED;
  2483. }
  2484. else if (_pUt->UT_IsNX98Key())
  2485. {
  2486. scancode |= KF_EXTENDED;
  2487. }
  2488. IHInjectKey(WM_KEYDOWN, VK_DELETE, scancode);
  2489. IHInjectKey(WM_KEYUP, VK_DELETE, scancode);
  2490. rc = TRUE;
  2491. DC_QUIT;
  2492. } else if (_fUseHookBypass) {
  2493. //
  2494. // Only continue processing other key substitutes if we're not using the
  2495. // powerful keyboard hooking functionality
  2496. //
  2497. rc = FALSE;
  2498. DC_QUIT;
  2499. }
  2500. if (isExtended && (pMsg->wParam == _IH.pHotkey->ctrlEsc))
  2501. {
  2502. //
  2503. // Ctrl-Esc hotkey
  2504. //
  2505. TRC_NRM((TB, _T("Ctrl-Esc hotkey")));
  2506. //
  2507. // Add a Tab-Up to switch off the Alt-key
  2508. //
  2509. IHInjectVKey(WM_SYSKEYUP, VK_TAB);
  2510. // First set the correct Alt key(s) up again.
  2511. // because win9x doesn't support GetKeyState on left/right
  2512. if (_IH.dwModifierKeyState & IH_LALT_DOWN)
  2513. {
  2514. IHInjectVKey(WM_KEYUP, VK_MENU);
  2515. }
  2516. if (_IH.dwModifierKeyState & IH_RALT_DOWN)
  2517. {
  2518. IHInjectKey(WM_KEYUP, VK_RMENU,
  2519. (UINT16)(MapVirtualKey(VK_MENU, 0) | KF_EXTENDED));
  2520. }
  2521. //
  2522. // Keep the flags up to date
  2523. //
  2524. _IH.dwModifierKeyState &= ~IH_ALT_MASK;
  2525. //
  2526. // Now send the Ctrl-Esc sequence
  2527. //
  2528. IHInjectVKey(WM_KEYDOWN, VK_CONTROL);
  2529. IHInjectVKey(WM_KEYDOWN, VK_ESCAPE);
  2530. IHInjectVKey(WM_KEYUP, VK_ESCAPE);
  2531. IHInjectVKey(WM_KEYUP, VK_CONTROL);
  2532. //
  2533. // Later, we'll received Home-up, Alt-up. Set a flag here telling
  2534. // us to discard them later.
  2535. //
  2536. _IH.fCtrlEscHotkey = TRUE;
  2537. }
  2538. else if (isExtended && (pMsg->wParam == _IH.pHotkey->altEsc))
  2539. {
  2540. //
  2541. // Alt-Esc hotkey
  2542. //
  2543. TRC_NRM((TB, _T("Alt-Esc hotkey")));
  2544. IHInjectVKey(WM_KEYDOWN, VK_ESCAPE);
  2545. IHInjectVKey(WM_KEYUP, VK_ESCAPE);
  2546. }
  2547. else if (isExtended && (pMsg->wParam == _IH.pHotkey->altTab))
  2548. {
  2549. //
  2550. // Alt-Tab hotkey
  2551. //
  2552. TRC_NRM((TB, _T("Alt-Tab hotkey")));
  2553. IHInjectVKey(WM_KEYDOWN, VK_TAB);
  2554. IHInjectVKey(WM_KEYUP, VK_TAB);
  2555. }
  2556. else if (isExtended && (pMsg->wParam == _IH.pHotkey->altShifttab))
  2557. {
  2558. //
  2559. // Alt-Shift-Tab hotkey
  2560. //
  2561. TRC_NRM((TB, _T("Alt-Shift Tab hotkey")));
  2562. IHInjectVKey(WM_KEYDOWN, VK_SHIFT);
  2563. IHInjectVKey(WM_KEYDOWN, VK_TAB);
  2564. IHInjectVKey(WM_KEYUP, VK_TAB);
  2565. IHInjectVKey(WM_KEYUP, VK_SHIFT);
  2566. }
  2567. else if (isExtended && (pMsg->wParam == _IH.pHotkey->altSpace))
  2568. {
  2569. //
  2570. // Alt-Space hotkey
  2571. //
  2572. TRC_NRM((TB, _T("Alt-Space hotkey")));
  2573. IHInjectVKey(WM_KEYDOWN, VK_SPACE);
  2574. IHInjectVKey(WM_KEYUP, VK_SPACE);
  2575. }
  2576. else if ((GetKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN) &&
  2577. (pMsg->wParam == VK_SUBTRACT))
  2578. {
  2579. BOOL bLeftCtrlDown = FALSE;
  2580. BOOL bRightCtrlDown = FALSE;
  2581. TRC_NRM((TB, _T("Alt-PrintScreen hotkey")));
  2582. //
  2583. // Alt print screen hotkey
  2584. //
  2585. // First set the correct Ctrl key(s) up again.
  2586. if (_IH.dwModifierKeyState & IH_LCTRL_DOWN) {
  2587. IHInjectVKey(WM_KEYUP, VK_CONTROL);
  2588. bLeftCtrlDown = TRUE;
  2589. }
  2590. else {
  2591. bLeftCtrlDown = FALSE;
  2592. }
  2593. if (_IH.dwModifierKeyState & IH_RCTRL_DOWN) {
  2594. IHInjectKey(WM_KEYUP, VK_RCONTROL,
  2595. (UINT16)(MapVirtualKey(VK_CONTROL, 0) | KF_EXTENDED));
  2596. bRightCtrlDown = TRUE;
  2597. }
  2598. else {
  2599. bRightCtrlDown = FALSE;
  2600. }
  2601. //
  2602. // Send the prntscreen key
  2603. // Win16 doesn't seem to map this scancode correctly
  2604. //
  2605. if (_pUt->UT_IsNEC98platform() &&
  2606. _pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95)
  2607. {
  2608. IHInjectKey(WM_SYSKEYDOWN, VK_SNAPSHOT, 0x61);
  2609. IHInjectKey(WM_SYSKEYUP, VK_SNAPSHOT, 0x61);
  2610. }
  2611. else
  2612. {
  2613. IHInjectKey(WM_SYSKEYDOWN, VK_SNAPSHOT, 0x54);
  2614. IHInjectKey(WM_SYSKEYUP, VK_SNAPSHOT, 0x54);
  2615. }
  2616. // Put the control key(s) back down (since they really are down)
  2617. if (bLeftCtrlDown)
  2618. {
  2619. IHInjectVKey(WM_KEYDOWN, VK_CONTROL);
  2620. }
  2621. if (bRightCtrlDown)
  2622. {
  2623. IHInjectKey(WM_KEYDOWN, VK_RCONTROL,
  2624. (UINT16)(MapVirtualKey(VK_CONTROL, 0) | KF_EXTENDED));
  2625. }
  2626. }
  2627. else if ((GetKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN) &&
  2628. (pMsg->wParam == VK_ADD))
  2629. {
  2630. BOOL bLeftCtrlDown = FALSE;
  2631. BOOL bLeftAltDown = FALSE;
  2632. BOOL bRightCtrlDown = FALSE;
  2633. BOOL bRightAltDown = FALSE;
  2634. TRC_NRM((TB, _T("PrintScreen hotkey")));
  2635. //
  2636. // print screen hotkey
  2637. //
  2638. // First set the Ctrl key(s) up.
  2639. if (_IH.dwModifierKeyState & IH_LCTRL_DOWN) {
  2640. IHInjectVKey(WM_KEYUP, VK_CONTROL);
  2641. bLeftCtrlDown = TRUE;
  2642. }
  2643. else {
  2644. bLeftCtrlDown = FALSE;
  2645. }
  2646. if (_IH.dwModifierKeyState & IH_RCTRL_DOWN) {
  2647. IHInjectKey(WM_KEYUP, VK_RCONTROL,
  2648. (UINT16)(MapVirtualKey(VK_CONTROL, 0) | KF_EXTENDED));
  2649. bRightCtrlDown = TRUE;
  2650. }
  2651. else {
  2652. bRightCtrlDown = FALSE;
  2653. }
  2654. // Add a Tab-Up to switch off the Alt-key.
  2655. IHInjectVKey(WM_SYSKEYUP, VK_TAB);
  2656. // Set the Alt key(s) up.
  2657. if (_IH.dwModifierKeyState & IH_LALT_DOWN) {
  2658. IHInjectVKey(WM_KEYUP, VK_MENU);
  2659. bLeftAltDown = TRUE;
  2660. }
  2661. else {
  2662. bLeftAltDown = FALSE;
  2663. }
  2664. if (_IH.dwModifierKeyState & IH_RALT_DOWN) {
  2665. IHInjectKey(WM_KEYUP, VK_RMENU,
  2666. (UINT16)(MapVirtualKey(VK_MENU, 0) | KF_EXTENDED));
  2667. bRightAltDown = TRUE;
  2668. }
  2669. else {
  2670. bRightAltDown = FALSE;
  2671. }
  2672. //
  2673. // Send the prntscreen key
  2674. // Win16 doesn't seem to map this scancode correctly
  2675. //
  2676. IHInjectKey(WM_SYSKEYDOWN, VK_SNAPSHOT, 0x54);
  2677. IHInjectKey(WM_SYSKEYUP, VK_SNAPSHOT, 0x54);
  2678. // Set the Alt key(s) down again
  2679. if (bLeftAltDown)
  2680. {
  2681. IHInjectVKey(WM_KEYDOWN, VK_MENU);
  2682. }
  2683. if (bRightAltDown)
  2684. {
  2685. IHInjectKey(WM_KEYDOWN, VK_RMENU,
  2686. (UINT16)(MapVirtualKey(VK_MENU, 0) | KF_EXTENDED));
  2687. }
  2688. // Set the Ctrl key(s) down again.
  2689. if (bLeftCtrlDown)
  2690. {
  2691. IHInjectVKey(WM_KEYDOWN, VK_CONTROL);
  2692. }
  2693. if (bRightCtrlDown)
  2694. {
  2695. IHInjectKey(WM_KEYDOWN, VK_RCONTROL,
  2696. (UINT16)(MapVirtualKey(VK_CONTROL, 0) | KF_EXTENDED));
  2697. }
  2698. }
  2699. else
  2700. {
  2701. //
  2702. // Not a hotkey we recognise
  2703. //
  2704. TRC_NRM((TB, _T("VK %x is not one of our hotkeys"), pMsg->wParam));
  2705. rc = FALSE;
  2706. }
  2707. DC_EXIT_POINT:
  2708. //
  2709. // If we've translated a hotkey, make sure the PDU is sent now.
  2710. //
  2711. if (rc)
  2712. {
  2713. TRC_NRM((TB, _T("Hotkey processed")));
  2714. _IH.priorityEventsQueued = TRUE;
  2715. IHMaybeSendPDU();
  2716. }
  2717. DC_END_FN();
  2718. return rc;
  2719. } /* IHCheckForHotkey */
  2720. #if defined(OS_WIN32)
  2721. /****************************************************************************/
  2722. /* Name: IHProcessKoreanVKHangulHanja */
  2723. /* */
  2724. /* Purpose: Fixup right-Alt/Ctrl key for Korean keyboards */
  2725. /* */
  2726. /* Returns: TRUE - event processed, continue with next event */
  2727. /* FALSE - do not continue wih next event */
  2728. /* */
  2729. /* Params: pMsg - message from Windows */
  2730. /****************************************************************************/
  2731. DCBOOL DCINTERNAL CIH::IHProcessKoreanVKHangulHanja(PWORD scancode, PWORD flags)
  2732. {
  2733. DCBOOL rc = FALSE;
  2734. if (KOREAN_KBD_LAYOUT(_pCc->_ccCombinedCapabilities.inputCapabilitySet.keyboardLayout))
  2735. {
  2736. if (_pUt->UT_IsKorean101LayoutForWin9x() &&
  2737. ((*scancode == 0x20 && (*flags & KF_EXTENDED)) || *scancode == 0))
  2738. {
  2739. // Evil hack for KOR Win95, Win95 OSR2 and Win98.
  2740. // These 101A/B/C keyboard driver have difference scan code by Right ALT key.
  2741. // This generated code is replace scan code to Windows NT's Right ALT and make extended flag.
  2742. *scancode = 0x38;
  2743. *flags |= KF_EXTENDED;
  2744. rc = TRUE;
  2745. }
  2746. else if (_pUt->UT_IsKorean101LayoutForNT351() &&
  2747. (*scancode == 0x38 || *scancode == 0x1d))
  2748. {
  2749. // Evil hack for KOR Windows NT ver 3.51
  2750. // These 101A/B keyboard driver doen't have extended flag by Right ALT key.
  2751. // This generated code make extended flag.
  2752. *flags |= KF_EXTENDED;
  2753. rc = TRUE;
  2754. }
  2755. }
  2756. return rc;
  2757. }
  2758. #endif
  2759. /****************************************************************************/
  2760. /* Name: IHProcessKeyboardEvent */
  2761. /* */
  2762. /* Purpose: Handle keyboard input events from Windows */
  2763. /* */
  2764. /* Returns: TRUE - event processed, continue with next event */
  2765. /* FALSE - do not continue wih next event */
  2766. /* */
  2767. /* Params: pMsg - message from Windows */
  2768. /****************************************************************************/
  2769. DCBOOL DCINTERNAL CIH::IHProcessKeyboardEvent(PMSG pMsg)
  2770. {
  2771. DCBOOL rc = FALSE;
  2772. WORD lParamLo, lParamHi;
  2773. WORD scancode, flags;
  2774. DCBOOL fCtrlEscHotkey = FALSE;
  2775. DCBOOL fLastKeyWasMenuDown = FALSE;
  2776. DC_BEGIN_FN("IHProcessKeyboardEvent");
  2777. /************************************************************************/
  2778. /* First get some useful data */
  2779. /************************************************************************/
  2780. lParamLo = LOWORD(pMsg->lParam);
  2781. lParamHi = HIWORD(pMsg->lParam);
  2782. scancode = (WORD)(lParamHi & 0x00FF);
  2783. flags = (WORD)(lParamHi & 0xFF00);
  2784. TRC_DBG((TB, _T("%s (%#x), wParam 0x%x, lParam 0x%x Scan:0x%x A/E/U"),
  2785. pMsg->message == WM_SYSKEYDOWN ? _T("WM_SYSKEYDOWN") :
  2786. pMsg->message == WM_SYSKEYUP ? _T("WM_SYSKEYUP") :
  2787. pMsg->message == WM_KEYDOWN ? _T("WM_KEYDOWN") :
  2788. pMsg->message == WM_KEYUP ? _T("WM_KEYUP") : _T("Unknown msg"),
  2789. pMsg->message, pMsg->wParam, pMsg->lParam,
  2790. scancode, (flags & KF_ALTDOWN) != 0,
  2791. (flags & KF_EXTENDED) != 0,
  2792. (flags & KF_UP) != 0));
  2793. /************************************************************************/
  2794. /* If NumLock is on, the numeric keypad keys return VK_NUMPADx. */
  2795. /* However, if shift is pressed, they return VK_LEFT etc. Windows */
  2796. /* generates a Shift-Up and Shift-Down around these keys, so as to fake */
  2797. /* the shift state to off. Hence, if the user presses Shift-NumPad6, */
  2798. /* the following sequence is returned to the app: */
  2799. /* */
  2800. /* - VK_SHIFT down */
  2801. /* - VK_SHIFT up (generated by Windows) */
  2802. /* - VK_RIGHT down */
  2803. /* - VK_RIGHT up */
  2804. /* - VK_SHIFT down (generated by Windows) */
  2805. /* - VK_SHIFT up */
  2806. /* */
  2807. /* If we inject this sequence, the shift state is wrong at the point we */
  2808. /* inject VK_RIGHT, so it is interpreted as a '6'. In order to bypass */
  2809. /* this, we set the extended flag here. This tells Windows that the */
  2810. /* regular arrow keys were pressed, so they are interpreted correctly. */
  2811. /* */
  2812. /* None of this is necessary if we're hooking the keyboard */
  2813. /* */
  2814. /************************************************************************/
  2815. if (!_fUseHookBypass && _IH.NumLock)
  2816. {
  2817. if (((pMsg->wParam >= VK_PRIOR) && (pMsg->wParam <= VK_DOWN)) ||
  2818. ((pMsg->wParam == VK_INSERT) || (pMsg->wParam == VK_DELETE)))
  2819. {
  2820. flags |= KF_EXTENDED;
  2821. TRC_NRM((TB, _T("Set extended flag on VK %#x"), pMsg->wParam));
  2822. }
  2823. }
  2824. //
  2825. // I don't care what modifiers are down, we need to filter the "Speed
  2826. // Racer" keys if we're not using the hook so they don't go to both
  2827. // the client and the server
  2828. //
  2829. // Back, Forward, Stop, Refresh, Search, Favorites, Web/Home, Mail, Mute,
  2830. // Volume +/-, Play/Pause, Stop, Prev Track, Next Track, Media,
  2831. // My Comuputer, Calculator, Sleep
  2832. //
  2833. //
  2834. // I'm using a switch because I know these are consecutive numbers
  2835. // and I want the compiler to make me a fast little jump table
  2836. //
  2837. #ifndef OS_WINCE
  2838. switch (pMsg->wParam) {
  2839. case VK_BROWSER_BACK:
  2840. case VK_BROWSER_FORWARD:
  2841. case VK_BROWSER_REFRESH:
  2842. case VK_BROWSER_STOP:
  2843. case VK_BROWSER_SEARCH:
  2844. case VK_BROWSER_FAVORITES:
  2845. case VK_BROWSER_HOME:
  2846. case VK_VOLUME_MUTE:
  2847. case VK_VOLUME_DOWN:
  2848. case VK_VOLUME_UP:
  2849. case VK_MEDIA_NEXT_TRACK:
  2850. case VK_MEDIA_PREV_TRACK:
  2851. case VK_MEDIA_STOP:
  2852. case VK_MEDIA_PLAY_PAUSE:
  2853. case VK_LAUNCH_MAIL:
  2854. case VK_LAUNCH_MEDIA_SELECT:
  2855. case VK_LAUNCH_APP1:
  2856. case VK_LAUNCH_APP2:
  2857. case VK_SLEEP:
  2858. {
  2859. //
  2860. // This is the fix to discard speed
  2861. // racer keys when not hooking
  2862. //
  2863. if (!_fUseHookBypass) {
  2864. TRC_NRM((TB,_T("Discard Speed Racer Key: 0x%02x"),
  2865. pMsg->wParam));
  2866. DC_QUIT;
  2867. }
  2868. if (VK_SLEEP == pMsg->wParam)
  2869. {
  2870. //
  2871. // EthanZ says we should never ever send
  2872. // the sleep key to the server
  2873. //
  2874. TRC_NRM((TB, _T("Discard Sleep key")));
  2875. DC_QUIT;
  2876. }
  2877. }
  2878. break;
  2879. }
  2880. #endif OS_WINCE
  2881. #ifndef OS_WINCE
  2882. //
  2883. // Toss keys we injected back into the console.
  2884. //
  2885. //
  2886. // VK_IGNORE_VALUE is a very special hack case where we self inject
  2887. // a key back to ourselves to force win32k to do an internal keystate
  2888. // update after we regain focus. At the point we want to do a sync
  2889. //
  2890. if (pMsg->wParam == VK_IGNORE_VALUE) {
  2891. if (pMsg->message == WM_KEYDOWN && _IH.fDiscardSyncDownKey) {
  2892. // Clear the down key discard flag
  2893. _IH.fDiscardSyncDownKey = FALSE;
  2894. TRC_DBG((TB,
  2895. _T("Discarding self injected down key msg: 0x%x wP:0x%x lP:0x%x"),
  2896. pMsg->message, pMsg->wParam, pMsg->lParam));
  2897. DC_QUIT;
  2898. }
  2899. else if (pMsg->message == WM_KEYUP && _IH.fDiscardSyncUpKey) {
  2900. // Clear the UP key discard flag
  2901. _IH.fDiscardSyncUpKey = FALSE;
  2902. if (!_IH.allowBackgroundInput) {
  2903. //
  2904. // Do a modifier key fixup
  2905. //
  2906. TRC_DBG((TB,
  2907. _T("Doing modifier keystate update in response to keyhint")));
  2908. IHMaintainModifierKeyState(pMsg->wParam);
  2909. TRC_DBG((TB,
  2910. _T("Discarding self injected UP key msg: 0x%x wP:0x%x lP:0x%x"),
  2911. pMsg->message, pMsg->wParam, pMsg->lParam));
  2912. }
  2913. DC_QUIT;
  2914. }
  2915. }
  2916. //
  2917. // Toss keys we self-inject back into the console that are marked
  2918. // with an ignorevalue in EXTRAINFO. This mechanism can't be used in general
  2919. // because we attachthreadinput the UI and Input threads so the extrainfo
  2920. // state won't always be consistent. However for certain keys (specific example)
  2921. // is Windowskey+L we can get by doing it this way as we want the behavior
  2922. // of the local system getting the key.
  2923. //
  2924. if (GetMessageExtraInfo() == IH_EXTRAINFO_IGNOREVALUE) {
  2925. TRC_DBG((TB,
  2926. _T("Discarding self injected key msg: 0x%x wP:0x%x lP:0x%x"),
  2927. pMsg->message, pMsg->wParam, pMsg->lParam));
  2928. DC_QUIT;
  2929. }
  2930. #endif
  2931. if (!_IH.allowBackgroundInput) {
  2932. IHMaintainModifierKeyState(pMsg->wParam);
  2933. }
  2934. /************************************************************************/
  2935. /* Handling for (SYS)KEYUP messages */
  2936. /************************************************************************/
  2937. if ((pMsg->message == WM_KEYUP) || (pMsg->message == WM_SYSKEYUP))
  2938. {
  2939. /********************************************************************/
  2940. /* Special processing for some keys */
  2941. /********************************************************************/
  2942. switch (pMsg->wParam)
  2943. {
  2944. case VK_MENU:
  2945. {
  2946. TRC_DBG((TB, _T("VK_MENU")));
  2947. #ifdef OS_WINNT
  2948. //
  2949. // Track ALT state and fixup for possible
  2950. // incorrect assumption in IHSync
  2951. //
  2952. DCUINT cancelKey = (flags & KF_EXTENDED) ?
  2953. IH_RALT_DOWN : IH_LALT_DOWN;
  2954. if (_IH.dwModifierKeyState & cancelKey)
  2955. {
  2956. TRC_DBG((TB,_T("Cancel key: current: 0x%x cancel: 0x%X"),
  2957. _IH.dwModifierKeyState, cancelKey));
  2958. _IH.dwModifierKeyState &= (~cancelKey);
  2959. }
  2960. else if ((IH_RALT_DOWN == cancelKey &&
  2961. (_IH.dwModifierKeyState & IH_LALT_DOWN)))
  2962. {
  2963. //
  2964. // Must have made a wrong assumption in
  2965. // IH_Sync on 9x. Switch this RALT up
  2966. // to a LALT up to properly sync with
  2967. // the server.
  2968. //
  2969. TRC_DBG((TB,_T("Switch LALT to RALT")));
  2970. flags &= ~KF_EXTENDED;
  2971. _IH.dwModifierKeyState &= (~IH_LALT_DOWN);
  2972. }
  2973. else
  2974. {
  2975. // Current flags state is not consistent
  2976. // with the UP key we just received
  2977. TRC_ERR((TB,
  2978. _T("ALT up without previous down (E:%d,dwModifierKeyState:0x%x"),
  2979. (flags & KF_EXTENDED),_IH.dwModifierKeyState));
  2980. }
  2981. #endif
  2982. /************************************************************/
  2983. /* If we've just processed a Ctrl-Esc hotkey, discard the */
  2984. /* trailing Alt-up */
  2985. /************************************************************/
  2986. if (_IH.fCtrlEscHotkey)
  2987. {
  2988. TRC_NRM((TB, _T("Discard Alt-up")));
  2989. DC_QUIT;
  2990. }
  2991. /************************************************************/
  2992. /* When the user uses Alt-Tab on the client we may see an */
  2993. /* Alt-Down Alt-Up with nothing in between, but is distinct */
  2994. /* because the Alt-Up is a WM_KEYUP not a WM_SYSKEY up. */
  2995. /* For this we inject an Tab-up similar to what is seen on */
  2996. /* the console for alt-tabbing to ensure the server doesn't */
  2997. /* highlight the menu */
  2998. /************************************************************/
  2999. if ((_IH.fLastKeyWasMenuDown) && (pMsg->message == WM_KEYUP))
  3000. {
  3001. // Inject our Tab-up.
  3002. IHInjectVKey(WM_SYSKEYUP, VK_TAB);
  3003. // Fall through and send the original Alt-up now.
  3004. }
  3005. }
  3006. break;
  3007. case VK_PAUSE:
  3008. {
  3009. TRC_DBG((TB, _T("VK_PAUSE")));
  3010. /************************************************************/
  3011. /* If the user presses Pause, we see VK_PAUSE without the */
  3012. /* EXTENDED flag set. Don't send this key-up - we've */
  3013. /* already completed this sequence in the key-down case. */
  3014. /************************************************************/
  3015. if (!(flags & KF_EXTENDED))
  3016. {
  3017. TRC_NRM((TB, _T("Drop VK_PAUSE Up")));
  3018. DC_QUIT;
  3019. }
  3020. }
  3021. break;
  3022. #if defined(OS_WINNT)
  3023. case VK_CANCEL:
  3024. {
  3025. TRC_DBG((TB, _T("VK_CANCEL")));
  3026. if (!(flags & KF_EXTENDED))
  3027. {
  3028. if (_pUt->UT_IsNEC98platform() && _pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95) {
  3029. //
  3030. // NEC PC-98 Windows 95 platform
  3031. // If the user presses STOP key, we also see VK_CANCEL,
  3032. // Don't send this key-up - we've already completed
  3033. // this sequence in the key-down case.
  3034. //
  3035. TRC_NRM((TB, _T("Drop VK_CANCEL Up")));
  3036. DC_QUIT;
  3037. }
  3038. }
  3039. }
  3040. break;
  3041. #endif // OS_WINNT
  3042. case VK_SHIFT:
  3043. {
  3044. TRC_DBG((TB, _T("VK_SHIFT")));
  3045. #ifndef OS_WINCE // We don't want unnecessary checks for Windows CE
  3046. /************************************************************/
  3047. /* Win311 and Win9x are Evil. If a shift key is generated, */
  3048. /* it is always the RIGHT shift, regardless of which one is */
  3049. /* actually down. Here we ensure that the correct Shift-Up */
  3050. /* is sent to the Server. Ick. */
  3051. /* */
  3052. /* As far as we know, this occurs only when NumLock is on. */
  3053. /* */
  3054. /* Se the other half of this hack in the KEYDOWN case below.*/
  3055. /************************************************************/
  3056. if (((_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95) ||
  3057. (_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_31X)) &&
  3058. _IH.NumLock &&
  3059. (scancode == 0x36) &&
  3060. ((_IH.dwModifierKeyState & IH_RSHIFT_DOWN) == 0) )
  3061. {
  3062. /********************************************************/
  3063. /* Ahem. The condition is (WinEvil) and (RIGHT SHIFT */
  3064. /* UP) and (We thought it WAS up) and (NumLock is on) */
  3065. /********************************************************/
  3066. TRC_NRM((TB, _T("Evil hack: switch right to left shift")));
  3067. scancode = 0x2a;
  3068. _IH.fWinEvilShiftHack = TRUE;
  3069. }
  3070. #endif
  3071. /************************************************************/
  3072. /* If both Shift keys are pressed, then we only get one */
  3073. /* keyup message. In this case send both the 'up's. */
  3074. /************************************************************/
  3075. TRC_NRM((TB, _T("Shift up: state %x"), _IH.dwModifierKeyState & IH_SHIFT_MASK));
  3076. if (_IH.dwModifierKeyState == IH_SHIFT_MASK)
  3077. {
  3078. /************************************************************/
  3079. /* Add the two shift-up events */
  3080. /************************************************************/
  3081. pMsg->lParam = MAKELONG(lParamLo, 0x2a | flags);
  3082. IHAddEventToPDU(pMsg);
  3083. scancode = 0x36;
  3084. /************************************************************/
  3085. /* This one falls through to be added to the PDU below */
  3086. /************************************************************/
  3087. }
  3088. /****************************************************************/
  3089. /* Reset the shift state */
  3090. /****************************************************************/
  3091. _IH.dwModifierKeyState &= ~IH_SHIFT_MASK;
  3092. }
  3093. break;
  3094. #ifndef OS_WINCE
  3095. case VK_SNAPSHOT:
  3096. {
  3097. TRC_DBG((TB, _T("VK_SNAPSHOT")));
  3098. /************************************************************/
  3099. /* Some inferior operating systems put a scan code of 00 */
  3100. /************************************************************/
  3101. if ((DCUINT16)(HIWORD(pMsg->lParam) & 0x00FF) == 0) {
  3102. pMsg->lParam = MAKELONG(0, 0x54);
  3103. }
  3104. /************************************************************/
  3105. /* If Alt-Shift-PrtScr is pressed (it's an Accessability */
  3106. /* sequence), we see only PrtScr-up, no PrtScr-down. */
  3107. /* Hence, we fake a PrtScr-down here before injecting the */
  3108. /* PrtScr-up. */
  3109. /************************************************************/
  3110. TRC_NRM((TB, _T("PrtScr Up")));
  3111. if ((GetKeyState(VK_MENU) & IH_KEYSTATE_DOWN) &&
  3112. (GetKeyState(VK_SHIFT) & IH_KEYSTATE_DOWN))
  3113. {
  3114. /********************************************************/
  3115. /* Add a PrtScr-down before this Prt-Scr up */
  3116. /********************************************************/
  3117. TRC_NRM((TB, _T("Alt & Shift down")));
  3118. pMsg->message = WM_SYSKEYDOWN;
  3119. IHAddEventToPDU(pMsg);
  3120. pMsg->message = WM_SYSKEYUP;
  3121. }
  3122. }
  3123. break;
  3124. #endif
  3125. #ifdef OS_WINNT
  3126. case VK_CONTROL:
  3127. {
  3128. TRC_DBG((TB, _T("VK_CONTROL")));
  3129. //
  3130. // Track CTRL state and fixup for possible
  3131. // incorrect assumption in IHSync
  3132. //
  3133. DCUINT cancelKey = (flags & KF_EXTENDED) ?
  3134. IH_RCTRL_DOWN : IH_LCTRL_DOWN;
  3135. if (_IH.dwModifierKeyState & cancelKey)
  3136. {
  3137. _IH.dwModifierKeyState &= (~cancelKey);
  3138. }
  3139. else if ((IH_RCTRL_DOWN == cancelKey &&
  3140. (_IH.dwModifierKeyState & IH_LCTRL_DOWN)))
  3141. {
  3142. //
  3143. // Must have made a wrong assumption in
  3144. // IH_Sync on 9x. Switch this RCTRL up
  3145. // to a LCTRL up to properly sync with
  3146. // the server.
  3147. //
  3148. flags &= ~KF_EXTENDED;
  3149. _IH.dwModifierKeyState &= (~IH_LCTRL_DOWN);
  3150. }
  3151. else
  3152. {
  3153. // Current flags state is not consistent
  3154. // with the UP key we just received
  3155. TRC_ERR((TB,
  3156. _T("Ctrl up without previous down (E:%d,dwModifierKeyState:0x%x"),
  3157. (flags & KF_EXTENDED),_IH.dwModifierKeyState));
  3158. }
  3159. }
  3160. break;
  3161. #endif
  3162. case VK_HOME:
  3163. {
  3164. TRC_DBG((TB, _T("VK_HOME")));
  3165. /************************************************************/
  3166. /* Discard Home-up if we've just processed a Ctrl-Esc */
  3167. /* hotkey - but remain in this state. */
  3168. /************************************************************/
  3169. if (_IH.fCtrlEscHotkey)
  3170. {
  3171. TRC_NRM((TB, _T("Discard Home-up")));
  3172. fCtrlEscHotkey = TRUE;
  3173. DC_QUIT;
  3174. }
  3175. }
  3176. break;
  3177. #if defined(OS_WIN32)
  3178. case VK_HANGUL:
  3179. case VK_HANJA:
  3180. {
  3181. TRC_DBG((TB, _T("VK_HANGUL/VK_HANJA")));
  3182. IHProcessKoreanVKHangulHanja(&scancode, &flags);
  3183. }
  3184. break;
  3185. #endif
  3186. //
  3187. // If we're hooking keys, we might send the Windows key as
  3188. // a part of that feature.
  3189. // Only send the up if we intend to use it on the server
  3190. //
  3191. case VK_LWIN:
  3192. #ifndef OS_WINCE
  3193. if (!_fUseHookBypass) {
  3194. #else
  3195. if (!_fUseHookBypass && (g_CEConfig != CE_CONFIG_WBT)) {
  3196. #endif
  3197. DC_QUIT;
  3198. } else {
  3199. _IH.dwModifierKeyState &= ~IH_LWIN_DOWN;
  3200. }
  3201. break;
  3202. case VK_RWIN:
  3203. #ifndef OS_WINCE
  3204. if (!_fUseHookBypass) {
  3205. #else
  3206. if (!_fUseHookBypass && (g_CEConfig != CE_CONFIG_WBT)) {
  3207. #endif
  3208. DC_QUIT;
  3209. } else {
  3210. _IH.dwModifierKeyState &= ~IH_RWIN_DOWN;
  3211. }
  3212. break;
  3213. /****************************************************************/
  3214. /* No default case - default is no special processing */
  3215. /****************************************************************/
  3216. }
  3217. }
  3218. else
  3219. {
  3220. /********************************************************************/
  3221. /* Handling for (SYS)KEYDOWN messages */
  3222. /********************************************************************/
  3223. TRC_ASSERT(
  3224. ((pMsg->message == WM_KEYDOWN) || (pMsg->message == WM_SYSKEYDOWN)),
  3225. (TB, _T("Unexpected message %#x"), pMsg->message));
  3226. /********************************************************************/
  3227. /* First, weed out hotkey sequences */
  3228. /********************************************************************/
  3229. #ifdef OS_WINCE
  3230. if (g_CEConfig != CE_CONFIG_WBT)
  3231. {
  3232. #endif // OS_WINCE
  3233. if (GetKeyState(VK_MENU) & IH_KEYSTATE_DOWN)
  3234. {
  3235. if (IHCheckForHotkey(pMsg))
  3236. {
  3237. TRC_NRM((TB, _T("Hotkey processed")));
  3238. DC_QUIT;
  3239. }
  3240. }
  3241. #ifdef OS_WINCE
  3242. }
  3243. #endif // OS_WINCE
  3244. /********************************************************************/
  3245. /* Special processing per key */
  3246. /********************************************************************/
  3247. switch (pMsg->wParam)
  3248. {
  3249. case VK_MENU:
  3250. {
  3251. TRC_DBG((TB, _T("VK_MENU down")));
  3252. /************************************************************/
  3253. /* Track Alt state */
  3254. /************************************************************/
  3255. fLastKeyWasMenuDown = TRUE;
  3256. #ifdef OS_WINNT
  3257. _IH.dwModifierKeyState |= (flags & KF_EXTENDED) ?
  3258. IH_RALT_DOWN : IH_LALT_DOWN;
  3259. #endif
  3260. TRC_DBG((TB,_T("Process alt key. Mod key state: 0x%x"),
  3261. _IH.dwModifierKeyState));
  3262. }
  3263. break;
  3264. case VK_PAUSE:
  3265. {
  3266. TRC_DBG((TB, _T("VK_PAUSE down")));
  3267. /************************************************************/
  3268. /* If the user presses the Pause key, we see a VK_PAUSE */
  3269. /* without the EXTENDED flag set. We need to send */
  3270. /* Ctrl-NumLock, where the Ctrl has the EXTENDED1 flag set. */
  3271. /* */
  3272. /* If the user presses Ctrl-NumLock, we also see VK_PAUSE, */
  3273. /* but with the EXTENDED flag. We simply let this through */
  3274. /* here. */
  3275. /************************************************************/
  3276. if ((pMsg->wParam == VK_PAUSE) && !(flags & KF_EXTENDED))
  3277. {
  3278. TRC_NRM((TB, _T("Pause key from key no. 126 (Pause key)")));
  3279. #if defined(OS_WINNT)
  3280. if (! (_pUt->UT_IsNEC98platform() &&
  3281. _pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95)) {
  3282. #endif // OS_WINNT
  3283. pMsg->wParam = VK_CONTROL;
  3284. pMsg->lParam = MAKELONG(0,
  3285. MapVirtualKey(VK_CONTROL, 0) | IH_KF_EXTENDED1);
  3286. IHAddEventToPDU(pMsg);
  3287. pMsg->wParam = VK_NUMLOCK;
  3288. pMsg->lParam = MAKELONG(0, 0x45);
  3289. IHAddEventToPDU(pMsg);
  3290. pMsg->message = WM_KEYUP;
  3291. pMsg->wParam = VK_CONTROL;
  3292. pMsg->lParam = MAKELONG(0,
  3293. MapVirtualKey(VK_CONTROL, 0) | IH_KF_EXTENDED1);
  3294. IHAddEventToPDU(pMsg);
  3295. pMsg->wParam = VK_NUMLOCK;
  3296. pMsg->lParam = MAKELONG(0, 0x45);
  3297. IHAddEventToPDU(pMsg);
  3298. #if defined(OS_WINNT)
  3299. }
  3300. else {
  3301. //
  3302. // NEC PC-98 Windows 98 platform
  3303. // If the user presses STOP key, we also see VK_PAUSE,
  3304. // but WTS PC-98 keyboard layout doesn't have VK_PAUSE.
  3305. // In this case, we need to send VK_CONTROL and VK_CANCEL.
  3306. //
  3307. pMsg->wParam = VK_CONTROL;
  3308. pMsg->lParam = MAKELONG(0,
  3309. MapVirtualKey(VK_CONTROL, 0));
  3310. IHAddEventToPDU(pMsg);
  3311. pMsg->wParam = VK_CANCEL;
  3312. pMsg->lParam = MAKELONG(0, 0x60);
  3313. IHAddEventToPDU(pMsg);
  3314. pMsg->message = WM_KEYUP;
  3315. pMsg->wParam = VK_CONTROL;
  3316. pMsg->lParam = MAKELONG(0,
  3317. MapVirtualKey(VK_CONTROL, 0));
  3318. IHAddEventToPDU(pMsg);
  3319. pMsg->wParam = VK_CANCEL;
  3320. pMsg->lParam = MAKELONG(0, 0x60);
  3321. IHAddEventToPDU(pMsg);
  3322. }
  3323. #endif // OS_WINNT
  3324. /********************************************************/
  3325. /* Now that we've sent that fine key sequence we are */
  3326. /* done. */
  3327. /********************************************************/
  3328. DC_QUIT;
  3329. }
  3330. else if ((pMsg->wParam == VK_PAUSE) && (flags & KF_EXTENDED) &&
  3331. (_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95) &&
  3332. ((_IH.dwModifierKeyState & IH_CTRL_MASK) &&
  3333. (_IH.dwModifierKeyState & IH_ALT_MASK)))
  3334. {
  3335. //
  3336. // Hackery to work around Win9x problem. On Win9x a
  3337. // CTRL-ALT-NUMLOCK is received as a VK_PAUSE (Scancode 0x45)
  3338. // with the extended flag set. On NT this is received
  3339. // as a VK_NUMLOCK (also 0x45) with the extended flag set.
  3340. //
  3341. // Because of this difference in how the keys are interpreted
  3342. // numlock gets toggled on the server but not on the client
  3343. // (if running 9x). We fix that up by syncing the local state
  3344. // to match the server.
  3345. //
  3346. _IH.focusSyncRequired = TRUE;
  3347. }
  3348. }
  3349. break;
  3350. #if defined(OS_WINNT)
  3351. case VK_CANCEL:
  3352. {
  3353. TRC_DBG((TB, _T("VK_CANCEL down")));
  3354. if ((pMsg->wParam == VK_CANCEL) && !(flags & KF_EXTENDED))
  3355. {
  3356. if (_pUt->UT_IsNEC98platform() && _pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95) {
  3357. //
  3358. // NEC PC-98 Windows 95 platform
  3359. // If the user presses STOP key, we also see VK_CANCEL,
  3360. // but this platform doesn't send VK_CONTROL.
  3361. // In this case, we need to send VK_CONTROL and VK_CANCEL.
  3362. //
  3363. pMsg->wParam = VK_CONTROL;
  3364. pMsg->lParam = MAKELONG(0,
  3365. MapVirtualKey(VK_CONTROL, 0));
  3366. IHAddEventToPDU(pMsg);
  3367. pMsg->wParam = VK_CANCEL;
  3368. pMsg->lParam = MAKELONG(0, 0x60);
  3369. IHAddEventToPDU(pMsg);
  3370. pMsg->message = WM_KEYUP;
  3371. pMsg->wParam = VK_CONTROL;
  3372. pMsg->lParam = MAKELONG(0,
  3373. MapVirtualKey(VK_CONTROL, 0));
  3374. IHAddEventToPDU(pMsg);
  3375. pMsg->wParam = VK_CANCEL;
  3376. pMsg->lParam = MAKELONG(0, 0x60);
  3377. IHAddEventToPDU(pMsg);
  3378. }
  3379. /********************************************************/
  3380. /* Now that we've sent that fine key sequence we are */
  3381. /* done. */
  3382. /********************************************************/
  3383. DC_QUIT;
  3384. }
  3385. }
  3386. break;
  3387. #endif // OS_WINNT
  3388. case VK_SHIFT:
  3389. {
  3390. TRC_DBG((TB, _T("VK_SHIFT down")));
  3391. #ifndef OS_WINCE // We don't want unnecessary checks for Windows CE
  3392. /************************************************************/
  3393. /* Win311 and Win9x are Evil. If a shift key is generated, */
  3394. /* it is always the RIGHT shift, regardless of which one is */
  3395. /* actually down. Here we ensure that the correct */
  3396. /* Shift-Down is sent to the Server. Ack. */
  3397. /* */
  3398. /* As far as we know, this occurs only when NumLock is on. */
  3399. /* */
  3400. /* Se the other half of this hack in the KEYUP case above. */
  3401. /************************************************************/
  3402. if (((_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95) ||
  3403. (_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_31X)) &&
  3404. _IH.NumLock &&
  3405. (scancode == 0x36) &&
  3406. _IH.fWinEvilShiftHack )
  3407. {
  3408. /********************************************************/
  3409. /* If we're doing the hack and the right shift is going */
  3410. /* down again, switch it over to the matching left */
  3411. /* down. */
  3412. /********************************************************/
  3413. TRC_NRM((TB, _T("Evil hack (2): switch right to left shift")));
  3414. scancode = 0x2a;
  3415. _IH.fWinEvilShiftHack = FALSE;
  3416. }
  3417. #endif
  3418. /************************************************************/
  3419. /* Keep track of shift state */
  3420. /************************************************************/
  3421. #if defined(OS_WINNT)
  3422. if (scancode == 0x2a)
  3423. {
  3424. _IH.dwModifierKeyState |= IH_LSHIFT_DOWN;
  3425. }
  3426. else
  3427. {
  3428. if (_pUt->UT_IsNEC98platform() && _pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95) {
  3429. TRC_ASSERT((scancode == 0x70 || scancode == 0x7d),
  3430. (TB,_T("Unexpected scancode %#x for VK_SHIFT"),
  3431. scancode));
  3432. }
  3433. else
  3434. {
  3435. TRC_ASSERT((scancode == 0x36),
  3436. (TB,_T("Unexpected scancode %#x for VK_SHIFT"),
  3437. scancode));
  3438. }
  3439. _IH.dwModifierKeyState |= IH_RSHIFT_DOWN;
  3440. }
  3441. #endif // OS_WINNT
  3442. TRC_NRM((TB, _T("Shift down: new state %x"), _IH.dwModifierKeyState & IH_SHIFT_MASK));
  3443. }
  3444. break;
  3445. #ifdef OS_WINNT
  3446. case VK_CONTROL:
  3447. {
  3448. TRC_DBG((TB, _T("VK_CONTROL down")));
  3449. /********************************************************************/
  3450. /* Keep track of Ctrl state */
  3451. /********************************************************************/
  3452. _IH.dwModifierKeyState |= (flags & KF_EXTENDED) ?
  3453. IH_RCTRL_DOWN : IH_LCTRL_DOWN;
  3454. }
  3455. break;
  3456. #endif
  3457. #if defined(OS_WIN32)
  3458. case VK_HANGUL:
  3459. case VK_HANJA:
  3460. {
  3461. TRC_DBG((TB, _T("VK_HANGUL/VK_HANJA down")));
  3462. IHProcessKoreanVKHangulHanja(&scancode, &flags);
  3463. }
  3464. break;
  3465. #endif
  3466. #ifdef OS_WINNT
  3467. //
  3468. // If we're hooking keys, we might send the Windows key as
  3469. // a part of that feature. Originally, Citrix clients sent
  3470. // the Windows key make key and had the server ignore it
  3471. // because the client OS would eat the up (and show the Start
  3472. // menu). There's a protocol flag to make it not eat the make
  3473. // key which we turn on so we can send it, which means we'll
  3474. // need to eat the windows key make if we don't plan to send
  3475. // a windows key break
  3476. //
  3477. case VK_LWIN:
  3478. #ifndef OS_WINCE
  3479. if (!_fUseHookBypass) {
  3480. #else
  3481. if (!_fUseHookBypass && (g_CEConfig != CE_CONFIG_WBT)) {
  3482. #endif
  3483. DC_QUIT;
  3484. } else {
  3485. _IH.dwModifierKeyState |= IH_LWIN_DOWN;
  3486. }
  3487. break;
  3488. case VK_RWIN:
  3489. #ifndef OS_WINCE
  3490. if (!_fUseHookBypass) {
  3491. #else
  3492. if (!_fUseHookBypass && (g_CEConfig != CE_CONFIG_WBT)) {
  3493. #endif
  3494. DC_QUIT;
  3495. } else {
  3496. _IH.dwModifierKeyState |= IH_RWIN_DOWN;
  3497. }
  3498. break;
  3499. #endif
  3500. /****************************************************************/
  3501. /* No default case - default is no special processing */
  3502. /****************************************************************/
  3503. }
  3504. }
  3505. /************************************************************************/
  3506. /* Special processing for NUMLOCK key (on both KEYDOWN and KEYUP) */
  3507. /************************************************************************/
  3508. if (pMsg->wParam == VK_NUMLOCK)
  3509. {
  3510. /********************************************************************/
  3511. /* Keep track of its state */
  3512. /********************************************************************/
  3513. _IH.NumLock = (GetKeyState(VK_NUMLOCK) & IH_KEYSTATE_TOGGLED);
  3514. TRC_NRM((TB, _T("NumLock is %s"), _IH.NumLock ? _T("on") : _T("off")));
  3515. /********************************************************************/
  3516. /* Don't set the EXTENDED flag for NumLock - if NumLock is injected */
  3517. /* at the Server with KF_EXTENDED, it doesn't work. */
  3518. /********************************************************************/
  3519. flags &= ~KF_EXTENDED;
  3520. }
  3521. /************************************************************************/
  3522. /* Never set KF_EXTENDED for VK_PAUSE key */
  3523. /************************************************************************/
  3524. if (pMsg->wParam == VK_PAUSE)
  3525. {
  3526. TRC_DBG((TB, _T("Clear KF_EXTENDED for VK_PAUSE")));
  3527. flags &= ~KF_EXTENDED;
  3528. }
  3529. /************************************************************************/
  3530. /* Rebuild lParam before passing it to IHAddEventToPDU */
  3531. /************************************************************************/
  3532. lParamHi = (WORD)(scancode | flags);
  3533. pMsg->lParam = MAKELONG(lParamLo, lParamHi);
  3534. /************************************************************************/
  3535. /* Finally! Add the event to the PDU */
  3536. /************************************************************************/
  3537. IHAddEventToPDU(pMsg);
  3538. /************************************************************************/
  3539. /* If we get here, it's OK to look for more messages in the queue */
  3540. /************************************************************************/
  3541. rc = TRUE;
  3542. DC_EXIT_POINT:
  3543. /************************************************************************/
  3544. /* Set the new Ctrl-Esc state */
  3545. /************************************************************************/
  3546. TRC_DBG((TB, _T("New Ctrl-Esc state is %d"), fCtrlEscHotkey));
  3547. _IH.fCtrlEscHotkey = fCtrlEscHotkey;
  3548. /************************************************************************/
  3549. /* Set the new Alt-down state */
  3550. /************************************************************************/
  3551. TRC_DBG((TB, _T("New Alt-down state is %d"), fLastKeyWasMenuDown));
  3552. _IH.fLastKeyWasMenuDown = fLastKeyWasMenuDown;
  3553. TRC_DBG((TB,_T("IHProcessKeyboardEvent modifier post:0x%x"), _IH.dwModifierKeyState));
  3554. DC_END_FN();
  3555. return (rc);
  3556. } /* IHProcessKeyboardEvent */
  3557. /****************************************************************************/
  3558. /* Name: IHProcessMouseEvent */
  3559. /* */
  3560. /* Purpose: Handle mouse input events from Windows */
  3561. /* */
  3562. /* Returns: TRUE - event processed, continue with next event */
  3563. /* FALSE - do not continue wih next event */
  3564. /* */
  3565. /* Params: pMsg - message from Windows */
  3566. /****************************************************************************/
  3567. DCBOOL DCINTERNAL CIH::IHProcessMouseEvent(PMSG pMsg)
  3568. {
  3569. DCBOOL rc = TRUE;
  3570. #ifdef OS_WINCE
  3571. HANDLE hThread;
  3572. DCBOOL bRet;
  3573. #endif
  3574. DC_BEGIN_FN("IHProcessMouseEvent");
  3575. #if !defined(OS_WINCE)
  3576. TRC_NRM((TB, _T("%s (%#x), wParam %#x, lParam %#lx"),
  3577. pMsg->message == WM_MOUSEMOVE ? "WM_MOUSEMOVE" :
  3578. pMsg->message == WM_LBUTTONDOWN ? "WM_LBUTTONDOWN" :
  3579. pMsg->message == WM_RBUTTONDOWN ? "WM_RBUTTONDOWN" :
  3580. pMsg->message == WM_MBUTTONDOWN ? "WM_MBUTTONDOWN" :
  3581. pMsg->message == WM_LBUTTONUP ? "WM_LBUTTONUP" :
  3582. pMsg->message == WM_RBUTTONUP ? "WM_RBUTTONUP" :
  3583. pMsg->message == WM_MBUTTONUP ? "WM_MBUTTONUP" :
  3584. pMsg->message == WM_LBUTTONDBLCLK ? "WM_LBUTTONDBLCLK" :
  3585. pMsg->message == WM_RBUTTONDBLCLK ? "WM_RBUTTONDBLCLK" :
  3586. pMsg->message == WM_MBUTTONDBLCLK ? "WM_MBUTTONDBLCLK" :
  3587. pMsg->message == WM_MOUSEWHEEL ? "WM_MOUSEWHEEL" :
  3588. pMsg->message == WM_XBUTTONDOWN ? "WM_XBUTTONDOWN" :
  3589. pMsg->message == WM_XBUTTONUP ? "WM_XBUTTONUP" :
  3590. pMsg->message == WM_XBUTTONDBLCLK ? "WM_XBUTTONDBLCLK" :
  3591. "Unknown msg",
  3592. pMsg->message, pMsg->wParam, pMsg->lParam));
  3593. #else
  3594. TRC_NRM((TB, _T("%s (%#x), wParam %#x, lParam %#lx"),
  3595. pMsg->message == WM_MOUSEMOVE ? "WM_MOUSEMOVE" :
  3596. pMsg->message == WM_LBUTTONDOWN ? "WM_LBUTTONDOWN" :
  3597. pMsg->message == WM_RBUTTONDOWN ? "WM_RBUTTONDOWN" :
  3598. pMsg->message == WM_MBUTTONDOWN ? "WM_MBUTTONDOWN" :
  3599. pMsg->message == WM_LBUTTONUP ? "WM_LBUTTONUP" :
  3600. pMsg->message == WM_RBUTTONUP ? "WM_RBUTTONUP" :
  3601. pMsg->message == WM_MBUTTONUP ? "WM_MBUTTONUP" :
  3602. pMsg->message == WM_LBUTTONDBLCLK ? "WM_LBUTTONDBLCLK" :
  3603. pMsg->message == WM_RBUTTONDBLCLK ? "WM_RBUTTONDBLCLK" :
  3604. pMsg->message == WM_MBUTTONDBLCLK ? "WM_MBUTTONDBLCLK" :
  3605. "Unknown msg",
  3606. pMsg->message, pMsg->wParam, pMsg->lParam));
  3607. #endif
  3608. #ifdef OS_WIN32
  3609. /************************************************************************/
  3610. /* Delay sending mouse-downs until either another message arrives or */
  3611. /* IH_PENDMOUSE_DELAY elapses - only for Win95 though. */
  3612. /************************************************************************/
  3613. if (_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_95)
  3614. {
  3615. if ((pMsg->message == WM_LBUTTONDOWN) ||
  3616. (pMsg->message == WM_MBUTTONDOWN) ||
  3617. (pMsg->message == WM_RBUTTONDOWN))
  3618. {
  3619. TRC_DBG((TB, _T("Setting pendMouseDown to TRUE; ")
  3620. _T("starting pendmouse timer")));
  3621. _IH.pendMouseDown = TRUE;
  3622. _IH.mouseDownTime = _pUt->UT_GetCurrentTimeMS();
  3623. /****************************************************************/
  3624. /* This timer will kick us in 200ms to make sure we send our */
  3625. /* mouse-down. */
  3626. /****************************************************************/
  3627. _IH.pendMouseTimer = SetTimer(_IH.inputCaptureWindow,
  3628. IH_PENDMOUSE_TIMER_ID,
  3629. IH_PENDMOUSE_DELAY,
  3630. NULL);
  3631. }
  3632. else
  3633. {
  3634. TRC_DBG((TB, _T("Setting pendMouseDown to FALSE; ")
  3635. _T("killing pendmouse timer")));
  3636. _IH.pendMouseDown = FALSE;
  3637. if (_IH.pendMouseTimer != 0)
  3638. {
  3639. KillTimer(_IH.inputCaptureWindow, _IH.pendMouseTimer);
  3640. }
  3641. }
  3642. }
  3643. #endif
  3644. /************************************************************************/
  3645. /* Capture / release the mouse as required. */
  3646. /************************************************************************/
  3647. if ((pMsg->message == WM_LBUTTONDOWN) ||
  3648. (pMsg->message == WM_MBUTTONDOWN) ||
  3649. (pMsg->message == WM_RBUTTONDOWN))
  3650. {
  3651. TRC_DBG((TB, _T("Get capture")));
  3652. SetCapture(_IH.inputCaptureWindow);
  3653. }
  3654. else if ((pMsg->message == WM_LBUTTONUP) ||
  3655. (pMsg->message == WM_MBUTTONUP) ||
  3656. (pMsg->message == WM_RBUTTONUP))
  3657. {
  3658. TRC_DBG((TB, _T("Release capture")));
  3659. ReleaseCapture();
  3660. }
  3661. #ifdef OS_WINCE
  3662. if (_IH.maxMouseMove)
  3663. {
  3664. /************************************************************************/
  3665. /* Set global attribute to show LMouse Button state */
  3666. /************************************************************************/
  3667. if (pMsg->message == WM_LBUTTONDOWN)
  3668. {
  3669. TRC_DBG((TB, _T("Set MouseDown")));
  3670. _IH.bLMouseButtonDown = TRUE;
  3671. /************************************************************************/
  3672. /* Bump the thread priority so we get better mouse move data */
  3673. /************************************************************************/
  3674. hThread = GetCurrentThread();
  3675. if (NULL != hThread)
  3676. {
  3677. bRet = SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
  3678. }
  3679. }
  3680. else if (pMsg->message == WM_LBUTTONUP)
  3681. {
  3682. TRC_DBG((TB, _T("Set MouseUp")));
  3683. _IH.bLMouseButtonDown = FALSE;
  3684. /************************************************************************/
  3685. /* Reset the thread back to normal */
  3686. /************************************************************************/
  3687. hThread = GetCurrentThread();
  3688. if (NULL != hThread)
  3689. {
  3690. bRet = SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
  3691. }
  3692. }
  3693. }
  3694. #endif //OS_WINCE
  3695. /************************************************************************/
  3696. /* Add the event to the PDU */
  3697. /************************************************************************/
  3698. IHAddEventToPDU(pMsg);
  3699. /************************************************************************/
  3700. /* Always go on to look for more messages */
  3701. /************************************************************************/
  3702. rc = TRUE;
  3703. DC_END_FN();
  3704. return (rc);
  3705. } /* IHProcessMouseEvent */
  3706. #if (!defined(OS_WINCE)) || (!defined(WINCE_SDKBUILD))
  3707. /****************************************************************************/
  3708. /* Name: IHStaticLowLevelKeyboardProc */
  3709. /* */
  3710. /* Purpose: Notice keyboard input that can't be captured normally */
  3711. /* */
  3712. /* Returns: TRUE - event processed, continue with next event */
  3713. /* FALSE - do not continue wih next event */
  3714. /* */
  3715. /* Params: pMsg - message from Windows */
  3716. /****************************************************************************/
  3717. LRESULT CALLBACK CIH::IHStaticLowLevelKeyboardProc(int nCode, WPARAM wParam,
  3718. LPARAM lParam)
  3719. {
  3720. LRESULT rc;
  3721. CIH *tpIH = NULL;
  3722. DC_BEGIN_FN("CIH::IHStaticLowLevelKeyboardProc");
  3723. TRC_ASSERT(CIH::TlsIndex != 0xFFFFFFFF, (TB, _T("In hook with no TlsIndex")));
  3724. tpIH = (CIH *)TlsGetValue(CIH::TlsIndex);
  3725. TRC_ASSERT(tpIH != NULL, (TB, _T("Keyboard Hook with no tpIH")));
  3726. //
  3727. // Just call the non static one
  3728. //
  3729. rc = tpIH->IHLowLevelKeyboardProc(nCode, wParam, lParam);
  3730. DC_END_FN();
  3731. return rc;
  3732. }
  3733. /****************************************************************************/
  3734. /* Name: IHLowLevelKeyboardProc */
  3735. /* */
  3736. /* Purpose: Notice keyboard input that can't be captured normally */
  3737. /* */
  3738. /* Returns: TRUE - event processed, continue with next event */
  3739. /* FALSE - do not continue wih next event */
  3740. /* */
  3741. /* Params: pMsg - message from Windows */
  3742. /****************************************************************************/
  3743. LRESULT CIH::IHLowLevelKeyboardProc(int nCode, WPARAM wParam,
  3744. LPARAM lParam)
  3745. {
  3746. LRESULT rc = 1;
  3747. PKBDLLHOOKSTRUCT pkbdhs = NULL;
  3748. LPARAM outLParam = 0;
  3749. WORD flags = 0;
  3750. DWORD dwForegroundProcessId;
  3751. BOOL fDoDefaultKeyProcessing = TRUE;
  3752. BOOL fSelfInjectedKey = FALSE;
  3753. DC_BEGIN_FN("CIH::IHLowLevelKeyboardProc");
  3754. //
  3755. // **** Big Scary Comment ****
  3756. // This is a performance critical area. This gets run every keystroke
  3757. // in the (typically console) session, so try to organize any ifs or
  3758. // other logic to bail out quickly.
  3759. // **** End Big Scary Comment ****
  3760. //
  3761. if (nCode == HC_ACTION) {
  3762. //
  3763. // Chance to look for keys and take action
  3764. //
  3765. TRC_DBG((TB, _T("Keyboard hook called with HC_ACTION code")));
  3766. pkbdhs = (PKBDLLHOOKSTRUCT)lParam;
  3767. #ifndef OS_WINCE
  3768. TRC_DBG((TB, _T("hook vk: 0x%04x sc: 0x%04x char:(%c) A/E/U: %d/%d/%d"),
  3769. pkbdhs->vkCode,
  3770. pkbdhs->scanCode,
  3771. pkbdhs->vkCode,
  3772. (pkbdhs->flags & LLKHF_ALTDOWN) != 0,
  3773. (pkbdhs->flags & LLKHF_EXTENDED) != 0,
  3774. (pkbdhs->flags & LLKHF_UP) != 0));
  3775. #endif
  3776. GetWindowThreadProcessId( GetForegroundWindow(),
  3777. &dwForegroundProcessId);
  3778. if ((GetCurrentProcessId() == dwForegroundProcessId) &&
  3779. (GetFocus() == _IH.inputCaptureWindow)) {
  3780. fSelfInjectedKey = (pkbdhs->dwExtraInfo == IH_EXTRAINFO_IGNOREVALUE);
  3781. //
  3782. // Always discard self-injected keys
  3783. // Otherwise do special handling if we're hooking or if it's a VK_PACKET
  3784. //
  3785. // The processing will convert the pkbdhs to a message that will
  3786. // be posted to the IH's window proc for normal processing
  3787. //
  3788. if (!fSelfInjectedKey &&
  3789. (_fUseHookBypass || pkbdhs->vkCode == VK_PACKET)) {
  3790. switch (pkbdhs->vkCode) {
  3791. // Three LED keys
  3792. case VK_CAPITAL:
  3793. case VK_NUMLOCK:
  3794. case VK_SCROLL:
  3795. // Other state keys
  3796. case VK_KANA:
  3797. // Other modifiers, shift/control/alt
  3798. case VK_SHIFT:
  3799. case VK_LSHIFT:
  3800. case VK_RSHIFT:
  3801. case VK_CONTROL:
  3802. case VK_LCONTROL:
  3803. case VK_RCONTROL:
  3804. case VK_MENU:
  3805. case VK_LMENU:
  3806. case VK_RMENU:
  3807. fDoDefaultKeyProcessing = FALSE;
  3808. break;
  3809. #ifndef OS_WINCE
  3810. //
  3811. // Skip Windows+L to make sure the local console
  3812. // gets locked by that key combination
  3813. //
  3814. case VK_l: // intentional fallthru
  3815. case VK_L:
  3816. {
  3817. //
  3818. // We make sure none of the other modifiers are down
  3819. // otherwise it's not a real Windows+L hotkey
  3820. //
  3821. // Note: We can't use GetAsyncKeyState(VK_LWIN)
  3822. // because it doesn't work in a LL hook!
  3823. //
  3824. if ((_IH.dwModifierKeyState & IH_WIN_MASK) &&
  3825. !(GetAsyncKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN) &&
  3826. !(GetAsyncKeyState(VK_MENU) & IH_KEYSTATE_DOWN) &&
  3827. !(GetAsyncKeyState(VK_SHIFT) & IH_KEYSTATE_DOWN)) {
  3828. //
  3829. // WindowsKey+L must be handled locally to ensure
  3830. // the local desktop is locked so don't send to server
  3831. //
  3832. TRC_NRM((TB, _T("Hook skipping Windows+L!")));
  3833. //
  3834. // Defer the tail processing to avoid spending a
  3835. // lot of time in the hook.
  3836. //
  3837. // We only want to do the work once so on keydown.
  3838. //
  3839. if (!(pkbdhs->flags & LLKHF_UP)) {
  3840. TRC_NRM((TB, _T("Posting to process Win+L")));
  3841. PostMessage(_IH.inputCaptureWindow,
  3842. IH_WM_HANDLE_LOCKDESKTOP,
  3843. 0, 0);
  3844. }
  3845. fDoDefaultKeyProcessing = FALSE;
  3846. //
  3847. // Bail out completely to eat the 'L'
  3848. //
  3849. DC_QUIT;
  3850. }
  3851. else {
  3852. TRC_DBG((TB, _T("Normal 'l' handling will send")));
  3853. }
  3854. }
  3855. break;
  3856. #endif
  3857. case VK_DELETE:
  3858. {
  3859. TRC_DBG((TB, _T("VK_DELETE pressed 0x%x, 0x%x"),
  3860. ((GetAsyncKeyState(VK_MENU) & IH_KEYSTATE_DOWN)) != 0,
  3861. (GetAsyncKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN) != 0));
  3862. if ((GetAsyncKeyState(VK_MENU) & IH_KEYSTATE_DOWN) &&
  3863. (GetAsyncKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN)) {
  3864. //
  3865. // This is Ctrl+Alt+Del, which can't be blocked.
  3866. // Getting Two SAS sequences for this would be
  3867. // confusing, so don't send that on to the IH
  3868. //
  3869. TRC_DBG((TB, _T("Skipping VK_DELETE with Ctrl and Alt down")));
  3870. fDoDefaultKeyProcessing = FALSE;
  3871. } else {
  3872. //
  3873. // Fall through to default processing for all other
  3874. // VK_DELETE events.
  3875. //
  3876. TRC_DBG((TB, _T("Normal VK_DELETE, sending to server")));
  3877. }
  3878. }
  3879. break;
  3880. } // switch
  3881. if (fDoDefaultKeyProcessing) {
  3882. #ifndef OS_WINCE
  3883. if (pkbdhs->flags & LLKHF_EXTENDED) {
  3884. flags |= KF_EXTENDED;
  3885. }
  3886. if (pkbdhs->flags & LLKHF_ALTDOWN) {
  3887. flags |= KF_ALTDOWN;
  3888. }
  3889. if (pkbdhs->flags & LLKHF_UP) {
  3890. flags |= KF_UP;
  3891. }
  3892. if (pkbdhs->vkCode != VK_PACKET)
  3893. {
  3894. outLParam = MAKELONG(1,
  3895. ((WORD)pkbdhs->scanCode | flags));
  3896. }
  3897. else
  3898. {
  3899. outLParam = MAKELONG(1, ((WORD)pkbdhs->scanCode));
  3900. //TRC_ERR((TB,_T("VK_PACKET: scan:0x%x"),pkbdhs->scanCode));
  3901. }
  3902. #else
  3903. if ((pkbdhs->vkCode == VK_LWIN) || (pkbdhs->vkCode == VK_RWIN) || (pkbdhs->vkCode == VK_APPS)) {
  3904. flags |= KF_EXTENDED;
  3905. }
  3906. if (GetAsyncKeyState(VK_MENU) & IH_KEYSTATE_DOWN) {
  3907. flags |= KF_ALTDOWN;
  3908. }
  3909. if (wParam == WM_KEYUP) {
  3910. flags |= KF_UP;
  3911. }
  3912. if (pkbdhs->vkCode != VK_PACKET)
  3913. {
  3914. outLParam = MAKELONG(1, ((BYTE)pkbdhs->scanCode | flags));
  3915. }
  3916. else
  3917. {
  3918. outLParam = MAKELONG(1, ((BYTE)pkbdhs->scanCode));
  3919. }
  3920. #endif
  3921. #ifndef OS_WINCE
  3922. if ((pkbdhs->flags & LLKHF_UP) &&
  3923. #else
  3924. if ((wParam == WM_KEYUP) &&
  3925. #endif
  3926. BITTEST(_KeyboardState, (BYTE)pkbdhs->vkCode)) {
  3927. //
  3928. // Key was pressed when we gained the focus, let the key up
  3929. // go through.
  3930. //
  3931. TRC_DBG((TB,_T("Allowing normal keypress to update keystate table")));
  3932. BITCLEAR(_KeyboardState, (BYTE)pkbdhs->vkCode);
  3933. } else {
  3934. if (PostMessage(_IH.inputCaptureWindow, wParam,
  3935. pkbdhs->vkCode, outLParam)) {
  3936. DC_QUIT;
  3937. }
  3938. else {
  3939. TRC_SYSTEM_ERROR("PostThreadMessage in keyboard hook");
  3940. }
  3941. }
  3942. } // if fDoDefaultKeyProcessing
  3943. }
  3944. else if (fSelfInjectedKey) {
  3945. //
  3946. // Just let the system handle any self-injected keys
  3947. // Note: they could be posted to our message queue
  3948. // so we also check for the ignore flag there
  3949. //
  3950. TRC_DBG((TB,_T("Discard self injected key vk:0x%x")
  3951. _T("dwIgnore: 0x%x flags:0x%x"),
  3952. pkbdhs->vkCode,
  3953. pkbdhs->dwExtraInfo,
  3954. pkbdhs->flags));
  3955. }
  3956. else {
  3957. //
  3958. // We're not using hooks but we still leverage the hook to fix
  3959. // an alt-space problem
  3960. //
  3961. switch (pkbdhs->vkCode) {
  3962. case VK_SPACE:
  3963. if ((GetAsyncKeyState(VK_MENU) & IH_KEYSTATE_DOWN) &&
  3964. !(GetAsyncKeyState(VK_CONTROL) & IH_KEYSTATE_DOWN) &&
  3965. !(GetAsyncKeyState(VK_SHIFT) & IH_KEYSTATE_DOWN))
  3966. {
  3967. // Alt-Space!
  3968. //
  3969. // Queue a focus sync so that when the menu is dismissed
  3970. // we resync focus. (Prevents stuck alt key bug).
  3971. //
  3972. _IH.focusSyncRequired = TRUE;
  3973. }
  3974. break;
  3975. }
  3976. }
  3977. } // if current process and focus
  3978. } else {
  3979. //
  3980. // Not supposed to do anything but call the next hook
  3981. //
  3982. TRC_DBG((TB, _T("Keyboard hook called with non-HC_ACTION code")));
  3983. }
  3984. rc = CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam);
  3985. DC_EXIT_POINT:
  3986. DC_END_FN();
  3987. return rc;
  3988. }
  3989. #endif
  3990. /****************************************************************************/
  3991. /* Name: IHGatherKeyState */
  3992. /* */
  3993. /* Purpose: Once the focus is gained, no keyup sequences will be seen */
  3994. /* locally, which may causes some strange behavior. Track which */
  3995. /* keys to allow back up after gaining the focus */
  3996. /* */
  3997. /* Returns: TRUE - event processed, continue with next event */
  3998. /* FALSE - do not continue wih next event */
  3999. /* */
  4000. /* Params: pMsg - message from Windows */
  4001. /****************************************************************************/
  4002. VOID CIH::IHGatherKeyState()
  4003. {
  4004. int i;
  4005. DC_BEGIN_FN("CIH::IHGatherKeyState");
  4006. for (i = 0; i < 256; i++) {
  4007. if (GetAsyncKeyState(i) & IH_KEYSTATE_DOWN) {
  4008. BITSET(_KeyboardState, i);
  4009. } else {
  4010. BITCLEAR(_KeyboardState, i);
  4011. }
  4012. }
  4013. DC_END_FN();
  4014. }
  4015. VOID CIH::IHMaintainModifierKeyState(int vkKey)
  4016. /*
  4017. IHMaintainModifierKeyState
  4018. Purpose: Keep up the correct modifier key states by comparing our internal
  4019. state (and therefore what the server should think) with what the local
  4020. system will tell us. If these are out of sync, we should get them together
  4021. */
  4022. {
  4023. int vkShift, vkControl, vkMenu, vkWin;
  4024. // ~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
  4025. // IMPORTANT NOTE:
  4026. // When hooking is on we eat certain keys in the LL keyboard hook. In that
  4027. // case win32k does not update the keyboard state so it is not valid
  4028. // to call GetAsyncKeyState() or GetKeyState() on those keys. The prime
  4029. // example is the VK_LWIN, VK_RWIN keys that we eat to prevent double
  4030. // start menus.
  4031. //
  4032. //
  4033. // We call this thing every key stroke, so we try to use some quick
  4034. // checks to bail out early. We only have problems with modifiers getting
  4035. // stuck down, so we only make calls to the system if we think they are
  4036. // down.
  4037. //
  4038. DC_BEGIN_FN("IHMaintainModifierKeyState");
  4039. TRC_DBG((TB,_T("Maintain dwMod prev: 0x%x"), _IH.dwModifierKeyState));
  4040. switch (vkKey)
  4041. {
  4042. case VK_SHIFT:
  4043. case VK_CONTROL:
  4044. case VK_MENU:
  4045. case VK_LWIN:
  4046. case VK_RWIN:
  4047. //
  4048. // Don't try to fix the keystate while it's changing
  4049. //
  4050. DC_QUIT;
  4051. }
  4052. //
  4053. // GetKeyState doesn't work correctly on 9x for the right-side modifier
  4054. // keys, so do the generic left hand thing first for everybody
  4055. //
  4056. if(_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_NT) {
  4057. //
  4058. // NT systems check the specific key
  4059. //
  4060. vkShift = VK_LSHIFT;
  4061. vkControl = VK_LCONTROL;
  4062. vkMenu = VK_LMENU;
  4063. } else {
  4064. //
  4065. // Win9x systems check the general key
  4066. //
  4067. vkShift = VK_SHIFT;
  4068. vkControl = VK_CONTROL;
  4069. vkMenu = VK_MENU;
  4070. }
  4071. if (_IH.dwModifierKeyState & IH_LSHIFT_DOWN) {
  4072. if (!(GetKeyState(vkShift) & IH_KEYSTATE_DOWN)) {
  4073. TRC_DBG((TB, _T("Add left-Shift up event")));
  4074. IHInjectVKey(WM_KEYUP, vkShift);
  4075. _IH.dwModifierKeyState &= ~IH_LSHIFT_DOWN;
  4076. }
  4077. }
  4078. if (_IH.dwModifierKeyState & IH_LCTRL_DOWN) {
  4079. if (!(GetKeyState(vkControl) & IH_KEYSTATE_DOWN)) {
  4080. TRC_DBG((TB, _T("Add left-Ctrl up event")));
  4081. IHInjectVKey(WM_KEYUP, vkControl);
  4082. #ifdef OS_WINNT
  4083. _IH.dwModifierKeyState &= ~IH_LCTRL_DOWN;
  4084. #endif
  4085. }
  4086. }
  4087. if (_IH.dwModifierKeyState & IH_LALT_DOWN) {
  4088. if (!(GetKeyState(vkMenu) & IH_KEYSTATE_DOWN)) {
  4089. TRC_DBG((TB, _T("Add left-ALT up event")));
  4090. IHInjectVKey(WM_KEYUP, vkMenu);
  4091. #ifdef OS_WINNT
  4092. _IH.dwModifierKeyState &= ~IH_LALT_DOWN;
  4093. #endif
  4094. }
  4095. }
  4096. vkWin = VK_LWIN;
  4097. //
  4098. // Can only fixup winkeys when not hooking as the hook eats the VK_xWIN
  4099. // so GetKeyState() will never return the correct results.
  4100. //
  4101. if (_IH.dwModifierKeyState & IH_LWIN_DOWN && !_fUseHookBypass) {
  4102. if (!(GetKeyState(vkWin) & IH_KEYSTATE_DOWN)) {
  4103. TRC_DBG((TB, _T("Add left-Win up event")));
  4104. IHInjectKey(WM_KEYUP, VK_LWIN,(UINT16)
  4105. (MapVirtualKey(VK_LWIN, 0) | KF_EXTENDED));
  4106. #ifdef OS_WINNT
  4107. _IH.dwModifierKeyState &= ~IH_LWIN_DOWN;
  4108. #endif
  4109. }
  4110. }
  4111. //
  4112. // Right keys
  4113. //
  4114. if(_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_NT) {
  4115. //
  4116. // NT systems check the specific key
  4117. //
  4118. vkShift = VK_RSHIFT;
  4119. vkControl = VK_RCONTROL;
  4120. vkMenu = VK_RMENU;
  4121. } else {
  4122. //
  4123. // Win9x systems check the general key
  4124. //
  4125. // which are already set, no need to assign again
  4126. }
  4127. //
  4128. // Windows Key is fine on both platforms
  4129. //
  4130. vkWin = VK_RWIN;
  4131. if (_IH.dwModifierKeyState & IH_RSHIFT_DOWN) {
  4132. if (!(GetKeyState(vkShift) & IH_KEYSTATE_DOWN)) {
  4133. TRC_DBG((TB, _T("Add right-Shift up event")));
  4134. IHInjectKey(WM_KEYUP, VK_RSHIFT, (UINT16)IH_RSHIFT_SCANCODE);
  4135. _IH.dwModifierKeyState &= ~IH_RSHIFT_DOWN;
  4136. }
  4137. }
  4138. if (_IH.dwModifierKeyState & IH_RCTRL_DOWN) {
  4139. if (!(GetKeyState(vkControl) & IH_KEYSTATE_DOWN)) {
  4140. TRC_DBG((TB, _T("Add right-Ctrl up event")));
  4141. IHInjectKey(WM_KEYUP, VK_RCONTROL,
  4142. (UINT16)(MapVirtualKey(VK_CONTROL, 0) | KF_EXTENDED));
  4143. #ifdef OS_WINNT
  4144. _IH.dwModifierKeyState &= ~IH_RCTRL_DOWN;
  4145. #endif
  4146. }
  4147. }
  4148. if (_IH.dwModifierKeyState & IH_RALT_DOWN) {
  4149. if (!(GetKeyState(vkMenu) & IH_KEYSTATE_DOWN)) {
  4150. TRC_DBG((TB, _T("Add right-ALT up event")));
  4151. IHInjectKey(WM_KEYUP, VK_RMENU,
  4152. (UINT16)(MapVirtualKey(VK_MENU, 0) | KF_EXTENDED));
  4153. #ifdef OS_WINNT
  4154. _IH.dwModifierKeyState &= ~IH_RALT_DOWN;
  4155. #endif
  4156. }
  4157. }
  4158. //
  4159. // Can only fixup winkeys when not hooking as the hook eats the VK_WINS
  4160. // so GetKeyState() will never return the correct results.
  4161. //
  4162. if (_IH.dwModifierKeyState & IH_RWIN_DOWN && !_fUseHookBypass) {
  4163. if (!(GetKeyState(vkWin) & IH_KEYSTATE_DOWN)) {
  4164. TRC_DBG((TB, _T("Add right-Win up event")));
  4165. IHInjectKey(WM_KEYUP, VK_RWIN,(UINT16)
  4166. (MapVirtualKey(VK_RWIN, 0) | KF_EXTENDED));
  4167. #ifdef OS_WINNT
  4168. _IH.dwModifierKeyState &= ~IH_RWIN_DOWN;
  4169. #endif
  4170. }
  4171. }
  4172. DC_EXIT_POINT:
  4173. DC_END_FN();
  4174. }
  4175. #ifdef OS_WINNT
  4176. //
  4177. // IHHandleLocalLockDesktop
  4178. //
  4179. // Called to do tail processing for the case when we detect and eat a
  4180. // 'Windows+L' key request. In this case we want to
  4181. //
  4182. // 1) Fixup the remote windows key state
  4183. // 2) Send the local system a 'Windows+L' combo
  4184. //
  4185. VOID CIH::IHHandleLocalLockDesktop()
  4186. {
  4187. DC_BEGIN_FN("IHHandleLocalLockDesktop");
  4188. #define IH_SCANCODE_LWIN 0x5b
  4189. #define IH_SCANCODE_L 0x26
  4190. //
  4191. // Sanity check. This path should only be entered in response to a
  4192. // captured windows+L in the LL hook
  4193. //
  4194. TRC_ASSERT(_fUseHookBypass,
  4195. (TB,_T("IHHandleLocalLockDesktop called when not hooking!")));
  4196. //
  4197. // More IH specialness.
  4198. //
  4199. // If the server thinks the windows key was down
  4200. // we have a problem because if/when the user returns from
  4201. // the locked screen the windows key may be out of sync.
  4202. //
  4203. // We can't do a fixup in the normal MaintainModifiers() code
  4204. // because GetKeyState() doesn't work when hooking.
  4205. //
  4206. // Send the following sequence to clear this up
  4207. // -UP whatever winkey was down
  4208. // -Down L-winkey
  4209. //
  4210. //
  4211. // Inject local keys back into system.
  4212. // IMPORTANT: dwExtraFlag is set to prevent feedback
  4213. //
  4214. TRC_DBG((TB,_T("Done injecting local Windows+L")));
  4215. //LWIN down
  4216. keybd_event(VK_LWIN, IH_SCANCODE_LWIN,
  4217. KEYEVENTF_EXTENDEDKEY | 0,
  4218. IH_EXTRAINFO_IGNOREVALUE);
  4219. //'L' down
  4220. keybd_event(VK_L, IH_SCANCODE_L,
  4221. 0, IH_EXTRAINFO_IGNOREVALUE);
  4222. //'L' up
  4223. keybd_event(VK_L, IH_SCANCODE_L,
  4224. KEYEVENTF_KEYUP,
  4225. IH_EXTRAINFO_IGNOREVALUE);
  4226. //LWIN up
  4227. keybd_event(VK_LWIN, IH_SCANCODE_LWIN,
  4228. KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
  4229. IH_EXTRAINFO_IGNOREVALUE);
  4230. TRC_DBG((TB,_T("Done injecting local Windows+L")));
  4231. if (_IH.dwModifierKeyState & IH_LWIN_DOWN) {
  4232. TRC_DBG((TB,_T("Fixing up left windows key")));
  4233. IHInjectVKey(WM_KEYDOWN, VK_SHIFT);
  4234. IHInjectVKey(WM_KEYUP, VK_SHIFT);
  4235. IHInjectKey(WM_KEYUP, VK_LWIN,(UINT16)
  4236. (MapVirtualKey(VK_LWIN, 0) | KF_EXTENDED | KF_UP));
  4237. _IH.dwModifierKeyState &= ~IH_LWIN_DOWN;
  4238. }
  4239. if (_IH.dwModifierKeyState & IH_RWIN_DOWN) {
  4240. TRC_DBG((TB,_T("Fixing up right windows key")));
  4241. IHInjectVKey(WM_KEYDOWN, VK_SHIFT);
  4242. IHInjectVKey(WM_KEYUP, VK_SHIFT);
  4243. IHInjectKey(WM_KEYUP, VK_RWIN,
  4244. (UINT16)(MapVirtualKey(VK_RWIN, 0) | KF_EXTENDED | KF_UP));
  4245. _IH.dwModifierKeyState &= ~IH_RWIN_DOWN;
  4246. }
  4247. TRC_DBG((TB,_T("End fixup remote windows key")));
  4248. IHMaybeSendPDU();
  4249. DC_END_FN();
  4250. }
  4251. BOOL
  4252. CIH::IHIsForegroundWindow()
  4253. {
  4254. DWORD dwForegroundProcessId;
  4255. BOOL fIsFore = FALSE;
  4256. DC_BEGIN_FN("IHIsForegroundWindow");
  4257. GetWindowThreadProcessId( GetForegroundWindow(),
  4258. &dwForegroundProcessId);
  4259. if ((GetCurrentProcessId() == dwForegroundProcessId) &&
  4260. (GetFocus() == _IH.inputCaptureWindow)) {
  4261. fIsFore = TRUE;
  4262. }
  4263. DC_END_FN();
  4264. return fIsFore;
  4265. }
  4266. #endif //OS_WINNT