Source code of Windows XP (NT5)
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.

4510 lines
156 KiB

  1. #include "precomp.h"
  2. //
  3. // IM.CPP
  4. // Input Manager
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #include <confreg.h>
  9. #define MLZ_FILE_ZONE ZONE_INPUT
  10. //
  11. // IM_ShareStarting()
  12. //
  13. BOOL ASShare::IM_ShareStarting(void)
  14. {
  15. BOOL rc = FALSE;
  16. HKEY hkeyBandwidth;
  17. UINT i;
  18. BYTE tmpVK;
  19. DebugEntry(ASShare::IM_ShareStarting);
  20. //
  21. // Find out the scan codes for the left and right shift keys.
  22. //
  23. //
  24. // SFR 2537: Get the scan codes for this keyboard for the left-right
  25. // variants of SHIFT.
  26. //
  27. // We do not do this for the left-right variants of CONTROL and ALT (ie
  28. // menu) because they are extended keys.
  29. //
  30. // The scan codes are used in the keyboard hook (when sending) and in
  31. // the network translate to OS routine (when receiving), to
  32. // distinguish between the left-right variants of VK_SHIFT, where
  33. // Windows only reports a single value.
  34. //
  35. // This method is pretty long
  36. //
  37. m_imScanVKLShift = (BYTE) MapVirtualKey(VK_SHIFT, 0);
  38. for (i = 0; i < 256; i++)
  39. {
  40. tmpVK = (BYTE)MapVirtualKey(i, 1);
  41. if ( (tmpVK == VK_SHIFT) && (i != m_imScanVKLShift) )
  42. {
  43. m_imScanVKRShift = (BYTE)i;
  44. break;
  45. }
  46. }
  47. TRACE_OUT(( "Left/Right VK_SHIFT: scan codes = %02X, %02X",
  48. m_imScanVKLShift, m_imScanVKRShift));
  49. //
  50. // Check the user-reported bandwidth to decide if we should optimize
  51. // input for bandwidth or latency.
  52. // BUGBUG will want to vary this via flow control instead in future
  53. //
  54. m_imInControlMouseWithhold = 0;
  55. //
  56. // Find out if this is a DBCS enabled system - if it is then we'll need
  57. // to load IMM32.DLL.
  58. //
  59. ASSERT(m_imImmLib == NULL);
  60. ASSERT(m_imImmGVK == NULL);
  61. if (GetSystemMetrics(SM_DBCSENABLED))
  62. {
  63. //
  64. // DBCS system, so load IMM32.DLL
  65. //
  66. m_imImmLib = LoadLibrary("imm32.dll");
  67. if (!m_imImmLib)
  68. {
  69. ERROR_OUT(( "Failed to load imm32.dll"));
  70. DC_QUIT;
  71. }
  72. //
  73. // Now attempt to find the entry point in this DLL.
  74. //
  75. m_imImmGVK = (IMMGVK) GetProcAddress(m_imImmLib, "ImmGetVirtualKey");
  76. if (!m_imImmGVK)
  77. {
  78. ERROR_OUT(( "Failed to fixup <ImmGetVirtualKey>"));
  79. DC_QUIT;
  80. }
  81. }
  82. rc = TRUE;
  83. DC_EXIT_POINT:
  84. DebugExitBOOL(ASShare::IM_ShareStarting, rc);
  85. return(rc);
  86. }
  87. //
  88. // IM_ShareEnded()
  89. //
  90. void ASShare::IM_ShareEnded(void)
  91. {
  92. DebugEntry(ASShare::IM_ShareEnded);
  93. // Free imm32 dll
  94. m_imImmGVK = NULL;
  95. if (m_imImmLib)
  96. {
  97. FreeLibrary(m_imImmLib);
  98. m_imImmLib = NULL;
  99. }
  100. DebugExitVOID(ASShare::IM_ShareEnded);
  101. }
  102. //
  103. // IM_Controlled()
  104. //
  105. // Called when we start/stop being controlled.
  106. //
  107. BOOL ASShare::IM_Controlled(ASPerson * pasControlledBy)
  108. {
  109. BOOL rc;
  110. DebugEntry(ASShare::IM_Controlled);
  111. if (pasControlledBy)
  112. {
  113. // Incoming injected input queues should be empty
  114. ASSERT(m_imControlledEventQ.numEvents == 0);
  115. ASSERT(m_imControlledEventQ.head == 0);
  116. ASSERT(m_imControlledOSQ.numEvents == 0);
  117. ASSERT(m_imControlledOSQ.head == 0);
  118. //
  119. // Reset CONTROLLED vars
  120. //
  121. m_imfControlledMouseButtonsReversed = (GetSystemMetrics(SM_SWAPBUTTON) != 0);
  122. m_imfControlledMouseClipped = FALSE;
  123. m_imfControlledPaceInjection = FALSE;
  124. m_imfControlledNewEvent = TRUE;
  125. m_imControlledNumEventsPending = 0;
  126. m_imControlledNumEventsReturned = 0;
  127. m_imControlledLastLowLevelMouseEventTime = GetTickCount();
  128. m_imControlledLastMouseRemoteTime = 0;
  129. m_imControlledLastMouseLocalTime = 0;
  130. m_imControlledLastIncompleteConversion = 0;
  131. m_imControlledMouseBacklog = 0;
  132. GetCursorPos(&m_imControlledLastMousePos);
  133. // Get current keyboard state
  134. GetKeyboardState(m_aimControlledKeyStates);
  135. // Save it so we can put it back when done being controlled
  136. ASSERT(sizeof(m_aimControlledSavedKeyStates) == sizeof(m_aimControlledKeyStates));
  137. CopyMemory(m_aimControlledSavedKeyStates, m_aimControlledKeyStates, sizeof(m_aimControlledKeyStates));
  138. // Clear original keyboard state
  139. ZeroMemory(m_aimControlledKeyStates, sizeof(m_aimControlledKeyStates));
  140. SetKeyboardState(m_aimControlledKeyStates);
  141. //
  142. // On the other side, the remote will start sending us events to
  143. // bring our keyboard in sync with his. Then real input events.
  144. //
  145. }
  146. else
  147. {
  148. //
  149. // We're no longer controlled. Clear the remote queues.
  150. //
  151. m_imControlledOSQ.head = 0;
  152. m_imControlledOSQ.numEvents = 0;
  153. m_imControlledEventQ.numEvents = 0;
  154. //
  155. // Put back our saved keyboard state
  156. //
  157. SetKeyboardState(m_aimControlledSavedKeyStates);
  158. }
  159. rc = OSI_InstallControlledHooks(pasControlledBy != NULL);
  160. if (!rc)
  161. {
  162. ERROR_OUT(("IM_Controlled: Couldn't install controlled hooks"));
  163. DC_QUIT;
  164. }
  165. g_lpimSharedData->imControlled = (pasControlledBy != NULL);
  166. DC_EXIT_POINT:
  167. DebugExitBOOL(ASShare:IM_Controlled, rc);
  168. return(rc);
  169. }
  170. //
  171. // IM_InControl()
  172. //
  173. // Called when we start/stop being in control. We must observe high-level
  174. // keyboard events.
  175. //
  176. void ASShare::IM_InControl(ASPerson * pasInControlOf)
  177. {
  178. DebugEntry(ASShare::IM_InControl);
  179. if (pasInControlOf)
  180. {
  181. //
  182. // Set up InControl vars.
  183. //
  184. // Get current key state
  185. GetKeyboardState(m_aimInControlKeyStates);
  186. m_imfInControlEventIsPending = FALSE;
  187. m_imfInControlCtrlDown = FALSE;
  188. m_imfInControlShiftDown = FALSE;
  189. m_imfInControlMenuDown = FALSE;
  190. m_imfInControlCapsLock = FALSE;
  191. m_imfInControlNumLock = FALSE;
  192. m_imfInControlScrollLock = FALSE;
  193. m_imfInControlConsumeMenuUp = FALSE;
  194. m_imfInControlConsumeEscapeUp = FALSE;
  195. m_imfInControlNewEvent = TRUE;
  196. m_imInControlMouseDownCount = 0;
  197. m_imInControlMouseDownTime = 0;
  198. m_imInControlMouseSpoilRate = 0;
  199. m_imInControlNumEventsPending = 0;
  200. m_imInControlNumEventsReturned = 0;
  201. m_imInControlNextHotKeyEntry = 0;
  202. //
  203. // Send mouse move with our current position to the dude we're in
  204. // control of.
  205. //
  206. ValidateView(pasInControlOf);
  207. ASSERT(pasInControlOf->m_caControlledBy == m_pasLocal);
  208. }
  209. else
  210. {
  211. // Clear outgoing queues
  212. m_imInControlEventQ.head = 0;
  213. m_imInControlEventQ.numEvents = 0;
  214. }
  215. DebugExitVOID(ASShare::IM_InControl);
  216. }
  217. //
  218. // IM_Periodic
  219. //
  220. void ASShare::IM_Periodic(void)
  221. {
  222. POINT cursorPos;
  223. UINT timeDelta;
  224. DebugEntry(ASShare::IM_Periodic);
  225. if (m_pasLocal->m_caInControlOf)
  226. {
  227. //
  228. // Send outgoing input to person we're in control of
  229. //
  230. IMFlushOutgoingEvents();
  231. }
  232. else if (m_pasLocal->m_caControlledBy)
  233. {
  234. ASSERT(m_pHost);
  235. //
  236. // Playback input from person in control of us
  237. //
  238. IMMaybeInjectEvents();
  239. //
  240. // Get the current cursor position - we always need this.
  241. //
  242. GetCursorPos(&cursorPos);
  243. //
  244. // First check if we think that a cursor clip will have affected the
  245. // position when we replayed a remote event.
  246. //
  247. if (m_imfControlledMouseClipped)
  248. {
  249. RECT cursorClip;
  250. //
  251. // Get the current clip and the current cursor position.
  252. //
  253. GetClipCursor(&cursorClip);
  254. if ((cursorPos.x == cursorClip.left) ||
  255. (cursorPos.x == (cursorClip.right-1)) ||
  256. (cursorPos.y == cursorClip.top) ||
  257. (cursorPos.y == (cursorClip.bottom-1)))
  258. {
  259. WARNING_OUT(("CM_ApplicationMovedCursor {%04d, %04d}",
  260. cursorPos.x, cursorPos.y));
  261. //
  262. // We thought the cursor was going to be clipped and now we
  263. // find it is right at the edge of the clip so tell the CM to
  264. // tell its peers about the cursor being moved.
  265. //
  266. m_pHost->CM_ApplicationMovedCursor();
  267. m_imfControlledMouseClipped = FALSE;
  268. }
  269. }
  270. // We are being controlled by somebody else.
  271. // So now's the time to decide if a SetCursorPos has
  272. // happened. For us to believe that a SetCursorPos has actually
  273. // occurred, the elapsed time since the last low-level input event
  274. // was injected must be greater than IM_EVENT_PERCOLATE_TIME
  275. // and the cursor must be in a different position to that which we
  276. // currently believe it to be.
  277. //
  278. if ((cursorPos.x != m_imControlledLastMousePos.x) ||
  279. (cursorPos.y != m_imControlledLastMousePos.y))
  280. {
  281. TRACE_OUT(( "GCP gives (%d,%d), last mouse event is (%d,%d)",
  282. cursorPos.x,
  283. cursorPos.y,
  284. m_imControlledLastMousePos.x,
  285. m_imControlledLastMousePos.y));
  286. //
  287. // Get the current tick count.
  288. //
  289. timeDelta = GetTickCount() - m_imControlledLastLowLevelMouseEventTime;
  290. if (timeDelta > IM_EVENT_PERCOLATE_TIME)
  291. {
  292. //
  293. // Looks like a SetCursorPos has occured - tell CM.
  294. //
  295. WARNING_OUT(("CM_ApplicationMovedCursor {%04d, %04d}",
  296. cursorPos.x, cursorPos.y));
  297. m_pHost->CM_ApplicationMovedCursor();
  298. //
  299. // Update the last high level mouse position.
  300. //
  301. m_imControlledLastMousePos.x = cursorPos.x;
  302. m_imControlledLastMousePos.y = cursorPos.y;
  303. }
  304. }
  305. }
  306. DebugExitVOID(ASShare::IM_Periodic);
  307. }
  308. //
  309. // IM_ReceivedPacket()
  310. //
  311. // A null packet pointer can be used to trigger the injection of another
  312. // pending event
  313. //
  314. //
  315. // DESCRIPTION:
  316. //
  317. // Called when an IM events packet arrives at the PR. The IM will accept
  318. // the incoming packet. It may copy it to an internal queue rather than
  319. // process it immediately. IM events packets contain a series of
  320. // piggybacked IM events.
  321. //
  322. // PARAMETERS:
  323. //
  324. // personID - the source of the packet
  325. //
  326. // pPacket - a pointer to the packet
  327. //
  328. // RETURNS: NONE
  329. //
  330. void ASShare::IM_ReceivedPacket
  331. (
  332. ASPerson * pasFrom,
  333. PS20DATAPACKET pPacket
  334. )
  335. {
  336. LPIMPACKET pIMPacket;
  337. UINT i;
  338. DebugEntry(ASShare::IM_ReceivedPacket);
  339. if (!pasFrom)
  340. {
  341. TRACE_OUT(("Simply inject any pending events in"));
  342. DC_QUIT;
  343. }
  344. ValidatePerson(pasFrom);
  345. pIMPacket = (PIMPACKET)pPacket;
  346. // If this person isn't in control of us, blow this off
  347. if (pasFrom->m_caInControlOf != m_pasLocal)
  348. {
  349. DC_QUIT;
  350. }
  351. //
  352. // For each packet in the piggybacked packets array...
  353. //
  354. TRACE_OUT(("IM_ReceivedPacket: Processing packet with %d events",
  355. pIMPacket->numEvents));
  356. for (i = 0; i < pIMPacket->numEvents; i++)
  357. {
  358. switch (pIMPacket->aEvents[i].type)
  359. {
  360. case IM_TYPE_ASCII:
  361. case IM_TYPE_VK1:
  362. case IM_TYPE_VK2:
  363. case IM_TYPE_3BUTTON:
  364. {
  365. IMAppendNetEvent(&(pIMPacket->aEvents[i]));
  366. break;
  367. }
  368. default:
  369. //
  370. // Unexpected events are not error - we just ignore then
  371. // for future compatibility
  372. //
  373. TRACE_OUT(("Person [%d] unrecognised IM type (%04X) - event discarded",
  374. pasFrom->mcsID, pIMPacket->aEvents[i].type));
  375. break;
  376. }
  377. }
  378. DC_EXIT_POINT:
  379. //
  380. // Our final action is to feed one of the new events into USER.
  381. // We do NOT feed them all in at once because we want to simulate
  382. // typing them in, otherwise the amount of spoiling we see is
  383. // totally dependent upon the network latency and piggybacking.
  384. //
  385. ValidatePerson(m_pasLocal);
  386. if (m_pasLocal->m_caControlledBy)
  387. {
  388. //
  389. // @@@JPB: Temporary - want to inject as many events as possible -
  390. // this should be moved to a loop within IMMaybeInjectEvents...
  391. //
  392. // This greatly improves responsiveness when handling a large
  393. // number of input events in a short space of time (e.g. pounding
  394. // on the keyboard) - very little overrun.
  395. //
  396. for (i = 0; i < 10; i++)
  397. {
  398. IMMaybeInjectEvents();
  399. }
  400. //
  401. // Go into TURBO scheduling if this is a real input packet.
  402. //
  403. if (pPacket != NULL)
  404. {
  405. SCH_ContinueScheduling(SCH_MODE_TURBO);
  406. }
  407. }
  408. DebugExitVOID(ASShare::IM_ReceivedPacket);
  409. }
  410. //
  411. // IMGetHighLevelKeyState
  412. //
  413. // DESCRIPTION:
  414. //
  415. // Called by the IEM when it is converting a local event to a network event
  416. // to determine the state of the local keyboard when the event was
  417. // generated.
  418. //
  419. // PARAMETERS:
  420. //
  421. // vk - the key
  422. //
  423. // RETURNS:
  424. //
  425. // Flags - bit 7 set/reset key down/up, bit 0 toggle
  426. //
  427. //
  428. BYTE ASShare::IMGetHighLevelKeyState(UINT vk)
  429. {
  430. int keyState;
  431. BYTE rc;
  432. DebugEntry(ASShare::IMGetHighLevelKeyState);
  433. keyState = GetKeyState(vk);
  434. rc = (BYTE) (((keyState & 0x8000) >> 8) | keyState & 0x0001);
  435. DebugExitDWORD(ASShare::IMGetHighLevelKeyState, rc);
  436. return(rc);
  437. }
  438. //
  439. // FUNCTION: IMFlushOutgoingEvents
  440. //
  441. // DESCRIPTION:
  442. //
  443. // Called to send new IMEVENTs (as they are generated and periodically).
  444. // This function will send as many IMEVENTs from the current backlog as
  445. // possible.
  446. //
  447. // PARAMETERS: NONE
  448. //
  449. // RETURNS: NONE
  450. //
  451. //
  452. void ASShare::IMFlushOutgoingEvents(void)
  453. {
  454. UINT i;
  455. UINT sizeOfPacket;
  456. PIMPACKET pIMPacket;
  457. UINT lastEvent;
  458. UINT secondLastEvent;
  459. UINT elapsedTime;
  460. UINT time;
  461. UINT eventsToSend;
  462. UINT curTime;
  463. BOOL holdPacket;
  464. #ifdef _DEBUG
  465. UINT sentSize;
  466. #endif // _DEBUG
  467. DebugEntry(ASShare::IMFlushOutgoingEvents);
  468. ValidateView(m_pasLocal->m_caInControlOf);
  469. //
  470. // Try to convert the input into a bunch of IMEVENTs
  471. //
  472. while (m_imfInControlEventIsPending && (m_imInControlEventQ.numEvents < IM_SIZE_EVENTQ))
  473. {
  474. //
  475. // There is space to try and convert the pending packet.
  476. //
  477. m_imfInControlEventIsPending = (IMTranslateOutgoing(&m_imInControlPendingEvent,
  478. &m_imInControlEventQ.events[CIRCULAR_INDEX(m_imInControlEventQ.head,
  479. m_imInControlEventQ.numEvents, IM_SIZE_EVENTQ)]) != FALSE);
  480. if (m_imfInControlEventIsPending)
  481. {
  482. //
  483. // We have added a packet to the queue - update our queue
  484. // tracking variables.
  485. //
  486. m_imInControlEventQ.numEvents++;
  487. }
  488. }
  489. //
  490. // Mouse handling has been improved in the following ways
  491. // - withhold generation of packets while we are purely handling
  492. // mouse moves and we are within the LOCAL_MOUSE_WITHHOLD range
  493. // While we are doing this spoil them to the highest frequency
  494. // we are permitted to generate (SAMPLING_GAP_HIGH)
  495. // - if we exceed the withholding threshhold but remain within queue
  496. // size/2 spoil down to the intermediate range
  497. // (SAMPLING_GAP_MEDIUM)
  498. // - otherwise spoil down to the low range
  499. //
  500. // We spoil the events by hanging on to the last event for a while, if
  501. // it was a mouse move, so that we can use it for subsequent spoiling.
  502. // Whenever we get a non-mouse message then we spoil the lot to
  503. // eliminate latency, on clicks, for example.
  504. //
  505. //
  506. // Calculate the mouse spoil rate - do we need more than just the high
  507. // rate spoiling?
  508. //
  509. if (m_imInControlEventQ.numEvents > m_imInControlMouseWithhold + 1)
  510. {
  511. //
  512. // Are we into intermediate or low spoiling?
  513. //
  514. if (m_imInControlEventQ.numEvents < (IM_SIZE_EVENTQ +
  515. m_imInControlMouseWithhold) / 2)
  516. {
  517. TRACE_OUT(( "Mouse spoil rate to MEDIUM"));
  518. m_imInControlMouseSpoilRate = IM_LOCAL_MOUSE_SAMPLING_GAP_MEDIUM_MS;
  519. }
  520. else
  521. {
  522. TRACE_OUT(( "Mouse spoil rate to LOW"));
  523. m_imInControlMouseSpoilRate = IM_LOCAL_MOUSE_SAMPLING_GAP_LOW_MS;
  524. }
  525. }
  526. else
  527. {
  528. //
  529. // Spoil at the normal high rate
  530. //
  531. if (m_imInControlMouseSpoilRate != IM_LOCAL_MOUSE_SAMPLING_GAP_HIGH_MS)
  532. {
  533. TRACE_OUT(( "Mouse spoil rate to HIGH"));
  534. m_imInControlMouseSpoilRate = IM_LOCAL_MOUSE_SAMPLING_GAP_HIGH_MS;
  535. }
  536. }
  537. //
  538. // Firstly get a pointer to lastEvent for use here and in send arm
  539. // below (We wont use it if m_imInControlEventQ.numEvents == 0)
  540. //
  541. lastEvent = CIRCULAR_INDEX(m_imInControlEventQ.head,
  542. m_imInControlEventQ.numEvents - 1, IM_SIZE_EVENTQ);
  543. //
  544. // Now perform the spoiling, if necessary
  545. //
  546. if (m_imInControlEventQ.numEvents > 1)
  547. {
  548. if (lastEvent == 0)
  549. {
  550. secondLastEvent = IM_SIZE_EVENTQ - 1;
  551. }
  552. else
  553. {
  554. secondLastEvent = lastEvent - 1;
  555. }
  556. elapsedTime = m_imInControlEventQ.events[lastEvent].timeMS
  557. - m_imInControlEventQ.events[secondLastEvent].timeMS;
  558. TRACE_OUT(( "Inter packet time %d, sampling gap %ld",
  559. elapsedTime,m_imInControlMouseSpoilRate));
  560. if ((elapsedTime < m_imInControlMouseSpoilRate) &&
  561. (m_imInControlEventQ.events[lastEvent].type == IM_TYPE_3BUTTON) &&
  562. (m_imInControlEventQ.events[secondLastEvent].type == IM_TYPE_3BUTTON) &&
  563. (m_imInControlEventQ.events[lastEvent].data.mouse.flags &
  564. IM_FLAG_MOUSE_MOVE) &&
  565. (m_imInControlEventQ.events[secondLastEvent].data.mouse.flags &
  566. IM_FLAG_MOUSE_MOVE))
  567. {
  568. TRACE_OUT(( "spoil mouse move from pos %u", secondLastEvent));
  569. time = m_imInControlEventQ.events[secondLastEvent].timeMS;
  570. m_imInControlEventQ.events[secondLastEvent] =
  571. m_imInControlEventQ.events[lastEvent];
  572. m_imInControlEventQ.events[secondLastEvent].timeMS = time;
  573. m_imInControlEventQ.numEvents--;
  574. lastEvent = secondLastEvent;
  575. }
  576. }
  577. //
  578. // If we have any events queued up and we are not waiting for a mouse
  579. // button up event then try to send them. (Note we do not wait for a
  580. // mouse up event if the queue is full because if we got a mouse up
  581. // when the queue was full then we would have nowhere to put it!)
  582. //
  583. curTime = GetTickCount();
  584. if ((m_imInControlEventQ.numEvents != 0) &&
  585. ((m_imfInControlEventIsPending ||
  586. (m_imInControlMouseDownCount == 0) ||
  587. (curTime - m_imInControlMouseDownTime > IM_MOUSE_UP_WAIT_TIME))))
  588. {
  589. //
  590. // If there are mouse move messages on the queue and they are not
  591. // so old that we should send them anyway then hold them to allow
  592. // some spoiling to take place.
  593. //
  594. holdPacket = FALSE;
  595. if (m_imInControlEventQ.numEvents <= m_imInControlMouseWithhold)
  596. {
  597. if ((m_imInControlEventQ.events[lastEvent].type == IM_TYPE_3BUTTON) &&
  598. (m_imInControlEventQ.events[lastEvent].data.mouse.flags &
  599. IM_FLAG_MOUSE_MOVE))
  600. {
  601. if (curTime < (m_imInControlEventQ.events[m_imInControlEventQ.head].timeMS +
  602. IM_LOCAL_WITHHOLD_DELAY))
  603. {
  604. holdPacket = TRUE;
  605. }
  606. }
  607. }
  608. if (m_imInControlEventQ.numEvents <= IM_LOCAL_KEYBOARD_WITHHOLD)
  609. {
  610. //
  611. // If the message indicates the key is down then wait, either
  612. // for the release we know is coming, or intil it has auto
  613. // repeated for a while or until the buffer is full.
  614. //
  615. if (((m_imInControlEventQ.events[lastEvent].type == IM_TYPE_ASCII) ||
  616. (m_imInControlEventQ.events[lastEvent].type == IM_TYPE_VK1) ||
  617. (m_imInControlEventQ.events[lastEvent].type == IM_TYPE_VK2)) &&
  618. (m_imInControlEventQ.events[lastEvent].data.keyboard.flags &
  619. IM_FLAG_KEYBOARD_DOWN))
  620. {
  621. curTime = GetTickCount();
  622. if (curTime < (m_imInControlEventQ.events[m_imInControlEventQ.head].timeMS +
  623. IM_LOCAL_WITHHOLD_DELAY))
  624. {
  625. holdPacket = TRUE;
  626. }
  627. }
  628. }
  629. if (!holdPacket)
  630. {
  631. UINT destID;
  632. TRACE_OUT(( "Sending all %d packets",m_imInControlEventQ.numEvents));
  633. eventsToSend = m_imInControlEventQ.numEvents;
  634. m_imInControlEventQ.numEvents = 0;
  635. destID = m_pasLocal->m_caInControlOf->mcsID;
  636. sizeOfPacket = sizeof(IMPACKET) + (eventsToSend-1)*sizeof(IMEVENT);
  637. pIMPacket = (PIMPACKET)SC_AllocPkt(PROT_STR_INPUT, destID, sizeOfPacket);
  638. if (!pIMPacket)
  639. {
  640. //
  641. // Failed to send this packet - keep the data on the queue
  642. // until the next time we are called. To prevent the loss
  643. // of data, just make sure that the local packet list is
  644. // not overwritten by restoring the current out packets
  645. // count.
  646. //
  647. WARNING_OUT(("Failed to alloc IM packet, size %u", sizeOfPacket));
  648. m_imInControlEventQ.numEvents = eventsToSend;
  649. }
  650. else
  651. {
  652. TRACE_OUT(( "NetAllocPkt successful for %d packets size %d",
  653. eventsToSend, sizeOfPacket));
  654. //
  655. // Fill in the packet header.
  656. //
  657. pIMPacket->header.data.dataType = DT_IM;
  658. //
  659. // Construct the contents of the IM specific part of the
  660. // packet.
  661. //
  662. pIMPacket->numEvents = (TSHR_UINT16)eventsToSend;
  663. for (i = 0; i < eventsToSend; i++)
  664. {
  665. pIMPacket->aEvents[i] = m_imInControlEventQ.events[m_imInControlEventQ.head];
  666. m_imInControlEventQ.head =
  667. CIRCULAR_INDEX(m_imInControlEventQ.head, 1,
  668. IM_SIZE_EVENTQ);
  669. }
  670. //
  671. // Now send the packet.
  672. //
  673. #ifdef _DEBUG
  674. sentSize =
  675. #endif // _DEBUG
  676. DCS_CompressAndSendPacket(PROT_STR_INPUT, destID,
  677. &(pIMPacket->header), sizeOfPacket);
  678. TRACE_OUT(("IM packet size: %08d, sent %08d", sizeOfPacket, sentSize));
  679. }
  680. }
  681. }
  682. DebugExitVOID(ASShare::IMFlushOutgoingEvents);
  683. }
  684. //
  685. // IMSpoilEvents()
  686. //
  687. // Called when outgoing IM packets get backlogged, we spoil every other
  688. // mouse move to shrink the number of events and therefore the size of the
  689. // IM packet(s).
  690. //
  691. void ASShare::IMSpoilEvents(void)
  692. {
  693. UINT lastEvent;
  694. UINT i;
  695. UINT j;
  696. UINT k;
  697. BOOL discard = TRUE;
  698. DebugEntry(ASShare::IMSpoilEvents);
  699. WARNING_OUT(( "Major spoiling due to IM packet queue backlog!"));
  700. i = CIRCULAR_INDEX(m_imInControlEventQ.head,
  701. m_imInControlEventQ.numEvents - 1, IM_SIZE_EVENTQ);
  702. while (i != m_imInControlEventQ.head)
  703. {
  704. if ((m_imInControlEventQ.events[i].type == IM_TYPE_3BUTTON) &&
  705. (m_imInControlEventQ.events[i].data.mouse.flags & IM_FLAG_MOUSE_MOVE))
  706. {
  707. if (discard)
  708. {
  709. TRACE_OUT(( "spoil mouse move from pos %u", i));
  710. j = CIRCULAR_INDEX(i, 1, IM_SIZE_EVENTQ);
  711. k = i;
  712. lastEvent = CIRCULAR_INDEX(m_imInControlEventQ.head,
  713. m_imInControlEventQ.numEvents - 1, IM_SIZE_EVENTQ);
  714. while (k != lastEvent)
  715. {
  716. //
  717. // Shuffle the entries along the queue.
  718. //
  719. m_imInControlEventQ.events[k] = m_imInControlEventQ.events[j];
  720. k = CIRCULAR_INDEX(k, 1, IM_SIZE_EVENTQ);
  721. j = CIRCULAR_INDEX(j, 1, IM_SIZE_EVENTQ);
  722. }
  723. m_imInControlEventQ.numEvents--;
  724. discard = FALSE;
  725. }
  726. else
  727. {
  728. discard = TRUE;
  729. }
  730. }
  731. //
  732. // Move on to the next event infront of this one.
  733. //
  734. if (i > 0)
  735. {
  736. i = i - 1;
  737. }
  738. else
  739. {
  740. i = IM_SIZE_EVENTQ - 1;
  741. }
  742. }
  743. DebugExitVOID(ASShare::IMSpoilEvents);
  744. }
  745. //
  746. // IMAppendNetEvent()
  747. //
  748. // Add the incoming event to the remote network queue, doing basic
  749. // translation like mouse button swapping. Ignore unrecognized events.
  750. //
  751. void ASShare::IMAppendNetEvent(PIMEVENT pIMEvent)
  752. {
  753. int i;
  754. BOOL discard = TRUE;
  755. DebugEntry(ASShare::IMAppendNetEvent);
  756. switch (pIMEvent->type)
  757. {
  758. case IM_TYPE_3BUTTON:
  759. if (!(pIMEvent->data.mouse.flags & IM_FLAG_MOUSE_MOVE))
  760. {
  761. //
  762. // Swap the mouse buttons if necessary.
  763. //
  764. if (m_imfControlledMouseButtonsReversed &&
  765. (pIMEvent->data.mouse.flags &
  766. (TSHR_UINT16)(IM_FLAG_MOUSE_BUTTON1 |
  767. IM_FLAG_MOUSE_BUTTON2)))
  768. {
  769. pIMEvent->data.mouse.flags ^=
  770. (TSHR_UINT16)(IM_FLAG_MOUSE_BUTTON1 |
  771. IM_FLAG_MOUSE_BUTTON2);
  772. }
  773. }
  774. break;
  775. }
  776. //
  777. // Now put the IMEVENT into our queue.
  778. // Before we try to add the current packet we will try to inject some
  779. // more events (and therefore make space on the network event queue)
  780. //
  781. if (m_imControlledEventQ.numEvents >= IM_SIZE_EVENTQ)
  782. {
  783. //
  784. // Our network event queue is full - discard every other mouse
  785. // move event in the queue.
  786. //
  787. WARNING_OUT(( "Major spoiling due to network event queue backlog!"));
  788. for (i = m_imControlledEventQ.numEvents - 1; i >= 0; i--)
  789. {
  790. if (IM_IS_MOUSE_MOVE(m_imControlledEventQ.events[i].data.mouse.flags))
  791. {
  792. if (discard)
  793. {
  794. //
  795. // Remove this mouse move event by moving all events
  796. // after it down one.
  797. //
  798. WARNING_OUT(("Discard mouse move to {%d, %d}",
  799. (UINT)(m_imControlledEventQ.events[i].data.mouse.x),
  800. (UINT)(m_imControlledEventQ.events[i].data.mouse.y)));
  801. UT_MoveMemory(&(m_imControlledEventQ.events[i]),
  802. &(m_imControlledEventQ.events[i+1]),
  803. sizeof(IMEVENT) *
  804. (m_imControlledEventQ.numEvents-1-i) );
  805. m_imControlledEventQ.numEvents--;
  806. discard = FALSE;
  807. }
  808. else
  809. {
  810. discard = TRUE;
  811. }
  812. }
  813. }
  814. }
  815. if (m_imControlledEventQ.numEvents + 1 >= IM_SIZE_EVENTQ)
  816. {
  817. //
  818. // We've done our best and can't find any space.
  819. //
  820. WARNING_OUT(( "IM packet dropped %04X", pIMEvent->type));
  821. }
  822. else
  823. {
  824. //
  825. // Add this event to the queue
  826. //
  827. m_imControlledEventQ.events[m_imControlledEventQ.numEvents] = *pIMEvent;
  828. m_imControlledEventQ.numEvents++;
  829. }
  830. DebugExitVOID(ASShare::IMAppendNetEvent);
  831. }
  832. //
  833. // IM_OutgoingMouseInput()
  834. //
  835. // Called to send mouse moves and clicks to the remote host.
  836. // Called from the view window code.
  837. //
  838. void ASShare::IM_OutgoingMouseInput
  839. (
  840. ASPerson * pasHost,
  841. LPPOINT pMousePos,
  842. UINT message,
  843. UINT dwExtra
  844. )
  845. {
  846. IMEVENT imEvent;
  847. DebugEntry(ASShare::IM_OutgoingMouseInput);
  848. ValidateView(pasHost);
  849. ASSERT(pasHost->m_caControlledBy == m_pasLocal);
  850. GetKeyboardState(m_aimInControlKeyStates);
  851. //
  852. // Create the event.
  853. //
  854. imEvent.type = IM_TYPE_3BUTTON;
  855. //
  856. // We should only get WM_MOUSE* messages.
  857. //
  858. ASSERT(message >= WM_MOUSEFIRST);
  859. ASSERT(message <= WM_MOUSELAST);
  860. //
  861. // Convert to bit flags.
  862. //
  863. switch (message)
  864. {
  865. case WM_MOUSEMOVE:
  866. imEvent.data.mouse.flags = IM_FLAG_MOUSE_MOVE;
  867. break;
  868. case WM_LBUTTONDOWN:
  869. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON1 |
  870. IM_FLAG_MOUSE_DOWN;
  871. break;
  872. case WM_LBUTTONDBLCLK:
  873. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON1 |
  874. IM_FLAG_MOUSE_DOUBLE |
  875. IM_FLAG_MOUSE_DOWN;
  876. break;
  877. case WM_LBUTTONUP:
  878. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON1;
  879. break;
  880. case WM_RBUTTONDOWN:
  881. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON2 |
  882. IM_FLAG_MOUSE_DOWN;
  883. break;
  884. case WM_RBUTTONDBLCLK:
  885. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON2 |
  886. IM_FLAG_MOUSE_DOUBLE |
  887. IM_FLAG_MOUSE_DOWN;
  888. break;
  889. case WM_RBUTTONUP:
  890. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON2;
  891. break;
  892. case WM_MBUTTONDOWN:
  893. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON3 |
  894. IM_FLAG_MOUSE_DOWN;
  895. break;
  896. case WM_MBUTTONDBLCLK:
  897. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON3 |
  898. IM_FLAG_MOUSE_DOUBLE |
  899. IM_FLAG_MOUSE_DOWN;
  900. break;
  901. case WM_MBUTTONUP:
  902. imEvent.data.mouse.flags = IM_FLAG_MOUSE_BUTTON3;
  903. break;
  904. case WM_MOUSEWHEEL:
  905. //
  906. // LAURABU BOGUSBOGUS
  907. //
  908. // The HIWORD of wParam represents the # of clicks the wheel
  909. // has turned.
  910. //
  911. // But what about Win95? NT and Win95 Magellan mouse work
  912. // differently.
  913. //
  914. imEvent.data.mouse.flags = IM_FLAG_MOUSE_WHEEL;
  915. //
  916. // Check for overflows. If the wheel delta is outside the
  917. // values that can be sent by the protocol, send the maximum
  918. // values.
  919. //
  920. if ((TSHR_INT16)HIWORD(dwExtra) >
  921. (IM_FLAG_MOUSE_ROTATION_MASK - IM_FLAG_MOUSE_DIRECTION))
  922. {
  923. ERROR_OUT(( "Mouse wheel overflow %hd", HIWORD(dwExtra)));
  924. imEvent.data.mouse.flags |=
  925. (IM_FLAG_MOUSE_ROTATION_MASK - IM_FLAG_MOUSE_DIRECTION);
  926. }
  927. else if ((TSHR_INT16)HIWORD(dwExtra) < -IM_FLAG_MOUSE_DIRECTION)
  928. {
  929. ERROR_OUT(( "Mouse wheel underflow %hd", HIWORD(dwExtra)));
  930. imEvent.data.mouse.flags |= IM_FLAG_MOUSE_DIRECTION;
  931. }
  932. else
  933. {
  934. imEvent.data.mouse.flags |=
  935. (HIWORD(dwExtra) & IM_FLAG_MOUSE_ROTATION_MASK);
  936. }
  937. //
  938. // Win95 boxes need to know whether the middle mouse button is
  939. // up or down.
  940. //
  941. if (LOWORD(dwExtra) & MK_MBUTTON)
  942. {
  943. imEvent.data.mouse.flags |= IM_FLAG_MOUSE_DOWN;
  944. }
  945. break;
  946. default:
  947. imEvent.data.mouse.flags = IM_FLAG_MOUSE_MOVE;
  948. ERROR_OUT(( "Unrecognised mouse event - %#x", message));
  949. break;
  950. }
  951. TRACE_OUT(( "Mouse event flags %hx", imEvent.data.mouse.flags));
  952. imEvent.data.mouse.x = (TSHR_INT16)(pMousePos->x);
  953. imEvent.data.mouse.y = (TSHR_INT16)(pMousePos->y);
  954. imEvent.timeMS = GetTickCount();
  955. //
  956. // If this is a mouse down event then we will wait a while before
  957. // sending the packet for a mouse up event so that a single click
  958. // can be sent in one packet to avoid timing problems on the remote
  959. // side - with for example a scroll bar scrolling multiple lines
  960. // instead of just one line.
  961. //
  962. if ((message == WM_LBUTTONDOWN) ||
  963. (message == WM_RBUTTONDOWN) ||
  964. (message == WM_MBUTTONDOWN) ||
  965. (message == WM_LBUTTONDBLCLK) ||
  966. (message == WM_RBUTTONDBLCLK) ||
  967. (message == WM_MBUTTONDBLCLK))
  968. {
  969. m_imInControlMouseDownCount++;
  970. m_imInControlMouseDownTime = GetTickCount();
  971. }
  972. else if ((message == WM_LBUTTONUP) ||
  973. (message == WM_RBUTTONUP) ||
  974. (message == WM_MBUTTONUP))
  975. {
  976. --m_imInControlMouseDownCount;
  977. if (m_imInControlMouseDownCount < 0)
  978. {
  979. TRACE_OUT(("Unmatched button down for %d", message));
  980. m_imInControlMouseDownCount = 0;
  981. }
  982. }
  983. //
  984. // Try to send the packet.
  985. //
  986. if (!IMConvertAndSendEvent(pasHost, &imEvent))
  987. {
  988. WARNING_OUT(("Couldn't send mouse packet from local node"));
  989. }
  990. DebugExitVOID(ASShare::IM_OutgoingMouseInput);
  991. }
  992. //
  993. // IM_OutgoingKeyboardInput()
  994. //
  995. // Called to key downs, ups, and chars to the remote host.
  996. // Called from the view window code.
  997. //
  998. void ASShare::IM_OutgoingKeyboardInput
  999. (
  1000. ASPerson * pasHost,
  1001. UINT wParam,
  1002. UINT lParam
  1003. )
  1004. {
  1005. IMEVENT imEvent;
  1006. int rc;
  1007. int retFlags;
  1008. WORD result[2];
  1009. UINT i;
  1010. BOOL fSwallowDeadKey;
  1011. UINT mainVK;
  1012. DebugEntry(ASShare::IM_OutgoingKeyboardInput);
  1013. ValidateView(pasHost);
  1014. ASSERT(pasHost->m_caControlledBy = m_pasLocal);
  1015. GetKeyboardState(m_aimInControlKeyStates);
  1016. //
  1017. // Trace out the parameters once we've got this far.
  1018. //
  1019. TRACE_OUT(( "wParam - %04X, lParam - %08lX", wParam, lParam));
  1020. //
  1021. // Create the event.
  1022. //
  1023. imEvent.data.keyboard.flags = (TSHR_UINT16)
  1024. (HIWORD(lParam) & IM_MASK_KEYBOARD_SYSFLAGS);
  1025. imEvent.timeMS = GetTickCount();
  1026. imEvent.data.keyboard.keyCode = LOBYTE(wParam);
  1027. retFlags = CA_SEND_EVENT | CA_ALLOW_EVENT;
  1028. if ((wParam == VK_LWIN) || (wParam == VK_RWIN))
  1029. {
  1030. //
  1031. // The Windows keys give control to the local user interface.
  1032. //
  1033. // The keys are defined to do the following by the spec "New key
  1034. // support for Microsoft Windows Operating Systems and
  1035. // Applications"
  1036. //
  1037. // Left Windows key - set focus to Win95 user interface
  1038. // Right Windows key - as left
  1039. // Both Windows keys - Log-on key for Windows NT
  1040. // Windows key + any other - reserved for system hot keys
  1041. //
  1042. // Thus it does not make any sense to send these keys to the remote
  1043. // system at all.
  1044. //
  1045. retFlags &= ~CA_SEND_EVENT;
  1046. }
  1047. else if ((wParam == VK_PROCESSKEY) && (m_imImmGVK != NULL))
  1048. {
  1049. //
  1050. // An IME has processed this key - we want to find out what the
  1051. // original key was so call <ImmGetVirtualKey>.
  1052. //
  1053. ValidateView(pasHost);
  1054. wParam = m_imImmGVK(pasHost->m_pView->m_viewClient);
  1055. TRACE_OUT(( "Translated wP from VK_PROCESSKEY to %#lx", wParam));
  1056. }
  1057. if (retFlags & CA_SEND_EVENT)
  1058. {
  1059. //
  1060. // First check if this is a dead-key up stroke - if it is then
  1061. // don't call ToAscii as the shift state may have changed and we'll
  1062. // get the wrong accent or no accent at all. Assume that if the VK
  1063. // is a potential dead key VK (disregarding shift state) and
  1064. // m_imInControlNumDeadKeysDown is > 0 that this is a dead key - swallow
  1065. // it.
  1066. //
  1067. fSwallowDeadKey = FALSE;
  1068. if ((m_imInControlNumDeadKeysDown != 0) &&
  1069. (imEvent.data.keyboard.flags & IM_FLAG_KEYBOARD_RELEASE))
  1070. {
  1071. for (i = 0; i < m_imInControlNumDeadKeys; i++)
  1072. {
  1073. if (m_aimInControlDeadKeys[i] == (BYTE)imEvent.data.keyboard.keyCode)
  1074. {
  1075. //
  1076. // Assume this is a dead key up and therefore we don't
  1077. // want to pass it through ToAscii or generate any
  1078. // events based on it.
  1079. //
  1080. m_imInControlNumDeadKeysDown--;
  1081. TRACE_OUT(( "m_imInControlNumDeadKeysDown - %d",
  1082. m_imInControlNumDeadKeysDown));
  1083. fSwallowDeadKey = TRUE;
  1084. }
  1085. }
  1086. }
  1087. if (!fSwallowDeadKey)
  1088. {
  1089. //
  1090. // Find out if we can translate this virtual key into the
  1091. // Windows character set.
  1092. //
  1093. //
  1094. // Now try to convert this to an Ascii character.
  1095. //
  1096. rc = ToAscii(wParam,
  1097. LOBYTE(HIWORD(lParam)),
  1098. m_aimInControlKeyStates,
  1099. &result[0],
  1100. !(!(HIWORD(lParam) & KF_MENUMODE)));
  1101. if ((rc == 1) && (LOBYTE(result[0]) <= ' '))
  1102. {
  1103. //
  1104. // Don't use the results of ToAscii if its less than space
  1105. // (32) or space itself as Windows claims that the
  1106. // characters below this in the Windows character set are
  1107. // not supported and ToAscii will convert space plus
  1108. // modifiers to an ascii space and when we replay it
  1109. // VkKeyScan will tell us that ascii space shouldn't have
  1110. // any modifiers so we will undo any modifiers. This will
  1111. // clobber apps which interpret Ctrl-Space, Shift-Space.
  1112. //
  1113. rc = 0;
  1114. }
  1115. //
  1116. // Some Ascii characters can be generated from more than one
  1117. // key. (Eg '-' is on the main keyboard and the number pad).
  1118. // Convert this ASCII character back to a VK_ value. If it is
  1119. // different from the VK_ we started with, then do not send the
  1120. // key press as ASCII (Ie only send the 'main' way of entering
  1121. // an ASCII value as ASCII).
  1122. //
  1123. // Oprah1943: revert to the VK only if the ASCII code is less
  1124. // than 0x80. This avoids losing the diacritic in a dead-key
  1125. // sequence. VkKeyScan for the key down following the dead-key
  1126. // up returns the dead-key VK rather than that of the keystroke
  1127. // (wParam).
  1128. //
  1129. if (rc == 1)
  1130. {
  1131. mainVK = VkKeyScan(LOBYTE(result[0]));
  1132. if ( (LOBYTE(mainVK) != LOBYTE(wParam)) &&
  1133. (LOBYTE(result[0]) < 0x80) )
  1134. {
  1135. TRACE_OUT((
  1136. "Not MAIN VK pressed=0x%02hx main=0x%02hx ('%c'/%02hx)",
  1137. (TSHR_UINT16)LOBYTE(wParam),
  1138. (TSHR_UINT16)LOBYTE(mainVK),
  1139. (char)LOBYTE(result[0]),
  1140. (UINT)LOBYTE(result[0])));
  1141. rc = 0;
  1142. }
  1143. }
  1144. //
  1145. // If ToAscii converts this to a dead key then don't send any
  1146. // packets at all.
  1147. //
  1148. if (rc != -1)
  1149. {
  1150. if (rc == 1)
  1151. {
  1152. TRACE_OUT(( "ToAscii rc=1, result - %02X",
  1153. LOBYTE(result[0])));
  1154. //
  1155. // Succesfully converted to an Ascii key.
  1156. //
  1157. imEvent.type = IM_TYPE_ASCII;
  1158. imEvent.data.keyboard.keyCode = LOBYTE(result[0]);
  1159. //
  1160. // Try to send the packet.
  1161. //
  1162. if (!IMConvertAndSendEvent(pasHost, &imEvent))
  1163. {
  1164. WARNING_OUT(( "dropped local key press %u",
  1165. (UINT)imEvent.data.keyboard.keyCode));
  1166. }
  1167. }
  1168. else if (rc == 2)
  1169. {
  1170. TRACE_OUT(( "ToAscii rc=2, result - %04X", result[0]));
  1171. //
  1172. // Succesfully converted to two Ascii keys. If this is
  1173. // a key down then we will return a key down and key up
  1174. // for the `dead' character first then the key down.
  1175. // If its a key up then just return the key up.
  1176. //
  1177. if (!(imEvent.data.keyboard.flags &
  1178. IM_FLAG_KEYBOARD_RELEASE))
  1179. {
  1180. //
  1181. // This is the key down - so generate a fake
  1182. // keyboard press for the dead key.
  1183. //
  1184. IMGenerateFakeKeyPress(IM_TYPE_ASCII,
  1185. LOBYTE(result[0]),
  1186. imEvent.data.keyboard.flags);
  1187. }
  1188. //
  1189. // Now return the current keystroke.
  1190. //
  1191. imEvent.type = IM_TYPE_ASCII;
  1192. imEvent.data.keyboard.keyCode = LOBYTE(result[1]);
  1193. //
  1194. // Try to send the packet.
  1195. //
  1196. if (!IMConvertAndSendEvent(pasHost, &imEvent))
  1197. {
  1198. WARNING_OUT(( "dropped local key press %u",
  1199. (UINT)imEvent.data.keyboard.keyCode));
  1200. }
  1201. }
  1202. else
  1203. {
  1204. //
  1205. // Check for keys that we want to convert.
  1206. //
  1207. if (LOBYTE(wParam) == VK_KANJI)
  1208. {
  1209. //
  1210. // We only see a down press for VK_KANJI so we
  1211. // fake a complete key press so that the remote
  1212. // does not get confused.
  1213. //
  1214. IMGenerateFakeKeyPress(IM_TYPE_VK1,
  1215. VK_KANJI,
  1216. imEvent.data.keyboard.flags);
  1217. }
  1218. else
  1219. {
  1220. //
  1221. // No conversion - use the VK itself.
  1222. //
  1223. imEvent.type = IM_TYPE_VK1;
  1224. imEvent.data.keyboard.keyCode = LOBYTE(wParam);
  1225. //
  1226. // SFR 2537: If this is a right shift VK (which we
  1227. // can detect via the scan code in lParam), set the
  1228. // right_variant keyboard flag. We do not do this
  1229. // for the right-variants of CONTROL and ALT (ie
  1230. // menu) because they are extended keys - already
  1231. // catered for by the extended flag.
  1232. //
  1233. if ( (m_imScanVKRShift != 0) &&
  1234. (m_imScanVKRShift == LOBYTE(HIWORD(lParam))) )
  1235. {
  1236. imEvent.data.keyboard.flags |=
  1237. IM_FLAG_KEYBOARD_RIGHT;
  1238. }
  1239. //
  1240. // Try to send the packet.
  1241. //
  1242. if (!IMConvertAndSendEvent(pasHost, &imEvent))
  1243. {
  1244. WARNING_OUT(( "dropped local key press %u",
  1245. (UINT)imEvent.data.keyboard.keyCode));
  1246. }
  1247. }
  1248. }
  1249. }
  1250. else
  1251. {
  1252. //
  1253. // This is a dead key - add it to our array of dead keys if
  1254. // we haven't already heard about it.
  1255. //
  1256. IMMaybeAddDeadKey(
  1257. (BYTE)imEvent.data.keyboard.keyCode);
  1258. m_imInControlNumDeadKeysDown++;
  1259. TRACE_OUT(( "m_imInControlNumDeadKeysDown - %d",
  1260. m_imInControlNumDeadKeysDown));
  1261. }
  1262. }
  1263. }
  1264. DebugExitVOID(ASShare::IM_OutgoingKeyboardInput);
  1265. }
  1266. //
  1267. // FUNCTION: IMGenerateFakeKeyPress(...)
  1268. //
  1269. // DESCRIPTION:
  1270. //
  1271. // Generates a fake keyboard press.
  1272. //
  1273. // PARAMETERS:
  1274. //
  1275. // type - packet type to generate.
  1276. // key - key to generate press for.
  1277. // flags - flags on keyboard press.
  1278. //
  1279. // RETURNS:
  1280. //
  1281. // Nothing.
  1282. //
  1283. //
  1284. void ASShare::IMGenerateFakeKeyPress
  1285. (
  1286. TSHR_UINT16 type,
  1287. TSHR_UINT16 key,
  1288. TSHR_UINT16 flags
  1289. )
  1290. {
  1291. IMEVENT imEventFake;
  1292. DebugEntry(ASShare::IMGenerateFakeKeyPress);
  1293. TRACE_OUT(( "Faking keyboard press:%#hx type:%#hx", key, type));
  1294. //
  1295. // Generate the key down first of all.
  1296. //
  1297. ZeroMemory(&imEventFake, sizeof(imEventFake));
  1298. imEventFake.type = type;
  1299. imEventFake.timeMS = GetTickCount();
  1300. imEventFake.data.keyboard.keyCode = key;
  1301. //
  1302. // Try to send the packet.
  1303. //
  1304. if (!IMConvertAndSendEvent(m_pasLocal->m_caInControlOf, &imEventFake))
  1305. {
  1306. WARNING_OUT(( "Dropped local key press %hu (flags: %#hx)",
  1307. imEventFake.data.keyboard.keyCode,
  1308. imEventFake.data.keyboard.flags));
  1309. }
  1310. //
  1311. // Set the release and down flags in order to fake the up.
  1312. //
  1313. imEventFake.data.keyboard.flags = IM_FLAG_KEYBOARD_DOWN | IM_FLAG_KEYBOARD_RELEASE;
  1314. //
  1315. // Try to send the packet.
  1316. //
  1317. if (!IMConvertAndSendEvent(m_pasLocal->m_caInControlOf, &imEventFake))
  1318. {
  1319. WARNING_OUT(( "Dropped local key press %hu (flags: %#hx)",
  1320. imEventFake.data.keyboard.keyCode,
  1321. imEventFake.data.keyboard.flags));
  1322. }
  1323. DebugExitVOID(ASShare::IMGenerateFakeKeyPress);
  1324. }
  1325. //
  1326. // FUNCTION: IMConvertAndSendEvent
  1327. //
  1328. // DESCRIPTION:
  1329. //
  1330. // Called with an IMEVENT this function will try to queue (and even send
  1331. // if possible) the packet. If it fails it will return FALSE - the caller
  1332. // should discard the packet. If it succeeds it will return TRUE.
  1333. //
  1334. // If pasFor is us, it means to send to everybody (and coords are relative
  1335. // to sender's screen).
  1336. //
  1337. // If pasFor is a remote, it means that the IM packet is meant for just
  1338. // that person and the coords are relative to pasFor's screen.
  1339. //
  1340. //
  1341. // PARAMETERS:
  1342. //
  1343. // pIMEvent - the IMEVENT to convert and send
  1344. //
  1345. // RETURNS: TRUE or FALSE - success or failure
  1346. //
  1347. //
  1348. BOOL ASShare::IMConvertAndSendEvent
  1349. (
  1350. ASPerson * pasFor,
  1351. PIMEVENT pIMEvent
  1352. )
  1353. {
  1354. BOOL rc = FALSE;
  1355. DebugEntry(ASShare::IMConvertAndSendEvent);
  1356. //
  1357. // If there is already a pending packet then see if we can flush some
  1358. // packets onto the network.
  1359. //
  1360. if (m_imfInControlEventIsPending)
  1361. {
  1362. IMFlushOutgoingEvents();
  1363. }
  1364. //
  1365. // If there is still a pending packet then see if we can spoil some
  1366. // events.
  1367. //
  1368. if (m_imfInControlEventIsPending)
  1369. {
  1370. TRACE_OUT(( "trying to drop mouse move events"));
  1371. IMSpoilEvents();
  1372. IMFlushOutgoingEvents();
  1373. }
  1374. //
  1375. // Now see if we are able to accept a new packet
  1376. //
  1377. if (m_imfInControlEventIsPending)
  1378. {
  1379. //
  1380. // If there is still a previous IMEVENT which we are in the
  1381. // process of converting then we are not ready to receive any more
  1382. // packets.
  1383. //
  1384. TRACE_OUT(( "can't queue packet"));
  1385. DC_QUIT;
  1386. }
  1387. //
  1388. // Now set up the new packet and try to flush the packets again.
  1389. //
  1390. m_imfInControlEventIsPending = TRUE;
  1391. m_imInControlPendingEvent = *pIMEvent;
  1392. IMFlushOutgoingEvents();
  1393. rc = TRUE;
  1394. DC_EXIT_POINT:
  1395. DebugExitBOOL(ASShare::IMConvertAndSendEvent, rc);
  1396. return(rc);
  1397. }
  1398. //
  1399. // FUNCTION: IMMaybeAddDeadKey
  1400. //
  1401. // DESCRIPTION:
  1402. //
  1403. // Called whenever ToAscii tells us about a dead key. If we haven't
  1404. // got it in our table already then we will add it. We create the table
  1405. // incrementally because we have found that some keyboard drivers don't
  1406. // cope very well with being queried with all possible VKs to find the
  1407. // dead keys. Note that this will not cope with someone switching their
  1408. // keyboard driver whilst DC-Share is running.
  1409. //
  1410. // PARAMETERS:
  1411. //
  1412. // vk - the VK in question
  1413. //
  1414. // RETURNS: NONE
  1415. //
  1416. //
  1417. void ASShare::IMMaybeAddDeadKey(BYTE vk)
  1418. {
  1419. UINT i;
  1420. DebugEntry(IMMaybeAddDeadKey);
  1421. //
  1422. // First see if we already know about this key.
  1423. //
  1424. for (i = 0; i < m_imInControlNumDeadKeys; i++)
  1425. {
  1426. if (m_aimInControlDeadKeys[i] == vk)
  1427. {
  1428. DC_QUIT;
  1429. }
  1430. }
  1431. //
  1432. // Add this key if there's space in the array.
  1433. //
  1434. if (m_imInControlNumDeadKeys < IM_MAX_DEAD_KEYS)
  1435. {
  1436. TRACE_OUT(( "Add %02X", (TSHR_UINT16)vk));
  1437. m_aimInControlDeadKeys[m_imInControlNumDeadKeys++] = vk;
  1438. }
  1439. DC_EXIT_POINT:
  1440. DebugExitVOID(ASShare::IMMaybeAddDeadKey);
  1441. }
  1442. //
  1443. // IMConvertIMEventToOSEvent()
  1444. // Converts incoming event to something we can playback.
  1445. //
  1446. // PARAMETERS:
  1447. //
  1448. // pIMEvent - the IMEVENT to be converted
  1449. //
  1450. // pOSEvent - the IMOSEVENT to be created
  1451. //
  1452. //
  1453. UINT ASShare::IMConvertIMEventToOSEvent
  1454. (
  1455. PIMEVENT pIMEvent,
  1456. LPIMOSEVENT pOSEvent
  1457. )
  1458. {
  1459. int mouseX;
  1460. int mouseY;
  1461. int realMouseX;
  1462. int realMouseY;
  1463. RECT cursorClip;
  1464. UINT rc = (IM_IMQUEUEREMOVE | IM_OSQUEUEINJECT);
  1465. DebugEntry(ASShare::IMConvertIMEventToOSEvent);
  1466. switch (pIMEvent->type)
  1467. {
  1468. case IM_TYPE_3BUTTON:
  1469. //
  1470. // Fill in common fields. Note that we claim to be a 3 button
  1471. // mouse so that we can replay events from remote three button
  1472. // mice and we always give absolute coordinates.
  1473. //
  1474. pOSEvent->type = IM_MOUSE_EVENT;
  1475. pOSEvent->flags = 0;
  1476. pOSEvent->time = pIMEvent->timeMS;
  1477. pOSEvent->event.mouse.cButtons = 3;
  1478. pOSEvent->event.mouse.mouseData = 0;
  1479. pOSEvent->event.mouse.dwExtraInfo = 0;
  1480. //
  1481. // First check for a wheel rotate, since this is easy to
  1482. // process. (It cannot include any mouse movement as well).
  1483. //
  1484. if (pIMEvent->data.mouse.flags & IM_FLAG_MOUSE_WHEEL)
  1485. {
  1486. if (pIMEvent->data.mouse.flags &
  1487. (IM_FLAG_MOUSE_BUTTON1 |
  1488. IM_FLAG_MOUSE_BUTTON2 |
  1489. IM_FLAG_MOUSE_BUTTON3))
  1490. {
  1491. //
  1492. // Using any of the button flags along with the wheel
  1493. // flag is currently undefined - for forward
  1494. // compatability we therefore ignore such an event by
  1495. // converting it into a NULL injected event.
  1496. //
  1497. // (We do not sg_lpimSharedData->imply discard it, since the logic to
  1498. // discard events does not seem to work).
  1499. //
  1500. pOSEvent->event.mouse.flags = 0;
  1501. pOSEvent->event.mouse.pt.x = 0;
  1502. pOSEvent->event.mouse.pt.y = 0;
  1503. }
  1504. else
  1505. {
  1506. //
  1507. // This is a wheel movement.
  1508. //
  1509. // Note that the protocol has sent whether the mouse's
  1510. // middle button is depressed or released, but we don't
  1511. // need that info for NT, so just ignore it.
  1512. //
  1513. pOSEvent->event.mouse.flags = MOUSEEVENTF_WHEEL;
  1514. pOSEvent->event.mouse.mouseData =
  1515. (pIMEvent->data.mouse.flags & IM_FLAG_MOUSE_ROTATION_MASK);
  1516. pOSEvent->event.mouse.pt.x = 0;
  1517. pOSEvent->event.mouse.pt.y = 0;
  1518. //
  1519. // Sign extend the rotation amount up to the full 32
  1520. // bits
  1521. //
  1522. if (pOSEvent->event.mouse.mouseData & IM_FLAG_MOUSE_DIRECTION)
  1523. {
  1524. pOSEvent->event.mouse.mouseData |=
  1525. ~IM_FLAG_MOUSE_ROTATION_MASK;
  1526. }
  1527. }
  1528. break;
  1529. }
  1530. //
  1531. // We are left now with non wheel-rotate events.
  1532. //
  1533. pOSEvent->event.mouse.flags = MOUSEEVENTF_ABSOLUTE;
  1534. //
  1535. // We must convert from virtual desktop coordinates to local
  1536. // screen coordinates here and we must also prevent the
  1537. // position wrapping if we try to replay a mouse move to an
  1538. // off-screen position.
  1539. //
  1540. realMouseX = pIMEvent->data.mouse.x;
  1541. realMouseY = pIMEvent->data.mouse.y;
  1542. //
  1543. // Now lg_lpimSharedData->imit to the size of the real screen.
  1544. //
  1545. mouseX = min((m_pasLocal->cpcCaps.screen.capsScreenWidth-1), max(0, realMouseX));
  1546. mouseY = min((m_pasLocal->cpcCaps.screen.capsScreenHeight-1), max(0, realMouseY));
  1547. //
  1548. // Work out if this event will be clipped by the clip cursor
  1549. //
  1550. GetClipCursor(&cursorClip);
  1551. if ((mouseX < cursorClip.left) ||
  1552. (mouseX >= cursorClip.right) ||
  1553. (mouseY < cursorClip.top) ||
  1554. (mouseY >= cursorClip.bottom))
  1555. {
  1556. //
  1557. // This event will actually be clipped because of the
  1558. // current clip cursor. Remember this.
  1559. //
  1560. m_imfControlledMouseClipped = TRUE;
  1561. }
  1562. else
  1563. {
  1564. m_imfControlledMouseClipped = FALSE;
  1565. //
  1566. // If we clamp the mouse position before replaying then we
  1567. // must remember the real packet and make the current
  1568. // packet into a move so that we don't click down/up at the
  1569. // wrong place.
  1570. //
  1571. if ((mouseX != realMouseX) || (mouseY != realMouseY))
  1572. {
  1573. //
  1574. // The mouse position we've recieved is off the
  1575. // local physical screen. Now that we no longer have
  1576. // desktop scrolling, we simply clamp it rather than
  1577. // inject it at the edge and wait for the scroll.
  1578. //
  1579. // We turn mouse down-clicks into moves and let
  1580. // up-clicks pass through (in case the mouse button
  1581. // has been pressed within the real screen).
  1582. //
  1583. // Note that the mouse position has already been
  1584. // adjusted so that it is within the real screen.
  1585. //
  1586. if (pIMEvent->data.mouse.flags & IM_FLAG_MOUSE_DOWN)
  1587. {
  1588. pIMEvent->data.mouse.flags = IM_FLAG_MOUSE_MOVE;
  1589. }
  1590. }
  1591. }
  1592. //
  1593. // Store the mouse position.
  1594. //
  1595. pOSEvent->event.mouse.pt.x = mouseX;
  1596. pOSEvent->event.mouse.pt.y = mouseY;
  1597. //
  1598. // Add more flags as appropriate.
  1599. //
  1600. if (pIMEvent->data.mouse.flags & IM_FLAG_MOUSE_MOVE)
  1601. {
  1602. pOSEvent->event.mouse.flags |= MOUSEEVENTF_MOVE;
  1603. }
  1604. else
  1605. {
  1606. switch (pIMEvent->data.mouse.flags &
  1607. ( IM_FLAG_MOUSE_BUTTON1 |
  1608. IM_FLAG_MOUSE_BUTTON2 |
  1609. IM_FLAG_MOUSE_BUTTON3 |
  1610. IM_FLAG_MOUSE_DOWN ))
  1611. {
  1612. case IM_FLAG_MOUSE_BUTTON1 | IM_FLAG_MOUSE_DOWN:
  1613. pOSEvent->event.mouse.flags |= MOUSEEVENTF_LEFTDOWN;
  1614. break;
  1615. case IM_FLAG_MOUSE_BUTTON1:
  1616. pOSEvent->event.mouse.flags |= MOUSEEVENTF_LEFTUP;
  1617. break;
  1618. case IM_FLAG_MOUSE_BUTTON2 | IM_FLAG_MOUSE_DOWN:
  1619. pOSEvent->event.mouse.flags |= MOUSEEVENTF_RIGHTDOWN;
  1620. break;
  1621. case IM_FLAG_MOUSE_BUTTON2:
  1622. pOSEvent->event.mouse.flags |= MOUSEEVENTF_RIGHTUP;
  1623. break;
  1624. case IM_FLAG_MOUSE_BUTTON3 | IM_FLAG_MOUSE_DOWN:
  1625. pOSEvent->event.mouse.flags |= MOUSEEVENTF_MIDDLEDOWN;
  1626. break;
  1627. case IM_FLAG_MOUSE_BUTTON3:
  1628. pOSEvent->event.mouse.flags |= MOUSEEVENTF_MIDDLEUP;
  1629. break;
  1630. default:
  1631. //
  1632. // If we don't recognise this then don't play it
  1633. // back
  1634. //
  1635. ERROR_OUT(("Unrecognised mouse flags (%04X)",
  1636. pIMEvent->data.mouse.flags));
  1637. rc = IM_IMQUEUEREMOVE;
  1638. break;
  1639. }
  1640. }
  1641. break;
  1642. case IM_TYPE_VK1:
  1643. //
  1644. // Common fields.
  1645. //
  1646. pOSEvent->flags = 0;
  1647. if (pIMEvent->data.keyboard.flags & IM_FLAG_KEYBOARD_UPDATESTATE)
  1648. pOSEvent->flags |= IM_FLAG_UPDATESTATE;
  1649. pOSEvent->time = pIMEvent->timeMS;
  1650. //
  1651. // Now handle normal keyboard events.
  1652. //
  1653. pOSEvent->type = IM_KEYBOARD_EVENT;
  1654. //
  1655. // AX is the scancode in AL and 00h (press) or 80h (release) in
  1656. // AH. Map the DC protocol VK to the equivalent OS VK.
  1657. // AL = the scancode for the VK).
  1658. //
  1659. pOSEvent->event.keyboard.vkCode = LOBYTE(pIMEvent->data.keyboard.keyCode);
  1660. pOSEvent->event.keyboard.flags = 0;
  1661. if (IS_IM_KEY_RELEASE(pIMEvent->data.keyboard.flags))
  1662. {
  1663. pOSEvent->event.keyboard.flags |= KEYEVENTF_KEYUP;
  1664. }
  1665. //
  1666. // SFR 2537: If the flags indicate that the received VK is the
  1667. // right-variant, do not map the VK to a scan code, but rather
  1668. // directly use the already acquired right-variant scan code
  1669. // for the VK. (For the moment, the only case we support is
  1670. // for Windows, where this is an issue for SHIFT).
  1671. //
  1672. if ( IS_IM_KEY_RIGHT(pIMEvent->data.keyboard.flags) &&
  1673. (pIMEvent->data.keyboard.keyCode == VK_SHIFT) )
  1674. {
  1675. pOSEvent->event.keyboard.scanCode = m_imScanVKRShift;
  1676. }
  1677. else
  1678. {
  1679. pOSEvent->event.keyboard.scanCode =
  1680. (WORD)MapVirtualKey(pIMEvent->data.keyboard.keyCode, 0);
  1681. }
  1682. if (pIMEvent->data.keyboard.flags & IM_FLAG_KEYBOARD_EXTENDED)
  1683. {
  1684. pOSEvent->event.keyboard.flags |= KEYEVENTF_EXTENDEDKEY;
  1685. }
  1686. pOSEvent->event.keyboard.dwExtraInfo = 0;
  1687. break;
  1688. default:
  1689. ERROR_OUT(("Unrecognized imEvent (%d)", pIMEvent->type));
  1690. //
  1691. // Discard the event (remove from the IM queue and don't inject
  1692. // into the OS).
  1693. //
  1694. rc = IM_IMQUEUEREMOVE;
  1695. break;
  1696. }
  1697. DebugExitDWORD(ASShare::IMConvertIMEventToOSEvent, rc);
  1698. return(rc);
  1699. }
  1700. //
  1701. // IMTranslateOutgoing()
  1702. //
  1703. // DESCRIPTION:
  1704. //
  1705. // Converts locally generated sequences of IMEVENTs into transmitted
  1706. // sequences of IMEVENTs. Does a 1 to (0-n) translation. Handles
  1707. // buffering modifier keys and translating DC-Share hot-key sequences.
  1708. //
  1709. // When the CA has decided an IMEVENT should be sent this function is
  1710. // called by the IM with a pointer to that packet in pIMEventIn.
  1711. // IMTranslateOutgoing can then return TRUE and fill in the packet at
  1712. // pIMEventOut or return FALSE. If IMTranslateOutgoing returns TRUE the IM
  1713. // will call it again with the same packet. The IMEVENTs returned are
  1714. // sent across the network by the IM.
  1715. //
  1716. // PARAMETERS:
  1717. //
  1718. // pIMEventIn - pointer to IMEVENT
  1719. //
  1720. // pIMEventOut - pointer to IMEVENT
  1721. //
  1722. // RETURNS:
  1723. //
  1724. // TRUE - packet returned (call function again)
  1725. //
  1726. // FALSE - no packet returned (don't call function again)
  1727. //
  1728. //
  1729. BOOL ASShare::IMTranslateOutgoing
  1730. (
  1731. LPIMEVENT pIMEventIn,
  1732. LPIMEVENT pIMEventOut
  1733. )
  1734. {
  1735. UINT hotKeyArrayIndex;
  1736. UINT hotKeyValue;
  1737. BOOL fHotKeyFound;
  1738. BOOL rc = FALSE;
  1739. DebugEntry(ASShare::IMTranslateOutgoing);
  1740. //
  1741. // Here we need to tell the remote system about certain keys which are
  1742. // consumed locally so that it can make good decisions about whether
  1743. // and how to replay them. We want to keep the remote system in step
  1744. // with the current modifier and toggle key state on our system (as it
  1745. // is possible that either a modifier/toggle key event occurred whilst
  1746. // a local app was active and was therefore never sent) We also want to
  1747. // recognise certain `hot key' sequences and send further packets as a
  1748. // result of these.
  1749. //
  1750. // The keys we comsume locally are:
  1751. //
  1752. // Esc down or up when Ctrl is down - operates task list locally
  1753. //
  1754. // Tab down or up when Alt is down - operates task switcher locally
  1755. //
  1756. // Esc down or up when Alt is pressed - switches to next window locally
  1757. //
  1758. // Esc up when corresponding Esc down occurred when Alt was down - as
  1759. // above
  1760. //
  1761. // The sequences we want to produce hot keys from are:
  1762. //
  1763. // Alt + 9?? on the numeric keypad
  1764. //
  1765. // To detect hotkeys we keep a record of the last four keypresses and
  1766. // when we detect an Alt up we check if they form a valid sequence.
  1767. //
  1768. // The keystrokes which form part of the hotkey are sent to the remote
  1769. // system so if they have some meaning on a remote system then that
  1770. // system must decide whether to buffer them to determine if they are
  1771. // part of a hotkey or play them back anyway - on Windows we play them
  1772. // back anyway as they are a legitimate key sequence when controlling a
  1773. // Windows app - the number typed on the numeric keypad has a % 256
  1774. // applied to it.
  1775. //
  1776. // This means that for each incoming event we may want to generate 0 or
  1777. // more outgoing events. To do this we have a structure which looks
  1778. // roughly like this:
  1779. //
  1780. // IF m_m_imfInControlNewEvent
  1781. // calculate an array of events which we want to return
  1782. // set m_m_imfInControlNewEvent to FALSE
  1783. // set number of events returned to 0
  1784. // ENDIF
  1785. //
  1786. // IF !m_m_imfInControlNewEvent
  1787. // IF this is the last event to return
  1788. // set m_m_imfInControlNewEvent to TRUE
  1789. // ENDIF
  1790. // return current event
  1791. // ENDIF
  1792. //
  1793. //
  1794. if (m_imfInControlNewEvent)
  1795. {
  1796. //
  1797. // This is the first time we have seen this event so accumulate
  1798. // our list of events to generate.
  1799. //
  1800. //
  1801. // Do tracing
  1802. //
  1803. if (pIMEventIn->type == IM_TYPE_ASCII)
  1804. {
  1805. TRACE_OUT(( "IN ASCII code 0x%04X, flags 0x%04X",
  1806. pIMEventIn->data.keyboard.keyCode, pIMEventIn->data.keyboard.flags));
  1807. }
  1808. else if (pIMEventIn->type == IM_TYPE_VK1)
  1809. {
  1810. TRACE_OUT(( "IN VKEY code %04X, flags %04X",
  1811. pIMEventIn->data.keyboard.keyCode, pIMEventIn->data.keyboard.flags));
  1812. }
  1813. else if ((pIMEventIn->type == IM_TYPE_3BUTTON) &&
  1814. !(pIMEventIn->data.mouse.flags & IM_FLAG_MOUSE_MOVE))
  1815. {
  1816. TRACE_OUT(( "IN 3BTTN flags %04X (%d,%d)",
  1817. pIMEventIn->data.mouse.flags, pIMEventIn->data.mouse.x,
  1818. pIMEventIn->data.mouse.y));
  1819. }
  1820. else if (pIMEventIn->type == IM_TYPE_3BUTTON)
  1821. {
  1822. TRACE_OUT(( "IN 3BTTN flags %04X (%d,%d)",
  1823. pIMEventIn->data.mouse.flags, pIMEventIn->data.mouse.x,
  1824. pIMEventIn->data.mouse.y));
  1825. }
  1826. else if (pIMEventIn->type == IM_TYPE_VK_ASCII)
  1827. {
  1828. TRACE_OUT(("IN VK_ASC code %04X, flags %04X",
  1829. pIMEventIn->data.keyboard.keyCode, pIMEventIn->data.keyboard.flags));
  1830. }
  1831. else
  1832. {
  1833. ERROR_OUT(("Invalid IM type %d", pIMEventIn->type));
  1834. }
  1835. //
  1836. // Start from the beginning of our returned events array.
  1837. //
  1838. m_imInControlNumEventsPending = 0;
  1839. m_imInControlNumEventsReturned = 0;
  1840. //
  1841. // First get our flags for the modifiers and locks we think we have
  1842. // sent to the remote side up to date allowing for this event.
  1843. //
  1844. if (pIMEventIn->type == IM_TYPE_VK1)
  1845. {
  1846. switch (pIMEventIn->data.keyboard.keyCode)
  1847. {
  1848. case VK_CONTROL:
  1849. if (IS_IM_KEY_RELEASE(pIMEventIn->data.keyboard.flags))
  1850. {
  1851. m_imfInControlCtrlDown = FALSE;
  1852. }
  1853. else
  1854. {
  1855. m_imfInControlCtrlDown = TRUE;
  1856. }
  1857. break;
  1858. case VK_SHIFT:
  1859. if (IS_IM_KEY_RELEASE(pIMEventIn->data.keyboard.flags))
  1860. {
  1861. m_imfInControlShiftDown = FALSE;
  1862. }
  1863. else
  1864. {
  1865. m_imfInControlShiftDown = TRUE;
  1866. }
  1867. break;
  1868. case VK_MENU:
  1869. if (IS_IM_KEY_RELEASE(pIMEventIn->data.keyboard.flags))
  1870. {
  1871. m_imfInControlMenuDown = FALSE;
  1872. }
  1873. else
  1874. {
  1875. m_imfInControlMenuDown = TRUE;
  1876. }
  1877. break;
  1878. case VK_CAPITAL:
  1879. if (IS_IM_KEY_PRESS(pIMEventIn->data.keyboard.flags))
  1880. {
  1881. m_imfInControlCapsLock = !m_imfInControlCapsLock;
  1882. }
  1883. break;
  1884. case VK_NUMLOCK:
  1885. if (IS_IM_KEY_PRESS(pIMEventIn->data.keyboard.flags))
  1886. {
  1887. m_imfInControlNumLock = !m_imfInControlNumLock;
  1888. }
  1889. break;
  1890. case VK_SCROLL:
  1891. if (IS_IM_KEY_PRESS(pIMEventIn->data.keyboard.flags))
  1892. {
  1893. m_imfInControlScrollLock = !m_imfInControlScrollLock;
  1894. }
  1895. break;
  1896. default:
  1897. break;
  1898. }
  1899. }
  1900. //
  1901. // Now check the current state versus our remembered state and
  1902. // prepare to insert events if necessary. Do this for any events
  1903. // (ie including mouse events) as mouse clicks can have different
  1904. // effects depending on the current modifer state.
  1905. //
  1906. //
  1907. // First the modifiers. IMGetHighLevelKeyState will return us the
  1908. // keyboard state including the event we are currently processing
  1909. // because it is adjusted before the keyboard hook. The top most
  1910. // bit is set of the key is down otherwise it is reset.
  1911. //
  1912. if (IMGetHighLevelKeyState(VK_CONTROL) & 0x80)
  1913. {
  1914. if (!m_imfInControlCtrlDown)
  1915. {
  1916. //
  1917. // The key is down locally but we last told the remote
  1918. // machine it was up.
  1919. //
  1920. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1921. IEM_EVENT_CTRL_DOWN;
  1922. m_imfInControlCtrlDown = TRUE;
  1923. }
  1924. }
  1925. else
  1926. {
  1927. if (m_imfInControlCtrlDown)
  1928. {
  1929. //
  1930. // The key is up locally but we last told the remote
  1931. // machine it was down.
  1932. //
  1933. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1934. IEM_EVENT_CTRL_UP;
  1935. m_imfInControlCtrlDown = FALSE;
  1936. }
  1937. }
  1938. //
  1939. // Do the same for shift and menu (alt).
  1940. //
  1941. if (IMGetHighLevelKeyState(VK_SHIFT) & 0x80)
  1942. {
  1943. if (!m_imfInControlShiftDown)
  1944. {
  1945. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1946. IEM_EVENT_SHIFT_DOWN;
  1947. m_imfInControlShiftDown = TRUE;
  1948. }
  1949. }
  1950. else
  1951. {
  1952. if (m_imfInControlShiftDown)
  1953. {
  1954. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1955. IEM_EVENT_SHIFT_UP;
  1956. m_imfInControlShiftDown = FALSE;
  1957. }
  1958. }
  1959. if (IMGetHighLevelKeyState(VK_MENU) & 0x80)
  1960. {
  1961. if (!m_imfInControlMenuDown)
  1962. {
  1963. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1964. IEM_EVENT_MENU_DOWN;
  1965. m_imfInControlMenuDown = TRUE;
  1966. }
  1967. }
  1968. else
  1969. {
  1970. if (m_imfInControlMenuDown)
  1971. {
  1972. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1973. IEM_EVENT_MENU_UP;
  1974. m_imfInControlMenuDown = FALSE;
  1975. }
  1976. }
  1977. //
  1978. // Now handle the toggles. The least significant bit is set when
  1979. // the toggle is on, reset otherwise.
  1980. //
  1981. if ((IMGetHighLevelKeyState(VK_CAPITAL) & IM_KEY_STATE_FLAG_TOGGLE) ?
  1982. !m_imfInControlCapsLock : m_imfInControlCapsLock)
  1983. {
  1984. //
  1985. // The current caps lock state and what we've sent to the
  1986. // remote system are out of synch - fix it.
  1987. //
  1988. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1989. IEM_EVENT_CAPS_LOCK_DOWN;
  1990. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  1991. IEM_EVENT_CAPS_LOCK_UP;
  1992. m_imfInControlCapsLock = !m_imfInControlCapsLock;
  1993. }
  1994. //
  1995. // Do the same for Num lock and Scroll lock.
  1996. //
  1997. if ((IMGetHighLevelKeyState(VK_NUMLOCK) & 0x01) ?
  1998. !m_imfInControlNumLock : m_imfInControlNumLock)
  1999. {
  2000. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2001. IEM_EVENT_NUM_LOCK_DOWN;
  2002. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2003. IEM_EVENT_NUM_LOCK_UP;
  2004. m_imfInControlNumLock = !m_imfInControlNumLock;
  2005. }
  2006. if ((IMGetHighLevelKeyState(VK_SCROLL) & 0x01) ?
  2007. !m_imfInControlScrollLock : m_imfInControlScrollLock)
  2008. {
  2009. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2010. IEM_EVENT_SCROLL_LOCK_DOWN;
  2011. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2012. IEM_EVENT_SCROLL_LOCK_UP;
  2013. m_imfInControlScrollLock = !m_imfInControlScrollLock;
  2014. }
  2015. //
  2016. // Now we will do the appropriate processing for each type of
  2017. // packet we expect. We only expect to receive
  2018. //
  2019. // IM_TYPE_VK1
  2020. // IM_TYPE_ASCII
  2021. // IM_TYPE_3BUTTON
  2022. //
  2023. //
  2024. if (pIMEventIn->type == IM_TYPE_VK1)
  2025. {
  2026. //
  2027. // Now process a VK packet generated from the real keyboard.
  2028. // Check for Escape, Tab and Menu and decide whether to forward
  2029. // them or consume them first.
  2030. //
  2031. if (pIMEventIn->data.keyboard.keyCode == VK_ESCAPE)
  2032. {
  2033. //
  2034. // This is the escape key - check the current shift status
  2035. // to see whether we should flag this as consumed locally.
  2036. //
  2037. if (IMGetHighLevelKeyState(VK_MENU) & 0x80)
  2038. {
  2039. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2040. IEM_EVENT_CONSUMED;
  2041. //
  2042. // Also remember to consume the next Menu Up keystroke.
  2043. //
  2044. m_imfInControlConsumeMenuUp = TRUE;
  2045. if (!IS_IM_KEY_RELEASE(pIMEventIn->data.keyboard.flags))
  2046. {
  2047. //
  2048. // If this is an escape press then remember that we
  2049. // should consume the corresponding up stroke
  2050. // regardless of shift state.
  2051. //
  2052. m_imfInControlConsumeEscapeUp = TRUE;
  2053. }
  2054. }
  2055. else if (m_imfInControlConsumeEscapeUp &&
  2056. IS_IM_KEY_RELEASE(pIMEventIn->data.keyboard.flags))
  2057. {
  2058. //
  2059. // This is the up stroke corresponding to a down
  2060. // stroke we consumed so consume it too.
  2061. //
  2062. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2063. IEM_EVENT_CONSUMED;
  2064. m_imfInControlConsumeEscapeUp = FALSE;
  2065. }
  2066. else
  2067. {
  2068. //
  2069. // This Escape is not one of our special cases so
  2070. // forward it unchanged.
  2071. //
  2072. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2073. IEM_EVENT_FORWARD;
  2074. }
  2075. }
  2076. else if (pIMEventIn->data.keyboard.keyCode == VK_TAB)
  2077. {
  2078. //
  2079. // This is the Tab key - check for current shift status to
  2080. // see whether we should flag this as consumed locally.
  2081. //
  2082. if (IMGetHighLevelKeyState(VK_MENU) & 0x80)
  2083. {
  2084. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2085. IEM_EVENT_CONSUMED;
  2086. //
  2087. // Also remember to consume the next Menu Up keystroke.
  2088. //
  2089. m_imfInControlConsumeMenuUp = TRUE;
  2090. }
  2091. else
  2092. {
  2093. //
  2094. // This Tab is not our special case so forward it
  2095. // unchanged.
  2096. //
  2097. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2098. IEM_EVENT_FORWARD;
  2099. }
  2100. }
  2101. else if ((pIMEventIn->data.keyboard.keyCode == VK_MENU) &&
  2102. IS_IM_KEY_RELEASE(pIMEventIn->data.keyboard.flags))
  2103. {
  2104. //
  2105. // This is a menu up - check for one we should consume or
  2106. // for hotkeys.
  2107. //
  2108. if (m_imfInControlConsumeMenuUp)
  2109. {
  2110. //
  2111. // This is a menu up we want to consume - do so.
  2112. //
  2113. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2114. IEM_EVENT_CONSUMED;
  2115. m_imfInControlConsumeMenuUp = FALSE;
  2116. }
  2117. else
  2118. {
  2119. //
  2120. // This is a VK_MENU release
  2121. // hot key sequence in our array of last four key
  2122. // presses. Start looking at the next entry (the array
  2123. // is circular). A valid sequence is
  2124. //
  2125. // VK_MENU
  2126. // numeric pad 9
  2127. // numeric pad number
  2128. // numeric pad number
  2129. //
  2130. //
  2131. fHotKeyFound = FALSE;
  2132. hotKeyArrayIndex = m_imInControlNextHotKeyEntry;
  2133. if (m_aimInControlHotKeyArray[hotKeyArrayIndex] == VK_MENU)
  2134. {
  2135. hotKeyArrayIndex = (hotKeyArrayIndex+1)%4;
  2136. if (m_aimInControlHotKeyArray[hotKeyArrayIndex] == 9)
  2137. {
  2138. hotKeyArrayIndex = (hotKeyArrayIndex+1)%4;
  2139. if (m_aimInControlHotKeyArray[hotKeyArrayIndex] <= 9)
  2140. {
  2141. hotKeyValue =
  2142. 10*m_aimInControlHotKeyArray[hotKeyArrayIndex];
  2143. hotKeyArrayIndex = (hotKeyArrayIndex+1)%4;
  2144. if (m_aimInControlHotKeyArray[hotKeyArrayIndex] <= 9)
  2145. {
  2146. //
  2147. // This is a valid hot key - add a
  2148. // consumed VK_MENU and then a hot key
  2149. // packet.
  2150. //
  2151. hotKeyValue +=
  2152. m_aimInControlHotKeyArray[hotKeyArrayIndex];
  2153. m_aimInControlEventsToReturn[
  2154. m_imInControlNumEventsPending++] =
  2155. IEM_EVENT_CONSUMED;
  2156. m_aimInControlEventsToReturn[
  2157. m_imInControlNumEventsPending++] =
  2158. IEM_EVENT_HOTKEY_BASE + hotKeyValue;
  2159. TRACE_OUT(("Hotkey found %d", hotKeyValue));
  2160. fHotKeyFound = TRUE;
  2161. }
  2162. }
  2163. }
  2164. }
  2165. if (!fHotKeyFound)
  2166. {
  2167. //
  2168. // This was not a hotkey so send the menu up as
  2169. // normal.
  2170. //
  2171. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2172. IEM_EVENT_FORWARD;
  2173. }
  2174. }
  2175. }
  2176. else if (IS_IM_KEY_PRESS(pIMEventIn->data.keyboard.flags))
  2177. {
  2178. //
  2179. // Keep a record of the last four key presses (not
  2180. // including auto
  2181. // VK_MENU up event to determine if we have found a hotkey
  2182. // sequence.
  2183. //
  2184. //
  2185. // This is a key press and it is not a repeat. Throw out
  2186. // extended keys here so that we're not confused by the
  2187. // grey cursor keys.
  2188. //
  2189. if (pIMEventIn->data.keyboard.flags &
  2190. IM_FLAG_KEYBOARD_EXTENDED)
  2191. {
  2192. //
  2193. // An extended key breaks the sequence.
  2194. //
  2195. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 0xFF;
  2196. }
  2197. else
  2198. {
  2199. //
  2200. // Add an entry to our array for this key. We add
  2201. // VK_MENUs and add and translate numeric keypad keys
  2202. // anything else breaks the sequencs.
  2203. //
  2204. switch (pIMEventIn->data.keyboard.keyCode)
  2205. {
  2206. case VK_MENU:
  2207. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = VK_MENU;
  2208. break;
  2209. case VK_NUMPAD0:
  2210. case VK_INSERT:
  2211. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 0;
  2212. break;
  2213. case VK_NUMPAD1:
  2214. case VK_END:
  2215. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 1;
  2216. break;
  2217. case VK_NUMPAD2:
  2218. case VK_DOWN:
  2219. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 2;
  2220. break;
  2221. case VK_NUMPAD3:
  2222. case VK_NEXT:
  2223. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 3;
  2224. break;
  2225. case VK_NUMPAD4:
  2226. case VK_LEFT:
  2227. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 4;
  2228. break;
  2229. case VK_NUMPAD5:
  2230. case VK_CLEAR:
  2231. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 5;
  2232. break;
  2233. case VK_NUMPAD6:
  2234. case VK_RIGHT:
  2235. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 6;
  2236. break;
  2237. case VK_NUMPAD7:
  2238. case VK_HOME:
  2239. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 7;
  2240. break;
  2241. case VK_NUMPAD8:
  2242. case VK_UP:
  2243. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 8;
  2244. break;
  2245. case VK_NUMPAD9:
  2246. case VK_PRIOR:
  2247. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 9;
  2248. break;
  2249. default:
  2250. //
  2251. // Any unrecognised key breaks a sequence.
  2252. //
  2253. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 0xFF;
  2254. break;
  2255. }
  2256. }
  2257. //
  2258. // Wrap the hot key array at 4 entries.
  2259. //
  2260. m_imInControlNextHotKeyEntry = (m_imInControlNextHotKeyEntry+1)%4;
  2261. //
  2262. // Forward the event.
  2263. //
  2264. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2265. IEM_EVENT_FORWARD;
  2266. }
  2267. else
  2268. {
  2269. //
  2270. // Just forward the event as its not any of our special
  2271. // cases.
  2272. //
  2273. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2274. IEM_EVENT_FORWARD;
  2275. }
  2276. }
  2277. else if (pIMEventIn->type == IM_TYPE_VK_ASCII)
  2278. {
  2279. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2280. IEM_EVENT_FORWARD;
  2281. }
  2282. else if (pIMEventIn->type == IM_TYPE_ASCII)
  2283. {
  2284. //
  2285. // Any IM_TYPE_ASCII breaks the hot key sequence.
  2286. //
  2287. m_aimInControlHotKeyArray[m_imInControlNextHotKeyEntry] = 0xFF;
  2288. m_imInControlNextHotKeyEntry = (m_imInControlNextHotKeyEntry+1)%4;
  2289. //
  2290. // Then just forward the thing without doing anything clever.
  2291. //
  2292. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2293. IEM_EVENT_FORWARD;
  2294. }
  2295. else if (pIMEventIn->type == IM_TYPE_3BUTTON)
  2296. {
  2297. //
  2298. // To be nice and clean we would ideally have a completely new
  2299. // event for the wheeled Microsoft mouse. However to maintain
  2300. // backwards compatibility, we send the event out in such a way
  2301. // that old incompatible systems interpret it as a NULL mouse
  2302. // move.
  2303. //
  2304. if (pIMEventIn->data.mouse.flags & IM_FLAG_MOUSE_WHEEL)
  2305. {
  2306. //
  2307. // This is a wheel rotatation.
  2308. //
  2309. // We massage this event so that new systems can see it for
  2310. // what it truly is - a wheel rotation, but old systems
  2311. // (which check the MOUSE_MOVE flag first, and ignore all
  2312. // other flags if set) see it as a mouse move.
  2313. //
  2314. // We did not set the MOUSE_MOVE flag when we first
  2315. // generated this event, since we did not want to trigger
  2316. // any of the sending side mouse move processing which
  2317. // would otherwise have been invoked.
  2318. //
  2319. pIMEventIn->data.mouse.flags |= IM_FLAG_MOUSE_MOVE;
  2320. }
  2321. //
  2322. // Forward the event
  2323. //
  2324. m_aimInControlEventsToReturn[m_imInControlNumEventsPending++] =
  2325. IEM_EVENT_FORWARD;
  2326. }
  2327. //
  2328. // Now we are going into a loop to return the m_iemLocalEvents we
  2329. // have queued up. We will return the first one below and then be
  2330. // called again until we have returned them all and return FALSE.
  2331. //
  2332. m_imfInControlNewEvent = FALSE;
  2333. m_imInControlNumEventsReturned = 0;
  2334. }
  2335. if (!m_imfInControlNewEvent)
  2336. {
  2337. if (m_imInControlNumEventsReturned == m_imInControlNumEventsPending)
  2338. {
  2339. //
  2340. // There are no more m_aiemLocalEvents to return.
  2341. //
  2342. TRACE_OUT(( "NO MORE EVENTS"));
  2343. m_imfInControlNewEvent = TRUE;
  2344. DC_QUIT;
  2345. }
  2346. else
  2347. {
  2348. //
  2349. // Return the next event.
  2350. //
  2351. if (m_aimInControlEventsToReturn[m_imInControlNumEventsReturned] >=
  2352. IEM_EVENT_HOTKEY_BASE)
  2353. {
  2354. TRACE_OUT(( "HOTKEY "));
  2355. //
  2356. // Return a hotkey event.
  2357. //
  2358. pIMEventOut->type = IM_TYPE_VK2;
  2359. pIMEventOut->data.keyboard.keyCode = (TSHR_UINT16)
  2360. (m_aimInControlEventsToReturn[m_imInControlNumEventsReturned] -
  2361. IEM_EVENT_HOTKEY_BASE);
  2362. pIMEventOut->data.keyboard.flags = 0;
  2363. }
  2364. else
  2365. {
  2366. //
  2367. // Return a non-hotkey event.
  2368. //
  2369. switch (m_aimInControlEventsToReturn[m_imInControlNumEventsReturned])
  2370. {
  2371. case IEM_EVENT_CTRL_DOWN:
  2372. TRACE_OUT(( "CTRL DWN"));
  2373. //
  2374. // Set up a Ctrl down event.
  2375. //
  2376. pIMEventOut->type = IM_TYPE_VK1;
  2377. pIMEventOut->data.keyboard.keyCode = VK_CONTROL;
  2378. pIMEventOut->data.keyboard.flags = 0;
  2379. break;
  2380. case IEM_EVENT_CTRL_UP:
  2381. TRACE_OUT(( "CTRL UP "));
  2382. //
  2383. // Set up a Ctrl up event with the quiet flag set
  2384. // - this means it should have no effect (other
  2385. // than to release the control key).
  2386. //
  2387. pIMEventOut->type = IM_TYPE_VK1;
  2388. pIMEventOut->data.keyboard.keyCode = VK_CONTROL;
  2389. pIMEventOut->data.keyboard.flags =
  2390. IM_FLAG_KEYBOARD_DOWN |
  2391. IM_FLAG_KEYBOARD_RELEASE |
  2392. IM_FLAG_KEYBOARD_QUIET;
  2393. break;
  2394. case IEM_EVENT_SHIFT_DOWN:
  2395. TRACE_OUT(( "SHFT DWN"));
  2396. //
  2397. // Set up a Shift down event.
  2398. //
  2399. pIMEventOut->type = IM_TYPE_VK1;
  2400. pIMEventOut->data.keyboard.keyCode = VK_SHIFT;
  2401. pIMEventOut->data.keyboard.flags = 0;
  2402. break;
  2403. case IEM_EVENT_SHIFT_UP:
  2404. TRACE_OUT(( "SHFT UP "));
  2405. //
  2406. // Set up a Shift up event with the quiet flag set
  2407. // - this means it should have no effect (other
  2408. // than to release the shift key).
  2409. //
  2410. pIMEventOut->type = IM_TYPE_VK1;
  2411. pIMEventOut->data.keyboard.keyCode = VK_SHIFT;
  2412. pIMEventOut->data.keyboard.flags =
  2413. IM_FLAG_KEYBOARD_DOWN |
  2414. IM_FLAG_KEYBOARD_RELEASE |
  2415. IM_FLAG_KEYBOARD_QUIET;
  2416. break;
  2417. case IEM_EVENT_MENU_DOWN:
  2418. TRACE_OUT(( "MENU DWN"));
  2419. //
  2420. // Set up a Menu down event.
  2421. //
  2422. pIMEventOut->type = IM_TYPE_VK1;
  2423. pIMEventOut->data.keyboard.keyCode = VK_MENU;
  2424. break;
  2425. case IEM_EVENT_MENU_UP:
  2426. TRACE_OUT(( "MENU UP "));
  2427. //
  2428. // Set up a Ctrl down event with the quiet flag set
  2429. // - ths is means it should have no effect (other
  2430. // than to release the menu key).
  2431. //
  2432. pIMEventOut->type = IM_TYPE_VK1;
  2433. pIMEventOut->data.keyboard.keyCode = VK_MENU;
  2434. pIMEventOut->data.keyboard.flags =
  2435. IM_FLAG_KEYBOARD_DOWN |
  2436. IM_FLAG_KEYBOARD_RELEASE |
  2437. IM_FLAG_KEYBOARD_QUIET;
  2438. break;
  2439. case IEM_EVENT_CAPS_LOCK_DOWN:
  2440. TRACE_OUT(( "CAPS DWN"));
  2441. //
  2442. // Send a caps lock down.
  2443. //
  2444. pIMEventOut->type = IM_TYPE_VK1;
  2445. pIMEventOut->data.keyboard.keyCode = VK_CAPITAL;
  2446. pIMEventOut->data.keyboard.flags = 0;
  2447. break;
  2448. case IEM_EVENT_CAPS_LOCK_UP:
  2449. TRACE_OUT(( "CAPS UP "));
  2450. //
  2451. // Send a caps lock up.
  2452. //
  2453. pIMEventOut->type = IM_TYPE_VK1;
  2454. pIMEventOut->data.keyboard.keyCode = VK_CAPITAL;
  2455. pIMEventOut->data.keyboard.flags =
  2456. IM_FLAG_KEYBOARD_DOWN |
  2457. IM_FLAG_KEYBOARD_RELEASE;
  2458. break;
  2459. case IEM_EVENT_NUM_LOCK_DOWN:
  2460. TRACE_OUT(( "NUM DOWN"));
  2461. //
  2462. // Send a num lock down - num lock is an extended
  2463. // key.
  2464. //
  2465. pIMEventOut->type = IM_TYPE_VK1;
  2466. pIMEventOut->data.keyboard.keyCode = VK_NUMLOCK;
  2467. pIMEventOut->data.keyboard.flags =
  2468. IM_FLAG_KEYBOARD_EXTENDED;
  2469. break;
  2470. case IEM_EVENT_NUM_LOCK_UP:
  2471. //
  2472. // Send a num lock up - num lock is an extended
  2473. // key.
  2474. //
  2475. TRACE_OUT(( "NUM UP "));
  2476. pIMEventOut->type = IM_TYPE_VK1;
  2477. pIMEventOut->data.keyboard.keyCode = VK_NUMLOCK;
  2478. pIMEventOut->data.keyboard.flags =
  2479. IM_FLAG_KEYBOARD_DOWN |
  2480. IM_FLAG_KEYBOARD_RELEASE |
  2481. IM_FLAG_KEYBOARD_EXTENDED;
  2482. break;
  2483. case IEM_EVENT_SCROLL_LOCK_DOWN:
  2484. //
  2485. // Send a scroll lock down.
  2486. //
  2487. TRACE_OUT(( "SCROLDWN"));
  2488. pIMEventOut->type = IM_TYPE_VK1;
  2489. pIMEventOut->data.keyboard.keyCode = VK_SCROLL;
  2490. pIMEventOut->data.keyboard.flags = 0;
  2491. break;
  2492. case IEM_EVENT_SCROLL_LOCK_UP:
  2493. //
  2494. // Send a scroll lock up.
  2495. //
  2496. TRACE_OUT(( "SCROLLUP"));
  2497. pIMEventOut->type = IM_TYPE_VK1;
  2498. pIMEventOut->data.keyboard.keyCode = VK_SCROLL;
  2499. pIMEventOut->data.keyboard.flags =
  2500. IM_FLAG_KEYBOARD_DOWN |
  2501. IM_FLAG_KEYBOARD_RELEASE;
  2502. break;
  2503. case IEM_EVENT_FORWARD:
  2504. //
  2505. // Just copy the packet.
  2506. //
  2507. TRACE_OUT(( "FORWARD"));
  2508. *pIMEventOut = *pIMEventIn;
  2509. break;
  2510. case IEM_EVENT_CONSUMED:
  2511. //
  2512. // Copy the packet and set the flag.
  2513. //
  2514. TRACE_OUT(( "CONSUMED"));
  2515. *pIMEventOut = *pIMEventIn;
  2516. pIMEventOut->data.keyboard.flags |=
  2517. IM_FLAG_KEYBOARD_QUIET;
  2518. break;
  2519. default:
  2520. ERROR_OUT(( "Invalid code path"));
  2521. break;
  2522. }
  2523. }
  2524. m_imInControlNumEventsReturned++;
  2525. //
  2526. // Do tracing
  2527. //
  2528. if (pIMEventOut->type == IM_TYPE_ASCII)
  2529. {
  2530. TRACE_OUT(( "OUT ASCII code %04X, flags %04X",
  2531. pIMEventOut->data.keyboard.keyCode, pIMEventOut->data.keyboard.flags));
  2532. }
  2533. else if (pIMEventOut->type == IM_TYPE_VK1)
  2534. {
  2535. TRACE_OUT(( "OUT VK1 code %04X, flags %04X",
  2536. pIMEventOut->data.keyboard.keyCode, pIMEventOut->data.keyboard.flags));
  2537. }
  2538. else if (pIMEventOut->type == IM_TYPE_VK2)
  2539. {
  2540. TRACE_OUT(( "OUT VK2 code - %04X, flags - %04X",
  2541. pIMEventOut->data.keyboard.keyCode, pIMEventOut->data.keyboard.flags));
  2542. }
  2543. else if ((pIMEventOut->type == IM_TYPE_3BUTTON) &&
  2544. !(pIMEventOut->data.mouse.flags & IM_FLAG_MOUSE_MOVE))
  2545. {
  2546. TRACE_OUT(( "OUT 3BTTN flags - %04X (%d,%d)",
  2547. pIMEventOut->data.mouse.flags, pIMEventOut->data.mouse.x,
  2548. pIMEventOut->data.mouse.y));
  2549. }
  2550. else if (pIMEventOut->type == IM_TYPE_3BUTTON)
  2551. {
  2552. TRACE_OUT(( "OUT 3BTTN flags - %04X (%d,%d)",
  2553. pIMEventOut->data.mouse.flags, pIMEventOut->data.mouse.x,
  2554. pIMEventOut->data.mouse.y));
  2555. }
  2556. else
  2557. {
  2558. ERROR_OUT(("Invalid IM type %d", pIMEventOut->type));
  2559. }
  2560. rc = TRUE;
  2561. }
  2562. }
  2563. DC_EXIT_POINT:
  2564. DebugExitVOID(ASShare::IMTranslateOutgoing);
  2565. return(rc);
  2566. }
  2567. //
  2568. // IMTranslateIncoming()
  2569. //
  2570. // DESCRIPTION:
  2571. //
  2572. // Converts remotely generated sequences of IMEVENTs into sequences of
  2573. // IMEVENTs for replay. Does a 1 to (0-n) translation. Handles faking
  2574. // keys using ALT and keypad.
  2575. //
  2576. // When an IMEVENT is received and is ready to be replayed this function
  2577. // is called with a pointer to that packet in pIMEventIn.
  2578. // IMTranslateIncoming can then return TRUE and fill in the packet at
  2579. // pIMEventOut or return FALSE. If IMTranslateIncoming returns TRUE the
  2580. // IM will call it again with the same packet. The IMEVENTs returned are
  2581. // played back on the local machine using the journal playback hook by the
  2582. // IM.
  2583. //
  2584. // PARAMETERS:
  2585. //
  2586. // pIMEventIn - pointer to IMEVENT
  2587. //
  2588. // pIMEventOut - pointer to IMEVENT
  2589. //
  2590. // personID - the ID of the person this event was received from
  2591. //
  2592. // RETURNS:
  2593. //
  2594. // TRUE - packet returned (call function again)
  2595. //
  2596. // FALSE - no packet returned (don't call function again)
  2597. //
  2598. //
  2599. //
  2600. BOOL ASShare::IMTranslateIncoming
  2601. (
  2602. PIMEVENT pIMEventIn,
  2603. PIMEVENT pIMEventOut
  2604. )
  2605. {
  2606. BYTE curKbState;
  2607. BYTE rcVkKeyScanKbState;
  2608. UINT keyCode;
  2609. TSHR_UINT16 rcVkKeyScan;
  2610. BOOL bTranslateOEM;
  2611. char chAnsi;
  2612. char chOEM;
  2613. char chNewAnsi;
  2614. UINT position;
  2615. UINT digit;
  2616. UINT i;
  2617. DebugEntry(ASShare::IMTranslateIncoming);
  2618. //
  2619. // In this function we will receive several types of events
  2620. //
  2621. // IM_TYPE_VK1 - processed
  2622. // IM_TYPE_ASCII - processed
  2623. // IM_TYPE_VK2 - ignored (discarded)
  2624. // IM_TYPE_3BUTTON - processed
  2625. //
  2626. // For IM_TYPE_VK1:
  2627. //
  2628. // If it has the consumed locally flag set then try and play it back
  2629. // without anything happening. This means that for an Alt up we make
  2630. // sure that there have been some keyboard events between the Alt down
  2631. // and this event.
  2632. //
  2633. // For IM_TYPE_ASCII:
  2634. //
  2635. // Try to convert this to a VK to playback. If we are succesful then
  2636. // playback one or more key strokes to get into the correct shift state
  2637. // then play back the VK and then undo any shift states. If we can't
  2638. // convert to a VK then fake a sequence of Alt + numeric keypad keys to
  2639. // get the key in.
  2640. //
  2641. // For IM_TYPE_VK2:
  2642. //
  2643. // Discard unceremoniously.
  2644. //
  2645. // For IM_TYPE_3BUTTON:
  2646. //
  2647. // Play back directly.
  2648. //
  2649. //
  2650. keyCode = pIMEventIn->data.keyboard.keyCode;
  2651. if (m_imfControlledNewEvent)
  2652. {
  2653. //
  2654. // The first time we have seen a new event - accumulate an array
  2655. // of events we want to return.
  2656. //
  2657. //
  2658. // Start from the beginning of our returned events array.
  2659. //
  2660. m_imControlledNumEventsPending = 0;
  2661. m_imControlledNumEventsReturned = 0;
  2662. if (pIMEventIn->type == IM_TYPE_VK1)
  2663. {
  2664. //
  2665. // Handle VK1s first. Special cases are VK_MENU, VK_TAB and
  2666. // VK_ESC. We recognise VK_MENU down key strokes and remember
  2667. // when they happened so that we can possibly fiddle with
  2668. // VK_MENU up keystrokes later to go into menu mode. We check
  2669. // on VK_TAB for the IM_FLAG_KEYBOARD_QUIET flag and if it is
  2670. // set then we don't replay anything
  2671. // First translate the virtual key code from the DC-Share
  2672. // protocol code to the OS virtual key code
  2673. //
  2674. if (keyCode == VK_MENU)
  2675. {
  2676. if (!IS_IM_KEY_RELEASE(pIMEventIn->data.keyboard.flags))
  2677. {
  2678. //
  2679. // This is a VK_MENU press - return it without
  2680. // interfering.
  2681. //
  2682. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2683. IEM_EVENT_REPLAY;
  2684. }
  2685. else
  2686. {
  2687. //
  2688. // Handle VK_MENU up events
  2689. //
  2690. // If the menu up has the `quiet' flag set then
  2691. // insert a couple of shift key events to prevent it
  2692. // having any effect. There are two cases we're
  2693. // covering here where an Alt-UP can have some effect.
  2694. //
  2695. // 1. Alt-Down, Alt-Up causes the system menu button to
  2696. // be highlighted.
  2697. //
  2698. // 2. Entering characters from the numeric keypad takes
  2699. // effect on the Alt-Up.
  2700. //
  2701. // Both of these effects can be negated by adding the
  2702. // shift key strokes.
  2703. //
  2704. if (pIMEventIn->data.keyboard.flags &
  2705. IM_FLAG_KEYBOARD_QUIET)
  2706. {
  2707. //
  2708. // We need to `silence' this key - to do this we
  2709. // will insert to shift key strokes first
  2710. //
  2711. if (m_aimControlledControllerKeyStates[VK_SHIFT] & 0x80)
  2712. {
  2713. //
  2714. // Shift is currently down - insert an up then
  2715. // a down
  2716. //
  2717. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2718. IEM_EVENT_SHIFT_UP;
  2719. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2720. IEM_EVENT_SHIFT_DOWN;
  2721. }
  2722. else
  2723. {
  2724. //
  2725. // Shift is currently up - insert a down then
  2726. // an up
  2727. //
  2728. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2729. IEM_EVENT_SHIFT_DOWN;
  2730. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2731. IEM_EVENT_SHIFT_UP;
  2732. }
  2733. }
  2734. //
  2735. // Replay the menu up key stroke.
  2736. //
  2737. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2738. IEM_EVENT_REPLAY;
  2739. }
  2740. }
  2741. else if ((pIMEventIn->data.keyboard.flags &
  2742. IM_FLAG_KEYBOARD_QUIET) &&
  2743. ((keyCode == VK_TAB) ||
  2744. (keyCode == VK_ESCAPE)))
  2745. {
  2746. //
  2747. // Just get out of here - we don't want to play this back
  2748. //
  2749. return(FALSE);
  2750. }
  2751. else
  2752. {
  2753. //
  2754. // All other VKs just get replayed
  2755. //
  2756. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2757. IEM_EVENT_REPLAY;
  2758. }
  2759. }
  2760. else if (pIMEventIn->type == IM_TYPE_ASCII)
  2761. {
  2762. //
  2763. // For ASCII packets we need to find out how we can replay them
  2764. // on our local keyboard. If we can replay them directly or
  2765. // with shift or ctrl (but not with ALT), then we will do so,
  2766. // otherwise we will simulate Alt + numeric keypad to replay
  2767. // them. If we have to generate fake modifier key strokes
  2768. // ourselves then we will replay the whole key stroke on the
  2769. // incoming key down. If we don't need to generate fake key
  2770. // strokes then we will play the down and up keystrokes as they
  2771. // come in.
  2772. //
  2773. // We do not allow VK combinations involving ALT as this messes
  2774. // up remote international keyboard support. For example, if
  2775. // the remote keyboard is UK and we are (say) Spanish,
  2776. // VKKeyScan says we can do the "UK pound" character as
  2777. // Ctrl+Alt+3. While this works in Windows, and for DOS Boxes
  2778. // on standard keyboards, DOS Boxes with enhanced keyboards
  2779. // require ALTGR+3 (nb Windows seems to treat ALTGR as Ctrl+Alt
  2780. // anyway - at least for VKs and Async state). There is no VK
  2781. // for ALTGR, so do an ALT-nnn sequence for these cases.
  2782. //
  2783. rcVkKeyScan = VkKeyScan((char)keyCode);
  2784. TRACE_OUT(( "co_vk_key_scan of X%02x returns rcVkKeyScan X%02x",
  2785. keyCode, rcVkKeyScan));
  2786. if ((rcVkKeyScan != 0xffff) && !(rcVkKeyScan & 0x0400))
  2787. {
  2788. //
  2789. // This can be replayed using a combination of modifiers on
  2790. // this keyboard.
  2791. //
  2792. rcVkKeyScanKbState = HIBYTE(rcVkKeyScan);
  2793. //
  2794. // The high byte of rcVkKeyScan contains three bit flags
  2795. // which signify which modifiers ar required to generate
  2796. // this character. They are
  2797. //
  2798. // bit 0 - Shift
  2799. // bit 1 - Ctrl
  2800. // bit 2 - Alt (Menu)
  2801. //
  2802. // We will construct an equivalent set of flags which
  2803. // describes the current state of these modifiers.
  2804. //
  2805. curKbState = 0;
  2806. if (m_aimControlledControllerKeyStates[VK_SHIFT] & 0x80)
  2807. {
  2808. curKbState |= IEM_SHIFT_DOWN;
  2809. }
  2810. if (m_aimControlledControllerKeyStates[VK_CONTROL] & 0x80)
  2811. {
  2812. curKbState |= IEM_CTRL_DOWN;
  2813. }
  2814. if (m_aimControlledControllerKeyStates[VK_MENU] & 0x80)
  2815. {
  2816. curKbState |= IEM_MENU_DOWN;
  2817. //
  2818. // If the Alt key is down currently in this person's
  2819. // context then (in general
  2820. // it. This means accelerators which need to be
  2821. // shifted will work as we won't release the Alt key in
  2822. // order to generate the key strokes.
  2823. //
  2824. // However, if the ALT key is being held down in
  2825. // combination with SHIFT and CTRL to generate a
  2826. // character (e.g. CTRL-ALT-SHIFT-4 on a US keyboard
  2827. // to generate a � character) then we will allow the
  2828. // ALT key up before we play back the true character.
  2829. //
  2830. if ((curKbState & (IEM_SHIFT_DOWN | IEM_CTRL_DOWN)) !=
  2831. (IEM_SHIFT_DOWN | IEM_CTRL_DOWN))
  2832. {
  2833. rcVkKeyScanKbState |= IEM_MENU_DOWN;
  2834. }
  2835. }
  2836. if ((m_aimControlledControllerKeyStates[VK_CAPITAL] & 0x01) &&
  2837. ((LOBYTE(rcVkKeyScan) >= 'A') &&
  2838. ((LOBYTE(rcVkKeyScan) <= 'Z'))))
  2839. {
  2840. //
  2841. // If caps-lock is enabled then the effect of a shift
  2842. // down on VKs A thru Z is reversed. This logic ( 'A'
  2843. // <= x <= 'Z' is encoded in the keyboard.drv so it
  2844. // should be pretty safe).
  2845. //
  2846. curKbState ^= IEM_SHIFT_DOWN;
  2847. }
  2848. if (curKbState == rcVkKeyScanKbState)
  2849. {
  2850. //
  2851. // We are already in the correct shift state so just
  2852. // replay the VK.
  2853. //
  2854. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2855. IEM_EVENT_REPLAY_VK;
  2856. m_imControlledVKToReplay = LOBYTE(rcVkKeyScan);
  2857. }
  2858. else
  2859. {
  2860. //
  2861. // We need to generate some fake modifiers - only do
  2862. // this on a key press.
  2863. //
  2864. if (pIMEventIn->data.keyboard.flags &
  2865. IM_FLAG_KEYBOARD_RELEASE)
  2866. {
  2867. return(FALSE);
  2868. }
  2869. //
  2870. // Insert modifiers to get into the correct state.
  2871. //
  2872. m_imControlledNumEventsPending += IMInsertModifierKeystrokes(
  2873. curKbState,
  2874. rcVkKeyScanKbState,
  2875. &(m_aimControlledEventsToReturn[m_imControlledNumEventsPending]));
  2876. //
  2877. // Now insert the VK itself - a down and up.
  2878. //
  2879. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2880. IEM_EVENT_REPLAY_VK_DOWN;
  2881. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  2882. IEM_EVENT_REPLAY_VK_UP;
  2883. //
  2884. // Remeber the VK we want to replay when we come across
  2885. // IEM_EVENT_REPLAY_VK_DOWN/UP.
  2886. //
  2887. m_imControlledVKToReplay = LOBYTE(rcVkKeyScan);
  2888. //
  2889. // Now insert the modifiers to get back to the current
  2890. // state.
  2891. //
  2892. m_imControlledNumEventsPending += IMInsertModifierKeystrokes(
  2893. rcVkKeyScanKbState,
  2894. curKbState,
  2895. &(m_aimControlledEventsToReturn[m_imControlledNumEventsPending]));
  2896. //
  2897. // Now we have a complete set of events ready to replay
  2898. // so go for it.
  2899. //
  2900. }
  2901. }
  2902. else
  2903. {
  2904. //
  2905. // We can't replay directly, so will have to simulate an
  2906. // Alt+keypad sequence.
  2907. //
  2908. TRACE_OUT(( "FAKE AN ALT-nnn SEQUENCE IF WINDOWS"));
  2909. //
  2910. // We only do this sort of stuff on a key-press.
  2911. //
  2912. if (pIMEventIn->data.keyboard.flags &
  2913. IM_FLAG_KEYBOARD_RELEASE)
  2914. {
  2915. return(FALSE);
  2916. }
  2917. //
  2918. // The following code relies on keyCode being less than 999
  2919. // and we should receive a keycode > 255 so get out now if
  2920. // we have.
  2921. //
  2922. if (keyCode > 255)
  2923. {
  2924. return(FALSE);
  2925. }
  2926. //
  2927. // First get modifiers into correct state - create bit
  2928. // flags for current modifier state.
  2929. //
  2930. curKbState = 0;
  2931. //
  2932. // For windows we have a character to input that cannot
  2933. // be replayed by pressing a key...replay by injecting
  2934. // alt-nnn.
  2935. //
  2936. if (m_aimControlledControllerKeyStates[VK_SHIFT] & 0x80)
  2937. {
  2938. curKbState |= IEM_SHIFT_DOWN;
  2939. }
  2940. if (m_aimControlledControllerKeyStates[VK_CONTROL] & 0x80)
  2941. {
  2942. curKbState |= IEM_CTRL_DOWN;
  2943. }
  2944. if (m_aimControlledControllerKeyStates[VK_MENU] & 0x80)
  2945. {
  2946. curKbState |= IEM_MENU_DOWN;
  2947. }
  2948. //
  2949. // If necessary, reset all modifiers.
  2950. //
  2951. if (curKbState)
  2952. {
  2953. m_imControlledNumEventsPending += IMInsertModifierKeystrokes(
  2954. curKbState,
  2955. 0,
  2956. &(m_aimControlledEventsToReturn[m_imControlledNumEventsPending]));
  2957. }
  2958. //
  2959. // Now determine whether we can do the ALT-nnn keypad
  2960. // sequence using an OEM keycode or whether we have to use
  2961. // an ANSI (Windows) keycode.
  2962. //
  2963. // The issue here is that:
  2964. //
  2965. // - hosted Windows applications (or rather Windows itself)
  2966. // can distinguish between, and handle correctly, ANSI
  2967. // keycodes and OEM keycodes (where the latter vary
  2968. // depending on the keyboard type). For example,
  2969. // ALT-0163 is the ANSI "UK pound" on all keyboards,
  2970. // and on US national keyboards ALT-156 is the OEM
  2971. // keycode for "UK pound".
  2972. //
  2973. // - hosted DOS Boxes only understand OEM keycodes.
  2974. //
  2975. // So (for example), if we have a remote UK keyboard
  2976. // controlling local Windows and DOS Box applications, and
  2977. // we generate ALT-nnn using the OEM keycode (and without a
  2978. // leading zero), both the Windows and DOS Box applications
  2979. // interpret it as "UK pound" (Hoorah!). In contrast, if
  2980. // we generate ALT-nnn using the ANSI keycode (with a
  2981. // leading zero), the Windows applications still do "UK
  2982. // pound", BUT the DOS Box does an "u acute".
  2983. //
  2984. // As far as we can tell (eg by examining the DDK keyboard
  2985. // driver source for AnsiToOem), there should always be a
  2986. // translation. However, it is possible that the ANSI to
  2987. // OEM translation is not 1<->1. We therefore check this
  2988. // by doing a second translation back from OEM to ANSI. If
  2989. // this does not give us the original character we use the
  2990. // original ANSI code and play it back with a ALT-0nnn
  2991. // sequence.
  2992. //
  2993. chAnsi = (char)pIMEventIn->data.keyboard.keyCode;
  2994. AnsiToOemBuff(&chAnsi, &chOEM, 1);
  2995. OemToAnsiBuff(&chOEM, &chNewAnsi, 1);
  2996. TRACE_OUT(( "Ansi: %02x OEM: %02x NewAnsi: %02x",
  2997. (BYTE)chAnsi,
  2998. (BYTE)chOEM,
  2999. (BYTE)chNewAnsi ));
  3000. bTranslateOEM = (chAnsi == chNewAnsi);
  3001. keyCode = (bTranslateOEM)
  3002. ? (UINT)(BYTE)chOEM
  3003. : pIMEventIn->data.keyboard.keyCode;
  3004. //
  3005. // Now insert a VK_MENU down.
  3006. //
  3007. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  3008. IEM_EVENT_MENU_DOWN;
  3009. //
  3010. // Now insert the numeric keypad keystrokes. If we're
  3011. // doing an ANSI ALT
  3012. //
  3013. if (!bTranslateOEM)
  3014. {
  3015. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  3016. IEM_EVENT_KEYPAD0_DOWN;
  3017. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  3018. IEM_EVENT_KEYPAD0_UP;
  3019. }
  3020. //
  3021. // Add keystrokes for hundreds, tens and units, taking care
  3022. // to discard leading (but not trailing) zeros if we're
  3023. // doing an OEM sequence (which would confuse Windows into
  3024. // thinking an OEM ALT-nnn sequence was an ANSI sequence).
  3025. //
  3026. position = 100;
  3027. for (i=0 ; i<3 ; i++)
  3028. {
  3029. //
  3030. // Insert the correct digit for this position.
  3031. //
  3032. digit = keyCode / position;
  3033. if (!(digit == 0 && bTranslateOEM))
  3034. {
  3035. bTranslateOEM = FALSE;
  3036. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  3037. IEM_EVENT_KEYPAD0_DOWN + digit;
  3038. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  3039. IEM_EVENT_KEYPAD0_UP + digit;
  3040. }
  3041. //
  3042. // Move to next position.
  3043. //
  3044. keyCode %= position;
  3045. position /= 10;
  3046. }
  3047. //
  3048. // Now insert a VK_MENU up.
  3049. //
  3050. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] =
  3051. IEM_EVENT_MENU_UP;
  3052. //
  3053. // If necessary, get the modifiers back to the state they
  3054. // were in previously.
  3055. //
  3056. if (curKbState != 0)
  3057. {
  3058. m_imControlledNumEventsPending += IMInsertModifierKeystrokes(
  3059. 0,
  3060. curKbState,
  3061. &(m_aimControlledEventsToReturn[m_imControlledNumEventsPending]));
  3062. }
  3063. //
  3064. // Now we have a buffer full of keystrokes - go for it.
  3065. //
  3066. }
  3067. }
  3068. else if (pIMEventIn->type == IM_TYPE_VK2)
  3069. {
  3070. //
  3071. // Hot keys are thrown away - this is easy.
  3072. //
  3073. return(FALSE);
  3074. }
  3075. else if (pIMEventIn->type == IM_TYPE_3BUTTON)
  3076. {
  3077. //
  3078. // Mouse events are just replayed.
  3079. //
  3080. m_aimControlledEventsToReturn[m_imControlledNumEventsPending++] = IEM_EVENT_REPLAY;
  3081. }
  3082. else
  3083. {
  3084. //
  3085. // Unknown events are thrown away - this is easy.
  3086. //
  3087. return(FALSE);
  3088. }
  3089. //
  3090. // Now we have events to return.
  3091. //
  3092. m_imfControlledNewEvent = FALSE;
  3093. m_imControlledNumEventsReturned = 0;
  3094. }
  3095. if (!m_imfControlledNewEvent)
  3096. {
  3097. if (m_imControlledNumEventsReturned == m_imControlledNumEventsPending)
  3098. {
  3099. //
  3100. // There are no more events to return.
  3101. //
  3102. m_imfControlledNewEvent = TRUE;
  3103. return(FALSE);
  3104. }
  3105. else
  3106. {
  3107. TRACE_OUT(("Event to return: %u",
  3108. m_aimControlledEventsToReturn[m_imControlledNumEventsReturned]));
  3109. if ((m_aimControlledEventsToReturn[m_imControlledNumEventsReturned] >=
  3110. IEM_EVENT_KEYPAD0_DOWN) &&
  3111. (m_aimControlledEventsToReturn[m_imControlledNumEventsReturned] <=
  3112. (IEM_EVENT_KEYPAD0_DOWN+9)))
  3113. {
  3114. //
  3115. // Return a keypad down event.
  3116. //
  3117. pIMEventOut->type = IM_TYPE_VK1;
  3118. pIMEventOut->data.keyboard.keyCode = (TSHR_UINT16)
  3119. (VK_NUMPAD0 +
  3120. (m_aimControlledEventsToReturn[m_imControlledNumEventsReturned] -
  3121. IEM_EVENT_KEYPAD0_DOWN));
  3122. pIMEventOut->data.keyboard.flags = IM_FLAG_KEYBOARD_ALT_DOWN;
  3123. }
  3124. else if ((m_aimControlledEventsToReturn[m_imControlledNumEventsReturned] >=
  3125. IEM_EVENT_KEYPAD0_UP) &&
  3126. (m_aimControlledEventsToReturn[m_imControlledNumEventsReturned] <=
  3127. (IEM_EVENT_KEYPAD0_UP+9)))
  3128. {
  3129. //
  3130. // Return a keypad up event.
  3131. //
  3132. pIMEventOut->type = IM_TYPE_VK1;
  3133. pIMEventOut->data.keyboard.keyCode = (TSHR_UINT16)
  3134. (VK_NUMPAD0 +
  3135. (m_aimControlledEventsToReturn[m_imControlledNumEventsReturned] -
  3136. IEM_EVENT_KEYPAD0_UP));
  3137. pIMEventOut->data.keyboard.flags = IM_FLAG_KEYBOARD_DOWN |
  3138. IM_FLAG_KEYBOARD_RELEASE |
  3139. IM_FLAG_KEYBOARD_ALT_DOWN;
  3140. }
  3141. else
  3142. {
  3143. switch (m_aimControlledEventsToReturn[m_imControlledNumEventsReturned])
  3144. {
  3145. case IEM_EVENT_CTRL_DOWN:
  3146. //
  3147. // Set up a Ctrl down event.
  3148. //
  3149. pIMEventOut->type = IM_TYPE_VK1;
  3150. pIMEventOut->data.keyboard.keyCode =
  3151. VK_CONTROL;
  3152. pIMEventOut->data.keyboard.flags = 0;
  3153. break;
  3154. case IEM_EVENT_CTRL_UP:
  3155. //
  3156. // Set up a Ctrl up event.
  3157. //
  3158. pIMEventOut->type = IM_TYPE_VK1;
  3159. pIMEventOut->data.keyboard.keyCode =
  3160. VK_CONTROL;
  3161. pIMEventOut->data.keyboard.flags =
  3162. IM_FLAG_KEYBOARD_DOWN | IM_FLAG_KEYBOARD_RELEASE;
  3163. break;
  3164. case IEM_EVENT_SHIFT_DOWN:
  3165. //
  3166. // Set up a Shift down event.
  3167. //
  3168. pIMEventOut->type = IM_TYPE_VK1;
  3169. pIMEventOut->data.keyboard.keyCode =
  3170. VK_SHIFT;
  3171. pIMEventOut->data.keyboard.flags = 0;
  3172. break;
  3173. case IEM_EVENT_SHIFT_UP:
  3174. //
  3175. // Set up a Shift up event.
  3176. //
  3177. pIMEventOut->type = IM_TYPE_VK1;
  3178. pIMEventOut->data.keyboard.keyCode =
  3179. VK_SHIFT;
  3180. pIMEventOut->data.keyboard.flags =
  3181. IM_FLAG_KEYBOARD_DOWN | IM_FLAG_KEYBOARD_RELEASE;
  3182. break;
  3183. case IEM_EVENT_MENU_DOWN:
  3184. //
  3185. // Set up a Menu down event.
  3186. //
  3187. pIMEventOut->type = IM_TYPE_VK1;
  3188. pIMEventOut->data.keyboard.keyCode = VK_MENU;
  3189. pIMEventOut->data.keyboard.flags = 0;
  3190. break;
  3191. case IEM_EVENT_MENU_UP:
  3192. //
  3193. // Set up a Menu up event.
  3194. //
  3195. pIMEventOut->type = IM_TYPE_VK1;
  3196. pIMEventOut->data.keyboard.keyCode = VK_MENU;
  3197. pIMEventOut->data.keyboard.flags =
  3198. IM_FLAG_KEYBOARD_DOWN | IM_FLAG_KEYBOARD_RELEASE;
  3199. break;
  3200. case IEM_EVENT_REPLAY:
  3201. //
  3202. // Just copy the packet.
  3203. //
  3204. *pIMEventOut = *pIMEventIn;
  3205. break;
  3206. case IEM_EVENT_REPLAY_VK:
  3207. //
  3208. // Replay the VK from m_imControlledVKToReplay using the
  3209. // flags on the incoming packet.
  3210. //
  3211. *pIMEventOut = *pIMEventIn;
  3212. pIMEventOut->type = IM_TYPE_VK1;
  3213. pIMEventOut->data.keyboard.keyCode = (TSHR_UINT16)
  3214. m_imControlledVKToReplay;
  3215. break;
  3216. case IEM_EVENT_REPLAY_VK_UP:
  3217. //
  3218. // Replay an up key event for the VK in
  3219. // m_imControlledVKToReplay.
  3220. //
  3221. pIMEventOut->type = IM_TYPE_VK1;
  3222. pIMEventOut->data.keyboard.keyCode = (TSHR_UINT16)
  3223. m_imControlledVKToReplay;
  3224. pIMEventOut->data.keyboard.flags =
  3225. IM_FLAG_KEYBOARD_DOWN | IM_FLAG_KEYBOARD_RELEASE;
  3226. break;
  3227. case IEM_EVENT_REPLAY_VK_DOWN:
  3228. //
  3229. // Replay a down key event for the VK in
  3230. // m_imControlledVKToReplay.
  3231. //
  3232. pIMEventOut->type = IM_TYPE_VK1;
  3233. pIMEventOut->data.keyboard.keyCode = (TSHR_UINT16)
  3234. m_imControlledVKToReplay;
  3235. pIMEventOut->data.keyboard.flags = 0;
  3236. break;
  3237. case IEM_EVENT_NORMAL:
  3238. //
  3239. // Play back the event but force it to be normal.
  3240. //
  3241. *pIMEventOut = *pIMEventIn;
  3242. pIMEventOut->data.keyboard.flags &=
  3243. (TSHR_UINT16)~IM_FLAG_KEYBOARD_ALT_DOWN;
  3244. break;
  3245. case IEM_EVENT_SYSTEM:
  3246. //
  3247. // Play back the event but force it to be system.
  3248. //
  3249. *pIMEventOut = *pIMEventIn;
  3250. pIMEventOut->data.keyboard.flags |=
  3251. IM_FLAG_KEYBOARD_ALT_DOWN;
  3252. break;
  3253. default:
  3254. ERROR_OUT(( "Invalid code path"));
  3255. break;
  3256. }
  3257. }
  3258. }
  3259. m_imControlledNumEventsReturned++;
  3260. //
  3261. // If we're going to playback a NUMLOCK event, make sure we force
  3262. // the keyboard LEDs to be accurate.
  3263. //
  3264. if ((pIMEventOut->type == IM_TYPE_VK1) &&
  3265. (pIMEventOut->data.keyboard.keyCode == VK_NUMLOCK) &&
  3266. IS_IM_KEY_PRESS(pIMEventOut->data.keyboard.flags))
  3267. {
  3268. TRACE_OUT(("Playing back NUMLOCK; add IM_FLAG_KEYBOARD_UPDATESTATE"));
  3269. pIMEventOut->data.keyboard.flags |= IM_FLAG_KEYBOARD_UPDATESTATE;
  3270. }
  3271. return(TRUE);
  3272. }
  3273. DebugExitBOOL(ASShare::IMTranslateIncoming, FALSE);
  3274. return(FALSE);
  3275. }
  3276. //
  3277. // FUNCTION: IMInsertModifierKeystrokes
  3278. //
  3279. // DESCRIPTION:
  3280. //
  3281. // This function inserts various modifier keystrokes into the supplied
  3282. // buffer to move from one modifier state to another.
  3283. //
  3284. // PARAMETERS:
  3285. //
  3286. // curKbState - the current modifier state (bit 0 - Shift, bit 1 - Ctrl,
  3287. // bit 2 - Menu).
  3288. //
  3289. // targetKbState - the state we want the modifiers to be in
  3290. //
  3291. // pEventQueue - a pointer to an array where the required events can be
  3292. // inserted
  3293. //
  3294. // RETURNS: the number of events inserted
  3295. //
  3296. //
  3297. UINT ASShare::IMInsertModifierKeystrokes
  3298. (
  3299. BYTE curKbState,
  3300. BYTE targetKbState,
  3301. LPUINT pEventQueue
  3302. )
  3303. {
  3304. UINT kbDelta;
  3305. UINT events = 0;
  3306. DebugEntry(ASShare::IMInsertModifierKeystrokes);
  3307. //
  3308. // Find out which modifiers are different.
  3309. //
  3310. kbDelta = curKbState ^ targetKbState;
  3311. TRACE_OUT(( "Keyboard delat %x", kbDelta));
  3312. //
  3313. // Now generate the right events to get us into the correct modifier
  3314. // state.
  3315. //
  3316. if (kbDelta & IEM_SHIFT_DOWN)
  3317. {
  3318. //
  3319. // Shift state is different - do we need an up or down.
  3320. //
  3321. if (curKbState & IEM_SHIFT_DOWN)
  3322. {
  3323. //
  3324. // We need an up.
  3325. //
  3326. pEventQueue[events++] = IEM_EVENT_SHIFT_UP;
  3327. }
  3328. else
  3329. {
  3330. //
  3331. // We need a down.
  3332. //
  3333. pEventQueue[events++] = IEM_EVENT_SHIFT_DOWN;
  3334. }
  3335. }
  3336. //
  3337. // Same process for Ctrl and Alt.
  3338. //
  3339. if (kbDelta & IEM_CTRL_DOWN)
  3340. {
  3341. if (curKbState & IEM_CTRL_DOWN)
  3342. {
  3343. pEventQueue[events++] = IEM_EVENT_CTRL_UP;
  3344. }
  3345. else
  3346. {
  3347. pEventQueue[events++] = IEM_EVENT_CTRL_DOWN;
  3348. }
  3349. }
  3350. if (kbDelta & IEM_MENU_DOWN)
  3351. {
  3352. if (curKbState & IEM_MENU_DOWN)
  3353. {
  3354. pEventQueue[events++] = IEM_EVENT_MENU_UP;
  3355. }
  3356. else
  3357. {
  3358. pEventQueue[events++] = IEM_EVENT_MENU_DOWN;
  3359. }
  3360. }
  3361. DebugExitDWORD(ASShare::IMInsertModifierKeystrokes, events);
  3362. return(events);
  3363. }
  3364. //
  3365. // IMInjectEvent()
  3366. //
  3367. // DESCRIPTION:
  3368. //
  3369. // Called by IMMaybeInjectEvents when it is ready to inject an event.
  3370. // Given a pointer to a IMOSEVENT this function formats it correctly and
  3371. // calls the appropriate USER callback. It also updates the async key
  3372. // state arrays for the source queue and USER and sets m_imLastInjectTime to
  3373. // the tick count at which the event was injected. We protect against
  3374. // injecting up key strokes/mouse buttons when USER does not think the
  3375. // key/button is down in this function. It is quite possible (given the
  3376. // potential variety of CAs) that the IM will be asked to inject an up
  3377. // event when there has been no corresponding down event. This should be
  3378. // harmless as it is possible for this to happen in real life (ie the
  3379. // system message queue is full when the down event happens but there is
  3380. // space when the up event happens). However, it is quite unlikely and it
  3381. // is more likely that injecting these unmatched events will confuse
  3382. // applications.
  3383. //
  3384. // PARAMETERS:
  3385. //
  3386. // pEvent - pointer to an IMOSEVENT.
  3387. //
  3388. // THIS WORKS FOR NT AND WIN95.
  3389. //
  3390. BOOL ASShare::IMInjectEvent(LPIMOSEVENT pEvent)
  3391. {
  3392. UINT clickTime;
  3393. TSHR_UINT16 flags;
  3394. TSHR_UINT16 flagsAfter;
  3395. LPMSEV pMouseEvent;
  3396. DebugEntry(IMInjectEvent);
  3397. //
  3398. // Now inject the event.
  3399. //
  3400. switch (pEvent->type)
  3401. {
  3402. case IM_MOUSE_EVENT:
  3403. //
  3404. // Set up a pointer to the mouse event data.
  3405. //
  3406. pMouseEvent = &(pEvent->event.mouse);
  3407. //
  3408. // Check whether this is an unmatched up event
  3409. //
  3410. if ((IM_MEV_BUTTON1_UP(*pEvent) &&
  3411. IM_KEY_STATE_IS_UP(m_aimControlledKeyStates[VK_LBUTTON])) ||
  3412. (IM_MEV_BUTTON2_UP(*pEvent) &&
  3413. IM_KEY_STATE_IS_UP(m_aimControlledKeyStates[VK_RBUTTON])) ||
  3414. (IM_MEV_BUTTON3_UP(*pEvent) &&
  3415. IM_KEY_STATE_IS_UP(m_aimControlledKeyStates[VK_MBUTTON])))
  3416. {
  3417. //
  3418. // This is an unmatched up event so just discard it here
  3419. //
  3420. TRACE_OUT(("IMInjectEvent: discarding unmatched mouse up event"));
  3421. DC_QUIT;
  3422. }
  3423. //
  3424. // Store the injection time of this event.
  3425. //
  3426. m_imControlledLastLowLevelMouseEventTime = GetTickCount();
  3427. //
  3428. // Store the mouse position - only consider absolute mouse
  3429. // moves. (Note that for the cases in which we inject a
  3430. // relative mouse event we always set the co-ordinate change to
  3431. // 0).
  3432. //
  3433. if (pMouseEvent->flags & MOUSEEVENTF_ABSOLUTE)
  3434. {
  3435. m_imControlledLastMousePos.x = pMouseEvent->pt.x;
  3436. m_imControlledLastMousePos.y = pMouseEvent->pt.y;
  3437. TRACE_OUT(( "Updating mouse position (%d:%d)",
  3438. m_imControlledLastMousePos.x,
  3439. m_imControlledLastMousePos.y));
  3440. }
  3441. //
  3442. // Inject the event.
  3443. //
  3444. TRACE_OUT(("IMInjectEvent: MOUSE parameters are:"));
  3445. TRACE_OUT((" flags 0x%08x", pMouseEvent->flags));
  3446. TRACE_OUT((" time 0x%08x", m_imControlledLastLowLevelMouseEventTime));
  3447. TRACE_OUT((" position (%d, %d)", pMouseEvent->pt.x, pMouseEvent->pt.y));
  3448. TRACE_OUT((" mouseData %d", pMouseEvent->mouseData));
  3449. TRACE_OUT((" dwExtra %d", pMouseEvent->dwExtraInfo));
  3450. //
  3451. // Finally scale the logical screen co-ordinates to the full
  3452. // 16-bit range (0..65535).
  3453. //
  3454. ASSERT(m_pasLocal->cpcCaps.screen.capsScreenWidth);
  3455. ASSERT(m_pasLocal->cpcCaps.screen.capsScreenHeight);
  3456. pMouseEvent->pt.x = IM_MOUSEPOS_LOG_TO_OS(pMouseEvent->pt.x,
  3457. m_pasLocal->cpcCaps.screen.capsScreenWidth);
  3458. pMouseEvent->pt.y = IM_MOUSEPOS_LOG_TO_OS(pMouseEvent->pt.y,
  3459. m_pasLocal->cpcCaps.screen.capsScreenHeight);
  3460. OSI_InjectMouseEvent(pMouseEvent->flags, pMouseEvent->pt.x,
  3461. pMouseEvent->pt.y, pMouseEvent->mouseData, pMouseEvent->dwExtraInfo);
  3462. break;
  3463. case IM_KEYBOARD_EVENT:
  3464. //
  3465. // Check whether this is an unmatched up event
  3466. //
  3467. if (IM_KEV_KEYUP(*pEvent) &&
  3468. IM_KEY_STATE_IS_UP(m_aimControlledKeyStates[IM_KEV_VKCODE(*pEvent)]))
  3469. {
  3470. //
  3471. // This is an unmatched up event so just discard it.
  3472. //
  3473. TRACE_OUT(("IMInjectEvent: discarding unmatched key up event %04hX",
  3474. IM_KEV_VKCODE(*pEvent)));
  3475. DC_QUIT;
  3476. }
  3477. //
  3478. // Inject the event.
  3479. //
  3480. TRACE_OUT(("IMInjectEvent: KEYBD parameters are:"));
  3481. TRACE_OUT((" flags 0x%08x", pEvent->event.keyboard.flags));
  3482. TRACE_OUT((" virtkey %u", pEvent->event.keyboard.vkCode));
  3483. TRACE_OUT((" scan code %u", pEvent->event.keyboard.scanCode));
  3484. OSI_InjectKeyboardEvent(pEvent->event.keyboard.flags,
  3485. pEvent->event.keyboard.vkCode, pEvent->event.keyboard.scanCode,
  3486. pEvent->event.keyboard.dwExtraInfo);
  3487. if (pEvent->flags & IM_FLAG_UPDATESTATE)
  3488. {
  3489. BYTE kbState[256];
  3490. TRACE_OUT(("Updating keyboard LED state after playing back toggle"));
  3491. GetKeyboardState(kbState);
  3492. SetKeyboardState(kbState);
  3493. }
  3494. break;
  3495. default:
  3496. //
  3497. // We do nothing for unexpected events - this allow us to add
  3498. // more events later that can be sent to back level systems
  3499. // where they will be safely ignored
  3500. //
  3501. TRACE_OUT(( "Unexpected event %d", pEvent->type));
  3502. DC_QUIT;
  3503. }
  3504. //
  3505. // If we get here successfully then we want to update our copy of the
  3506. // async key state so set the flag.
  3507. //
  3508. IMUpdateAsyncArray(m_aimControlledKeyStates, pEvent);
  3509. DC_EXIT_POINT:
  3510. DebugExitBOOL(ASShare::IMInjectEvent, TRUE);
  3511. return(TRUE);
  3512. }
  3513. //
  3514. // FUNCTION: IMInjectingEvents
  3515. //
  3516. BOOL ASShare::IMInjectingEvents(void)
  3517. {
  3518. LPIMOSEVENT pNextEvent;
  3519. IMOSEVENT mouseMoveEvent;
  3520. UINT tick;
  3521. UINT targetTime;
  3522. UINT targetDelta;
  3523. BOOL rc = TRUE;
  3524. DebugEntry(ASShare::IMInjectingEvents);
  3525. if (m_pasLocal->m_caControlledBy && m_imControlledOSQ.numEvents)
  3526. {
  3527. pNextEvent = m_imControlledOSQ.events + m_imControlledOSQ.head;
  3528. //
  3529. // First check if this is a remote mouse event being injected too
  3530. // soon after the previous one. We used to only do this for mouse
  3531. // move events to prevent them all being spoiled if they were
  3532. // injected too quickly. However, we now do it for all mouse
  3533. // events because of a bug in Windows USER whereby if the mouse
  3534. // press which brings up a menu is processed after the
  3535. // corresponding mouse release has been passed to USER (so that the
  3536. // async state of the mouse button is up) then the menu is brought
  3537. // up in the position it is brought up in if it is selected via the
  3538. // keyboard rather than the position it is brought up in if it is
  3539. // selected by the mouse. (These positions are only different when
  3540. // the menu cannot be placed completely below or above the menu
  3541. // bar). This can then lead to the mouse release selecting an item
  3542. // from the menu.
  3543. //
  3544. tick = GetTickCount();
  3545. if (m_imfControlledPaceInjection &&
  3546. (pNextEvent->type == IM_MOUSE_EVENT))
  3547. {
  3548. //
  3549. // This is a remote mouse event so check that now is a good
  3550. // time to inject it Smooth out the backlog adjustment so that
  3551. // packet bursts do not get spoiled too much. Set an absolute
  3552. // lg_lpimSharedData->imit on injection delay of the low sample rate so that
  3553. // timestamp anomolies do not cause us to withhold messages
  3554. //
  3555. //
  3556. // The target delta between last and current events is
  3557. // calculated from the remote timestamps
  3558. //
  3559. targetDelta = abs((int)(pNextEvent->time -
  3560. m_imControlledLastMouseRemoteTime));
  3561. if (targetDelta > IM_LOCAL_MOUSE_SAMPLING_GAP_LOW_MS)
  3562. {
  3563. targetDelta = IM_LOCAL_MOUSE_SAMPLING_GAP_LOW_MS;
  3564. }
  3565. //
  3566. // The target injection time is based on the last injection
  3567. // time and our target delta, adjusted for any backlog we are
  3568. // seeing. Because packeting gives a jerky backlog we need to
  3569. // smooth our adjustment out (only modify by backlog/8)
  3570. //
  3571. targetTime = m_imControlledLastMouseLocalTime +
  3572. targetDelta - (m_imControlledMouseBacklog/8);
  3573. TRACE_OUT(( "Last tremote %#lx, this tremote %#lx, backlog %#lx",
  3574. m_imControlledLastMouseRemoteTime,
  3575. pNextEvent->time,
  3576. m_imControlledMouseBacklog));
  3577. TRACE_OUT(( "Last tlocal %#lx, tick %#lx, targetTime %#lx",
  3578. m_imControlledLastMouseLocalTime,
  3579. tick,
  3580. targetTime));
  3581. //
  3582. // Now inject the events - ignore them if they are too early
  3583. //
  3584. if (IM_MEV_ABS_MOVE(*pNextEvent) && (tick < targetTime))
  3585. {
  3586. //
  3587. // If values seem wild (for example this is the first mouse
  3588. // event ever) then reset them
  3589. //
  3590. if (targetTime > tick + 1000)
  3591. {
  3592. m_imControlledLastMouseRemoteTime = pNextEvent->time;
  3593. m_imControlledLastMouseLocalTime = tick;
  3594. m_imControlledMouseBacklog = 0;
  3595. TRACE_OUT(( "Wild values - reset"));
  3596. }
  3597. else
  3598. {
  3599. //
  3600. // This is too early - get out of the loop.
  3601. //
  3602. rc = FALSE;
  3603. DC_QUIT;
  3604. }
  3605. }
  3606. else
  3607. {
  3608. //
  3609. // We will inject this event (and remember when we did it
  3610. // so we don't inject the next one to quickly). Calculate
  3611. // the backlog because we may have to make up for a
  3612. // processing delay If this event is long (1000 mS) after
  3613. // our projected event time then assume a pause in movement
  3614. // and reset the backlog to avoid progressive erosion.
  3615. // Otherwise calculate the new backlog.
  3616. //
  3617. // Perf - don't reset backlog unless the time has expired.
  3618. // Restting just because we see a click means that we
  3619. // actually increase the latency by assuming that mouse
  3620. // messages queued behind the tick are not backlogged.
  3621. //
  3622. if (tick < (targetTime + 1000))
  3623. {
  3624. m_imControlledMouseBacklog += ( tick -
  3625. m_imControlledLastMouseLocalTime -
  3626. targetDelta );
  3627. }
  3628. else
  3629. {
  3630. m_imControlledMouseBacklog = 0;
  3631. TRACE_OUT(( "Non move/big gap in move"));
  3632. }
  3633. m_imControlledLastMouseRemoteTime = pNextEvent->time;
  3634. m_imControlledLastMouseLocalTime = tick;
  3635. }
  3636. }
  3637. else
  3638. {
  3639. //
  3640. // This is not a remote mouse event. Reset the
  3641. // m_imNextRemoteMouseEvent to zero so we don't hold up the next
  3642. // remote mouse event.
  3643. //
  3644. m_imControlledLastMouseRemoteTime = pNextEvent->time;
  3645. m_imControlledLastMouseLocalTime = tick;
  3646. m_imControlledMouseBacklog = 0;
  3647. TRACE_OUT(( "Local/non-paced/non-mouse - reset"));
  3648. }
  3649. //
  3650. // Only inject the event if IM_FLAG_DONT_REPLAY is not set
  3651. //
  3652. if (!(pNextEvent->flags & IM_FLAG_DONT_REPLAY))
  3653. {
  3654. //
  3655. // If the event is a mouse click then we always inject a mouse
  3656. // move event g_lpimSharedData->immediately before it to ensure that the current
  3657. // position is correct before the click is injected.
  3658. //
  3659. // This is because USER does not handle combined "move and
  3660. // click" events correctly (it appears to treat them as "click
  3661. // and move", generating a mouse move event AFTER the click
  3662. // event, rather than before). Under normal Windows operation
  3663. // it appears (from observation) that movement events and click
  3664. // events are generated separately (i.e. a click event will
  3665. // never have the movement flag set). However, incoming mouse
  3666. // click events may have positions that are different from the
  3667. // last mouse move event so we must inject the extra move event
  3668. // to keep USER happy.
  3669. //
  3670. if ( (pNextEvent->type == IM_MOUSE_EVENT) &&
  3671. (IM_MEV_BUTTON_DOWN(*pNextEvent) ||
  3672. IM_MEV_BUTTON_UP(*pNextEvent)) )
  3673. {
  3674. TRACE_OUT(( "Mouse clk: injecting extra"));
  3675. //
  3676. // Take a copy of the event.
  3677. //
  3678. mouseMoveEvent = *pNextEvent;
  3679. //
  3680. // Turn the mouse click event into a mouse move event with
  3681. // the absolute/relative flag unchanged.
  3682. //
  3683. mouseMoveEvent.event.mouse.flags &= MOUSEEVENTF_ABSOLUTE;
  3684. mouseMoveEvent.event.mouse.flags |= MOUSEEVENTF_MOVE;
  3685. //
  3686. // Inject the additional move event.
  3687. //
  3688. IMInjectEvent(&mouseMoveEvent);
  3689. //
  3690. // As the position is now correct, we turn the click into a
  3691. // relative event with an unchanged position.
  3692. //
  3693. pNextEvent->event.mouse.flags &= ~MOUSEEVENTF_ABSOLUTE;
  3694. pNextEvent->event.mouse.pt.x = 0;
  3695. pNextEvent->event.mouse.pt.y = 0;
  3696. //
  3697. // If this is a mouse down click then flag the injection
  3698. // heuristic as active. We deactivate the heuristic when
  3699. // the mouse is released so that dragging over menus can be
  3700. // done without delay. (We keep the heuristic active when
  3701. // mouse is depressed because most drawing apps perform
  3702. // freehand drawing in this way.
  3703. //
  3704. if (IM_MEV_BUTTON_DOWN(*pNextEvent))
  3705. {
  3706. TRACE_OUT(( "Injection pacing active"));
  3707. m_imfControlledPaceInjection = TRUE;
  3708. }
  3709. else
  3710. {
  3711. TRACE_OUT(( "Injection pacing inactive"));
  3712. m_imfControlledPaceInjection = FALSE;
  3713. }
  3714. }
  3715. //
  3716. // Inject the real event.
  3717. //
  3718. TRACE_OUT(( "Injecting the evnt now"));
  3719. IMInjectEvent(pNextEvent);
  3720. }
  3721. IMUpdateAsyncArray(m_aimControlledControllerKeyStates, pNextEvent);
  3722. ASSERT(m_imControlledOSQ.numEvents);
  3723. m_imControlledOSQ.numEvents--;
  3724. m_imControlledOSQ.head = CIRCULAR_INDEX(m_imControlledOSQ.head, 1,
  3725. IM_SIZE_OSQ);
  3726. //
  3727. // We only inject a single keyboard event per pass to prevent
  3728. // excessive spoiling of repeated events. Having got them here it
  3729. // seems a shame to spoil them. Spoil down to 5 so we don't get
  3730. // excessive overrun following a key repeat sequence.
  3731. //
  3732. if ((pNextEvent->type == IM_KEYBOARD_EVENT) &&
  3733. (m_imControlledOSQ.numEvents < 5))
  3734. {
  3735. TRACE_OUT(( "Keyboard event so leaving loop"));
  3736. rc = FALSE;
  3737. }
  3738. }
  3739. else
  3740. {
  3741. //
  3742. // We're done.
  3743. //
  3744. rc = FALSE;
  3745. }
  3746. DC_EXIT_POINT:
  3747. DebugExitBOOL(ASShare::IMInjectingEvents, rc);
  3748. return(rc);
  3749. }
  3750. //
  3751. // IMMaybeInjectEvents()
  3752. //
  3753. // DESCRIPTION:
  3754. //
  3755. // This is called whenever the IM believes there may be an opportunity to
  3756. // inject more events into USER via the input event callbacks. The two
  3757. // main reasons for this are:
  3758. //
  3759. // 1. We have received a new event in the mouse or keyboard hooks. This
  3760. // will normally imply that an event has been removed from the system
  3761. // message queue so there will be at least one free slot on it.
  3762. //
  3763. // 2. We have added a new event (or events) to either the local or remote
  3764. // USER event queues. This means there will be at least one event waiting
  3765. // to be injected.
  3766. //
  3767. // This function is also called periodically (via IM_Periodic) to keep
  3768. // things moving.
  3769. //
  3770. // In order for an event to be injected there must be
  3771. //
  3772. // - an event waiting (with IM_FLAG_DONT_REPLAY reset)
  3773. // - a space on the USER system message queue
  3774. // - a new time stamp (if we are switching event sources).
  3775. //
  3776. // This function works as a state machine. It always starts in a specified
  3777. // state and will then take various actions and then possibly enter a new
  3778. // state. It continues to loop through this process until it cannot take
  3779. // any actions in one of its states at which point it returns.
  3780. //
  3781. // There are four states (each of which is further qualified by whether it
  3782. // refers to local or remote events). The states are:
  3783. //
  3784. // IM_INJECTING_EVENTS - we are injecting events into USER from the
  3785. // appropriate queue.
  3786. //
  3787. // IM_WAITING_FOR_TICK - we are waiting for a timer tick to give us a new
  3788. // timestamp before injecting events
  3789. //
  3790. // IM_DEVICE_TO_NEW_SOURCE - we are injecting fake events to bring the
  3791. // state of the keyboard and mouse (as seen by USER) into line with the
  3792. // state of the new source of input.
  3793. //
  3794. void ASShare::IMMaybeInjectEvents(void)
  3795. {
  3796. IMEVENT eventIn;
  3797. IMEVENT eventOut;
  3798. IMOSEVENT OSEvent;
  3799. BOOL replay;
  3800. UINT rcConvert;
  3801. UINT now;
  3802. HWND hwndDest;
  3803. HWND hwndParent;
  3804. POINT ptMousePos;
  3805. LPIMOSEVENT pNextEvent;
  3806. DebugEntry(IMMaybeInjectEvents);
  3807. ASSERT(m_pasLocal->m_caControlledBy);
  3808. //
  3809. // Check whether we should wait before converting events. We need to
  3810. // do this to prevent us being swamped with mouse move events when
  3811. // we're waiting for the desktop to scroll.
  3812. //
  3813. now = GetTickCount();
  3814. if (IN_TIME_RANGE(m_imControlledLastIncompleteConversion,
  3815. m_imControlledLastIncompleteConversion + IM_MIN_RECONVERSION_INTERVAL_MS, now))
  3816. {
  3817. goto IM_DISCARD;
  3818. }
  3819. //
  3820. // NOW TRANSLATE NETWORK EVENTS TO OS EVENTS
  3821. // We'll discard or inject them when the time is right.
  3822. // But don't do translation if there are still OS events left
  3823. // waiting to be injected from the previous packet.
  3824. //
  3825. if (m_imControlledEventQ.numEvents && !m_imControlledOSQ.numEvents)
  3826. {
  3827. //
  3828. // Get the event from the front of the network event queue.
  3829. //
  3830. eventIn = m_imControlledEventQ.events[0];
  3831. replay = FALSE;
  3832. switch (eventIn.type)
  3833. {
  3834. case IM_TYPE_3BUTTON:
  3835. case IM_TYPE_VK1:
  3836. case IM_TYPE_VK2:
  3837. case IM_TYPE_ASCII:
  3838. {
  3839. replay = TRUE;
  3840. break;
  3841. }
  3842. default:
  3843. ERROR_OUT(("Bogus NETWORK event being translated"));
  3844. break;
  3845. }
  3846. //
  3847. // After this while loop we test rcConvert to see whether the
  3848. // input packet can now be removed (has been fully processed).
  3849. // We only SET rcConvert if IMTranslateIncoming returns TRUE,
  3850. // yet IM_TR specifically returns FALSE to indicate that the
  3851. // input packet does not contain an event and is to be
  3852. // discarded. To fix this - set rcConvert here.
  3853. //
  3854. rcConvert = IM_IMQUEUEREMOVE;
  3855. while (IMTranslateIncoming(&eventIn, &eventOut))
  3856. {
  3857. rcConvert = IMConvertIMEventToOSEvent(&eventOut, &OSEvent);
  3858. //
  3859. // Inject the event into the OS queue (if required).
  3860. //
  3861. if (rcConvert & IM_OSQUEUEINJECT)
  3862. {
  3863. if (!replay)
  3864. {
  3865. OSEvent.flags |= IM_FLAG_DONT_REPLAY;
  3866. }
  3867. // Add to playback queue
  3868. // Is the queue filled up?
  3869. if (m_imControlledOSQ.numEvents == IM_SIZE_OSQ)
  3870. {
  3871. ERROR_OUT(("Failed to add OS event to queue"));
  3872. }
  3873. else
  3874. {
  3875. // Put this element at the tail.
  3876. m_imControlledOSQ.events[CIRCULAR_INDEX(m_imControlledOSQ.head,
  3877. m_imControlledOSQ.numEvents, IM_SIZE_OSQ)] =
  3878. OSEvent;
  3879. m_imControlledOSQ.numEvents++;
  3880. }
  3881. }
  3882. }
  3883. //
  3884. // The following test is not ideal as it relies on the fact
  3885. // that any events for which IMConvertIMEventToUSEREvent does
  3886. // not set IM_IMQUEUEREMOVE had a one-one mapping.
  3887. //
  3888. // However, we know that this is always the case with mouse
  3889. // events, which are the only events that will be cause this
  3890. // flag to be unset.
  3891. //
  3892. if (rcConvert & IM_IMQUEUEREMOVE)
  3893. {
  3894. //
  3895. // Remove this from the network queue
  3896. //
  3897. m_imControlledEventQ.numEvents--;
  3898. UT_MoveMemory(&(m_imControlledEventQ.events[0]),
  3899. &(m_imControlledEventQ.events[1]),
  3900. sizeof(IMEVENT) * m_imControlledEventQ.numEvents);
  3901. }
  3902. else
  3903. {
  3904. //
  3905. // Remember this so we don't flood the input injection with
  3906. // events when we don't remove the network event from the
  3907. // queue.
  3908. //
  3909. TRACE_OUT(( "do not shuffle"));
  3910. m_imControlledLastIncompleteConversion = GetTickCount();
  3911. }
  3912. }
  3913. IM_DISCARD:
  3914. //
  3915. // Get rid of all discarded events. Update the remote controller's
  3916. // key state array to reflect it. But since we aren't going to replay
  3917. // these, don't update our local key state table.
  3918. //
  3919. while (m_imControlledOSQ.numEvents > 0)
  3920. {
  3921. pNextEvent = m_imControlledOSQ.events + m_imControlledOSQ.head;
  3922. if (!(pNextEvent->flags & IM_FLAG_DONT_REPLAY))
  3923. {
  3924. // We're done.
  3925. break;
  3926. }
  3927. IMUpdateAsyncArray(m_aimControlledControllerKeyStates, pNextEvent);
  3928. ASSERT(m_imControlledOSQ.numEvents);
  3929. m_imControlledOSQ.numEvents--;
  3930. m_imControlledOSQ.head = CIRCULAR_INDEX(m_imControlledOSQ.head, 1,
  3931. IM_SIZE_OSQ);
  3932. }
  3933. //
  3934. // NOW INJECT OS EVENTS into system
  3935. //
  3936. while (IMInjectingEvents())
  3937. {
  3938. ;
  3939. }
  3940. DebugExitVOID(ASShare::IMMaybeInjectEvents);
  3941. }
  3942. //
  3943. // FUNCTION: IMUpdateAsyncArray
  3944. //
  3945. // DESCRIPTION:
  3946. //
  3947. // Called with the address of one of our async key state arrays and a
  3948. // IMOSEVENT this function updates the async key state array according to
  3949. // the contents of the IMOSEVENT.
  3950. //
  3951. // PARAMETERS:
  3952. //
  3953. // paimKeyStates - pointer to async key state array.
  3954. //
  3955. // pEvent - pointer to IMOSEVENT.
  3956. //
  3957. // RETURNS: NONE
  3958. //
  3959. //
  3960. void ASShare::IMUpdateAsyncArray
  3961. (
  3962. LPBYTE paimKeyStates,
  3963. LPIMOSEVENT pEvent
  3964. )
  3965. {
  3966. UINT flags;
  3967. UINT vkCode;
  3968. DebugEntry(ASShare::IMUpdateAsyncArray);
  3969. switch (pEvent->type)
  3970. {
  3971. case IM_MOUSE_EVENT:
  3972. //
  3973. // Update the async key state arrays for this event. Note that
  3974. // we treat each event as independent - this is how Windows
  3975. // treats them and if all the up/down flags are set Windows
  3976. // will generate six mouse message! (and in down,up order).
  3977. //
  3978. flags = pEvent->event.mouse.flags;
  3979. if (flags & MOUSEEVENTF_LEFTDOWN)
  3980. {
  3981. IM_SET_VK_DOWN(paimKeyStates[VK_LBUTTON]);
  3982. }
  3983. if (flags & MOUSEEVENTF_LEFTUP)
  3984. {
  3985. IM_SET_VK_UP(paimKeyStates[VK_LBUTTON]);
  3986. }
  3987. if (flags & MOUSEEVENTF_RIGHTDOWN)
  3988. {
  3989. IM_SET_VK_DOWN(paimKeyStates[VK_RBUTTON]);
  3990. }
  3991. if (flags & MOUSEEVENTF_RIGHTUP)
  3992. {
  3993. IM_SET_VK_UP(paimKeyStates[VK_RBUTTON]);
  3994. }
  3995. if (flags & MOUSEEVENTF_MIDDLEDOWN)
  3996. {
  3997. IM_SET_VK_DOWN(paimKeyStates[VK_MBUTTON]);
  3998. }
  3999. if (flags & MOUSEEVENTF_MIDDLEUP)
  4000. {
  4001. IM_SET_VK_UP(paimKeyStates[VK_MBUTTON]);
  4002. }
  4003. break;
  4004. case IM_KEYBOARD_EVENT:
  4005. //
  4006. // Update the async key state arrays.
  4007. //
  4008. vkCode = IM_KEV_VKCODE(*pEvent);
  4009. if (IM_KEV_KEYUP(*pEvent))
  4010. {
  4011. IM_SET_VK_UP(paimKeyStates[vkCode]);
  4012. }
  4013. else
  4014. {
  4015. //
  4016. // This is a key down event - check if it is a press or a
  4017. // repeat.
  4018. //
  4019. if (IM_KEY_STATE_IS_UP(paimKeyStates[vkCode]))
  4020. {
  4021. //
  4022. // This is a key press as the key was previously up -
  4023. // alter the toggle state. We keep the toggle state
  4024. // for all keys although we currently only worry about
  4025. // it for the `known' toggles.
  4026. //
  4027. IM_TOGGLE_VK(paimKeyStates[vkCode]);
  4028. }
  4029. IM_SET_VK_DOWN(paimKeyStates[vkCode]);
  4030. }
  4031. break;
  4032. default:
  4033. //
  4034. // Just ignore unexpected events.
  4035. //
  4036. ERROR_OUT(( "Unexpected event %u", pEvent->type));
  4037. break;
  4038. }
  4039. DebugExitVOID(ASShare::IMUpdateAsyncArray);
  4040. }
  4041.