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

1561 lines
66 KiB

  1. /****************************************************************************/
  2. /* aimapi.cpp */
  3. /* */
  4. /* RDP Input Manager API functions */
  5. /* */
  6. /* Copyright(c) Microsoft, PictureTel 1993-1997 */
  7. /* Copyright (c) 1997-1999 Microsoft Corporation */
  8. /****************************************************************************/
  9. #include <precomp.h>
  10. #pragma hdrstop
  11. #define TRC_FILE "aimapi"
  12. #include <adcg.h>
  13. #include <as_conf.hpp>
  14. #include <nwdwint.h>
  15. /****************************************************************************/
  16. /* API FUNCTION: IM_Init */
  17. /* */
  18. /* Called to initialize the IM */
  19. /****************************************************************************/
  20. void RDPCALL SHCLASS IM_Init(void)
  21. {
  22. TS_INPUT_CAPABILITYSET Caps;
  23. DC_BEGIN_FN("IM_Init");
  24. #define DC_INIT_DATA
  25. #include <aimdata.c>
  26. #undef DC_INIT_DATA
  27. // Set up the input capabilities.
  28. Caps.capabilitySetType = TS_CAPSETTYPE_INPUT;
  29. Caps.lengthCapability = sizeof(Caps);
  30. Caps.inputFlags = TS_INPUT_FLAG_SCANCODES | TS_INPUT_FLAG_MOUSEX |
  31. TS_INPUT_FLAG_FASTPATH_INPUT2 | TS_INPUT_FLAG_VKPACKET;
  32. CPC_RegisterCapabilities((PTS_CAPABILITYHEADER)&Caps,
  33. sizeof(TS_INPUT_CAPABILITYSET));
  34. TRC_NRM((TB, "IM initialized"));
  35. DC_END_FN();
  36. }
  37. /****************************************************************************/
  38. // IM_PlaybackEvents
  39. //
  40. // Called when an IM input PDU arrives. Unpacks and injects events.
  41. /****************************************************************************/
  42. // Maximum number of batched mouse/keyboard events. We batch because sending
  43. // the events to the next higher driver (IcaChannelInput()) is more expensive
  44. // than the loop overhead and mispredicted branches incurred to create the
  45. // array of events. This constant is set to the same number found as
  46. // MAXIMUM_ITEMS_READ in ntos\w32\ntuser\kernel\ntinput.c.
  47. #define EventBatchLen 10
  48. void __fastcall SHCLASS IM_PlaybackEvents(
  49. PTS_INPUT_PDU pInputPDU,
  50. unsigned DataLength)
  51. {
  52. PTS_INPUT_EVENT pInputEvent;
  53. unsigned i, j, MsgLimit;
  54. NTSTATUS Status;
  55. DC_BEGIN_FN("IM_PlaybackEvents");
  56. /************************************************************************/
  57. /* We do not handle NULL packets. */
  58. /************************************************************************/
  59. TRC_ASSERT((NULL != pInputPDU), (TB,"NULL input PDU"));
  60. /************************************************************************/
  61. // Make sure we have at least enough bytes to read the header. Not having
  62. // any inputs in the packet is also considered an error.
  63. /************************************************************************/
  64. if (DataLength >= sizeof(TS_INPUT_PDU)) {
  65. /********************************************************************/
  66. // Convert the TS_INPUT_PDU from wire format.
  67. /********************************************************************/
  68. TRC_NRM((TB, "Received packet of %u events", pInputPDU->numberEvents));
  69. // Make sure we have the full packet length available.
  70. if (DataLength >= (sizeof(TS_INPUT_PDU) +
  71. (pInputPDU->numberEvents - 1) * sizeof(TS_INPUT_EVENT))) {
  72. // For each packet in the piggybacked packets array...
  73. for (i = 0; i < pInputPDU->numberEvents; i++) {
  74. // Get a pointer to the packet within the array of events.
  75. pInputEvent = &pInputPDU->eventList[i];
  76. switch (pInputEvent->messageType) {
  77. case TS_INPUT_EVENT_SCANCODE: //intentional fallthru
  78. case TS_INPUT_EVENT_VKPACKET: //intentional fallthru
  79. {
  80. BYTE FastPathEmulate[4];
  81. unsigned CurKbdData;
  82. KEYBOARD_INPUT_DATA KbdData[EventBatchLen];
  83. MsgLimit = min((pInputPDU->numberEvents - i),
  84. EventBatchLen);
  85. CurKbdData = 0;
  86. for (j = 0; j < MsgLimit; j++) {
  87. if (pInputPDU->eventList[i + j].messageType ==
  88. TS_INPUT_EVENT_SCANCODE) {
  89. // To coalesce code, we convert this kbd format
  90. // to fast-path and call the fast-path
  91. // event converter. Since fast-path is now
  92. // the default, extra work falls to this
  93. // path.
  94. FastPathEmulate[0] = (BYTE)
  95. ((pInputPDU->eventList[i + j].u.key.
  96. keyboardFlags &
  97. (TS_KBDFLAGS_EXTENDED |
  98. TS_KBDFLAGS_EXTENDED1)) >> 7);
  99. if (pInputPDU->eventList[i + j].u.key.
  100. keyboardFlags & TS_KBDFLAGS_RELEASE)
  101. FastPathEmulate[0] |=
  102. TS_INPUT_FASTPATH_KBD_RELEASE;
  103. FastPathEmulate[1] = (BYTE)
  104. pInputPDU->eventList[i + j].u.key.
  105. keyCode;
  106. // Convert the wire packet to a kernel mode
  107. // keyboard event. We pack into an array of
  108. // events because an IcaChannelInput is
  109. // expensive.
  110. if (IMConvertFastPathKeyboardToEvent(
  111. FastPathEmulate,
  112. &KbdData[CurKbdData])) {
  113. TRC_NRM((TB, "Add kbd evt to batch index "
  114. "%d: MakeCode(%u) flags(%#x)",
  115. CurKbdData,
  116. KbdData[CurKbdData].MakeCode,
  117. KbdData[CurKbdData].Flags));
  118. CurKbdData++;
  119. }
  120. }
  121. else if (pInputPDU->eventList[i+j].messageType ==
  122. TS_INPUT_EVENT_VKPACKET)
  123. {
  124. FastPathEmulate[0] = (BYTE)
  125. ((pInputPDU->eventList[i + j].u.key.
  126. keyboardFlags &
  127. (TS_KBDFLAGS_EXTENDED |
  128. TS_KBDFLAGS_EXTENDED1)) >> 7);
  129. FastPathEmulate[0] |=
  130. TS_INPUT_FASTPATH_EVENT_VKPACKET;
  131. if (pInputPDU->eventList[i + j].u.key.
  132. keyboardFlags & TS_KBDFLAGS_RELEASE)
  133. FastPathEmulate[0] |=
  134. TS_INPUT_FASTPATH_KBD_RELEASE;
  135. memcpy(&FastPathEmulate[1],
  136. &pInputPDU->eventList[i + j].u.key.keyCode,
  137. 2);
  138. // Convert the wire packet to a kernel mode
  139. // keyboard event. We pack into an array of
  140. // events because an IcaChannelInput is
  141. // expensive.
  142. if (IMConvertFastPathKeyboardToEvent(
  143. FastPathEmulate,
  144. &KbdData[CurKbdData])) {
  145. TRC_NRM((TB, "Add kbd evt to batch index "
  146. "%d: MakeCode(%u) flags(%#x)",
  147. CurKbdData,
  148. KbdData[CurKbdData].MakeCode,
  149. KbdData[CurKbdData].Flags));
  150. CurKbdData++;
  151. }
  152. }
  153. else
  154. {
  155. break;
  156. }
  157. }
  158. // Advance past the used messages, taking into account
  159. // the outer loop increment.
  160. i += j - 1;
  161. // Now do the input.
  162. if (m_pTSWd->shadowState != SHADOW_CLIENT) {
  163. Status = IcaChannelInput(m_pTSWd->pContext,
  164. Channel_Keyboard, 0, NULL,
  165. (PUCHAR) KbdData,
  166. sizeof(KEYBOARD_INPUT_DATA) * CurKbdData);
  167. TRC_DBG((TB,"Return from keyboard input injection %lu",
  168. Status));
  169. }
  170. // Else we must be shadowing, so blow the shadow if we
  171. // see the hotkey in this set of input.
  172. else {
  173. Status = IMCheckForShadowHotkey(KbdData,
  174. CurKbdData);
  175. }
  176. }
  177. break;
  178. case TS_INPUT_EVENT_MOUSE:
  179. case TS_INPUT_EVENT_MOUSEX:
  180. {
  181. unsigned CurMouseData;
  182. MOUSE_INPUT_DATA MouseData[EventBatchLen];
  183. MsgLimit = min((pInputPDU->numberEvents - i),
  184. EventBatchLen);
  185. CurMouseData = 0;
  186. for (j = 0; j < MsgLimit; j++) {
  187. if ((pInputPDU->eventList[i + j].messageType ==
  188. TS_INPUT_EVENT_MOUSE) ||
  189. (pInputPDU->eventList[i + j].messageType ==
  190. TS_INPUT_EVENT_MOUSEX)) {
  191. // Convert the wire packet to a kernel mode
  192. // mouse event. We pack into an array of
  193. // events because an IcaChannelInput is
  194. // expensive.
  195. if (IMConvertMousePacketToEvent(
  196. &pInputPDU->eventList[i + j].u.mouse,
  197. &MouseData[CurMouseData],
  198. (pInputPDU->eventList[i + j].messageType ==
  199. TS_INPUT_EVENT_MOUSEX)))
  200. {
  201. TRC_NRM((TB, "Add mouse evt to batch "
  202. "index %u: x(%ld) y(%ld) flags(%#hx) buttonflags(%#hx)",
  203. CurMouseData,
  204. MouseData[CurMouseData].LastX,
  205. MouseData[CurMouseData].LastY,
  206. MouseData[CurMouseData].Flags,
  207. MouseData[CurMouseData].ButtonFlags));
  208. CurMouseData++;
  209. }
  210. }
  211. else
  212. {
  213. break;
  214. }
  215. }
  216. // Advance past the used messages, taking into account
  217. // the outer loop increment.
  218. i += j - 1;
  219. // Now do the input.
  220. Status = IcaChannelInput(m_pTSWd->pContext,
  221. Channel_Mouse, 0, NULL,
  222. (unsigned char *)MouseData,
  223. sizeof(MOUSE_INPUT_DATA) * CurMouseData);
  224. TRC_DBG((TB,"Return from mouse input injection %lu",
  225. Status));
  226. }
  227. break;
  228. case TS_INPUT_EVENT_SYNC:
  229. Status = IMDoSync(pInputEvent->u.sync.toggleFlags);
  230. break;
  231. default:
  232. {
  233. // Unknown event type - log an event and disconnect
  234. // the offending Client.
  235. TRC_ERR((TB, "Unrecognized imPacket (%d)",
  236. pInputEvent->messageType));
  237. WDW_LogAndDisconnect(m_pTSWd, TRUE,
  238. Log_RDP_InvalidInputPDUType,
  239. (PBYTE)&(pInputEvent->messageType),
  240. sizeof(pInputEvent->messageType));
  241. DC_QUIT;
  242. }
  243. }
  244. }
  245. // Go into TURBO scheduling on user input to flush screen deltas
  246. // faster.
  247. SCH_ContinueScheduling(SCH_MODE_TURBO);
  248. }
  249. else {
  250. goto InsufficientData;
  251. }
  252. }
  253. else {
  254. goto InsufficientData;
  255. }
  256. DC_EXIT_POINT:
  257. DC_END_FN();
  258. return;
  259. // Error handling.
  260. InsufficientData:
  261. TRC_ERR((TB,"Input PDU received, len=%u, but data is not long enough",
  262. DataLength));
  263. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_InputPDUBadLength,
  264. (PBYTE)pInputPDU, DataLength);
  265. DC_END_FN();
  266. }
  267. /****************************************************************************/
  268. // IMCheckForShadowHotkey
  269. //
  270. // Looks for the shadow hotkey among client keyboard input.
  271. /****************************************************************************/
  272. NTSTATUS RDPCALL SHCLASS IMCheckForShadowHotkey(
  273. KEYBOARD_INPUT_DATA *pKbdData,
  274. unsigned NumData)
  275. {
  276. unsigned i;
  277. NTSTATUS Status;
  278. ICA_CHANNEL_COMMAND Data;
  279. BOOLEAN bHotKeyDetected = FALSE;
  280. DC_BEGIN_FN("IMCheckForShadowHotkey");
  281. // Blow the shadow if we see the hotkey in this set of input.
  282. for (i = 0; i < NumData; i++) {
  283. bHotKeyDetected |= KeyboardHotKeyProcedure(
  284. m_pTSWd->HotkeyVk,
  285. m_pTSWd->HotkeyModifiers,
  286. &pKbdData[i],
  287. m_pTSWd->gpScancodeMap,
  288. m_pTSWd->pKbdTbl,
  289. m_pTSWd->KeyboardType101,
  290. m_pTSWd->pgafPhysKeyState);
  291. }
  292. if (!bHotKeyDetected) {
  293. Status = STATUS_SUCCESS;
  294. }
  295. else {
  296. m_pTSWd->HotkeyVk = 0; // cut off all piped data
  297. Data.Header.Command = ICA_COMMAND_SHADOW_HOTKEY;
  298. Status = IcaChannelInput(m_pTSWd->pContext, Channel_Command, 0, NULL,
  299. (PUCHAR)&Data, sizeof(Data));
  300. TRC_ALT((TB,"Injected shadow HOTKEY command! status=%08X", Status));
  301. }
  302. DC_END_FN();
  303. return Status;
  304. }
  305. /****************************************************************************/
  306. // IM_DecodeFastPathInput
  307. //
  308. // On a primary stack, decodes optimized input bytestream and injects into
  309. // the input stream. NumEvents is passed from MCS, decoded from the header
  310. // -- if zero, the first byte of the data to decode contains the number of
  311. // events.
  312. /****************************************************************************/
  313. void RDPCALL SHCLASS IM_DecodeFastPathInput(
  314. BYTE *pData,
  315. unsigned DataLength,
  316. unsigned NumEvents)
  317. {
  318. unsigned i, j, MsgLimit;
  319. NTSTATUS Status;
  320. BYTE *pCurDecode = pData;
  321. DC_BEGIN_FN("IM_DecodeFastPathInput");
  322. // Make sure we've been given enough data.
  323. if (NumEvents == 0) {
  324. if (DataLength >= 1) {
  325. NumEvents = *pData;
  326. pData++;
  327. DataLength--;
  328. }
  329. else {
  330. TRC_ERR((TB,"Len %u too short for DataLength", DataLength));
  331. goto ShortData;
  332. }
  333. }
  334. // For each event...
  335. for (i = 0; i < NumEvents; i++) {
  336. if (DataLength >= 1) {
  337. switch (*pData & TS_INPUT_FASTPATH_EVENT_MASK) {
  338. case TS_INPUT_FASTPATH_EVENT_KEYBOARD:
  339. {
  340. unsigned CurKbdData;
  341. KEYBOARD_INPUT_DATA KbdData[EventBatchLen];
  342. MsgLimit = min((NumEvents - i), EventBatchLen);
  343. CurKbdData = 0;
  344. for (j = 0; j < MsgLimit; j++) {
  345. if (DataLength >= 1) {
  346. if ((*pData & TS_INPUT_FASTPATH_EVENT_MASK) ==
  347. TS_INPUT_FASTPATH_EVENT_KEYBOARD) {
  348. if (DataLength >= 2) {
  349. if (IMConvertFastPathKeyboardToEvent(
  350. pData, &KbdData[CurKbdData]))
  351. CurKbdData++;
  352. pData += 2;
  353. DataLength -= 2;
  354. }
  355. else {
  356. TRC_ERR((TB,"Ran out of space reading "
  357. "keyboard events"));
  358. goto ShortData;
  359. }
  360. }
  361. else {
  362. break;
  363. }
  364. }
  365. else {
  366. TRC_ERR((TB,"Ran out of space reading keyboard "
  367. "events"));
  368. goto ShortData;
  369. }
  370. }
  371. // Advance past the used messages, taking into account
  372. // the outer loop increment.
  373. i += j - 1;
  374. // Now do the input.
  375. if (m_pTSWd->shadowState != SHADOW_CLIENT) {
  376. Status = IcaChannelInput(m_pTSWd->pContext,
  377. Channel_Keyboard, 0, NULL,
  378. (PUCHAR)KbdData,
  379. sizeof(KEYBOARD_INPUT_DATA) * CurKbdData);
  380. TRC_DBG((TB,"Return from keyboard input injection %lu",
  381. Status));
  382. }
  383. // Else we must be shadowing, so blow the shadow if we
  384. // see the hotkey in this set of input.
  385. else {
  386. Status = IMCheckForShadowHotkey(KbdData,
  387. CurKbdData);
  388. }
  389. break;
  390. }
  391. case TS_INPUT_FASTPATH_EVENT_VKPACKET:
  392. {
  393. unsigned CurKbdData;
  394. KEYBOARD_INPUT_DATA KbdData[EventBatchLen];
  395. MsgLimit = min((NumEvents - i), EventBatchLen);
  396. CurKbdData = 0;
  397. for (j = 0; j < MsgLimit; j++) {
  398. if (DataLength >= 1) {
  399. if ((*pData & TS_INPUT_FASTPATH_EVENT_MASK) ==
  400. TS_INPUT_FASTPATH_EVENT_VKPACKET) {
  401. if (DataLength >= 3) {
  402. if (IMConvertFastPathKeyboardToEvent(
  403. pData, &KbdData[CurKbdData]))
  404. CurKbdData++;
  405. pData += 3;
  406. DataLength -= 3;
  407. }
  408. else {
  409. TRC_ERR((TB,"Ran out of space reading "
  410. "keyboard events"));
  411. goto ShortData;
  412. }
  413. }
  414. else {
  415. break;
  416. }
  417. }
  418. else {
  419. TRC_ERR((TB,"Ran out of space reading keyboard "
  420. "events"));
  421. goto ShortData;
  422. }
  423. }
  424. // Advance past the used messages, taking into account
  425. // the outer loop increment.
  426. i += j - 1;
  427. // Now do the input.
  428. if (m_pTSWd->shadowState != SHADOW_CLIENT) {
  429. Status = IcaChannelInput(m_pTSWd->pContext,
  430. Channel_Keyboard, 0, NULL,
  431. (PUCHAR)KbdData,
  432. sizeof(KEYBOARD_INPUT_DATA) * CurKbdData);
  433. TRC_DBG((TB,"Return from keyboard input injection %lu",
  434. Status));
  435. }
  436. break;
  437. }
  438. case TS_INPUT_FASTPATH_EVENT_MOUSE:
  439. case TS_INPUT_FASTPATH_EVENT_MOUSEX:
  440. {
  441. unsigned CurMouseData;
  442. MOUSE_INPUT_DATA MouseData[EventBatchLen];
  443. // After the 1-byte header the following 6 bytes are
  444. // the same format as a regular mouse input.
  445. MsgLimit = min((NumEvents - i), EventBatchLen);
  446. CurMouseData = 0;
  447. for (j = 0; j < MsgLimit; j++) {
  448. if (DataLength >= 1) {
  449. if ((((*pData & TS_INPUT_FASTPATH_EVENT_MASK) ==
  450. TS_INPUT_FASTPATH_EVENT_MOUSE) ||
  451. (*pData & TS_INPUT_FASTPATH_EVENT_MASK) ==
  452. TS_INPUT_FASTPATH_EVENT_MOUSEX)) {
  453. if (DataLength >= 7) {
  454. // Convert the wire packet to a kernel
  455. // mode mouse event. We pack into an
  456. // array of events because an
  457. // IcaChannelInput is expensive.
  458. if (IMConvertMousePacketToEvent(
  459. (TS_POINTER_EVENT UNALIGNED *)
  460. (pData + 1),
  461. &MouseData[CurMouseData],
  462. ((*pData &
  463. TS_INPUT_FASTPATH_EVENT_MASK) ==
  464. TS_INPUT_FASTPATH_EVENT_MOUSEX)))
  465. CurMouseData++;
  466. pData += 7;
  467. DataLength -= 7;
  468. }
  469. else {
  470. TRC_ERR((TB,"Out of data decoding "
  471. "mouse, i=%u, j=%u, NumEvents=%u, "
  472. "DataLen=%u",
  473. i, j, NumEvents, DataLength));
  474. goto ShortData;
  475. }
  476. }
  477. else {
  478. break;
  479. }
  480. }
  481. else {
  482. TRC_ERR((TB,"Out of data decoding "
  483. "mouse, i=%u, j=%u, NumEvents=%u, "
  484. "DataLen=%u",
  485. i, j, NumEvents, DataLength));
  486. goto ShortData;
  487. }
  488. }
  489. // Advance past the used messages, taking into account
  490. // the outer loop increment.
  491. i += j - 1;
  492. // Now do the input.
  493. Status = IcaChannelInput(m_pTSWd->pContext,
  494. Channel_Mouse, 0, NULL,
  495. (unsigned char *)MouseData,
  496. sizeof(MOUSE_INPUT_DATA) * CurMouseData);
  497. TRC_DBG((TB,"Return from mouse input injection %lu",
  498. Status));
  499. break;
  500. }
  501. case TS_INPUT_FASTPATH_EVENT_SYNC:
  502. Status = IMDoSync(*pData & TS_INPUT_FASTPATH_FLAGS_MASK);
  503. pData++;
  504. DataLength--;
  505. break;
  506. default:
  507. // Unknown event type - log an event and disconnect
  508. // the offending Client.
  509. TRC_ERR((TB, "Unrecognized imPacket (%d)",
  510. *pData & TS_INPUT_FASTPATH_EVENT_MASK));
  511. WDW_LogAndDisconnect(m_pTSWd, TRUE,
  512. Log_RDP_InvalidInputPDUType, pData, 1);
  513. DC_QUIT;
  514. }
  515. }
  516. else {
  517. TRC_ERR((TB,"Out of data reading input events"));
  518. goto ShortData;
  519. }
  520. } // end event loop
  521. // Go into TURBO scheduling on user input to flush screen deltas
  522. // faster.
  523. SCH_ContinueScheduling(SCH_MODE_TURBO);
  524. DC_EXIT_POINT:
  525. DC_END_FN();
  526. return;
  527. ShortData:
  528. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_InputPDUBadLength,
  529. (PBYTE)pData, DataLength);
  530. DC_END_FN();
  531. }
  532. /****************************************************************************/
  533. // IM_ConvertFastPathToShadow
  534. //
  535. // Inverse of the client IHTranslateInputToFastPath() function -- takes
  536. // a fast-path input stream and converts to the regular encoding. Used
  537. // by a passthru stack to send the resulting regular encoding over the
  538. // cross-server pipe via IcaRawInput().
  539. /****************************************************************************/
  540. #define MaxDefaultEvents 16
  541. void RDPCALL SHCLASS IM_ConvertFastPathToShadow(
  542. BYTE *pData,
  543. unsigned DataLength,
  544. unsigned NumEvents)
  545. {
  546. unsigned i, j, EventsThisPDU, PDUSize;
  547. NTSTATUS Status;
  548. PTS_INPUT_PDU pInput;
  549. BYTE DefaultBuf[sizeof(TS_INPUT_PDU) + sizeof(TS_INPUT_EVENT) *
  550. (MaxDefaultEvents - 1)];
  551. DC_BEGIN_FN("IM_ConvertFastPathToShadow");
  552. // Make sure we've been given enough data.
  553. if (NumEvents == 0) {
  554. if (DataLength >= 1) {
  555. NumEvents = *pData;
  556. pData++;
  557. DataLength--;
  558. }
  559. else {
  560. TRC_ERR((TB,"Len %u too short for DataLength", DataLength));
  561. goto ShortData;
  562. }
  563. }
  564. // We don't alloc memory, just send multiple input PDUs if we need to.
  565. if (NumEvents > 0) {
  566. pInput = (PTS_INPUT_PDU)DefaultBuf;
  567. // set the input pdu array to 0.
  568. memset(pInput, 0, sizeof(TS_INPUT_PDU) + sizeof(TS_INPUT_EVENT) *
  569. (MaxDefaultEvents - 1));
  570. }
  571. else {
  572. DC_QUIT;
  573. }
  574. // Set up the input PDU header info that won't be changing.
  575. // Shadow handling does not care about the following, so we don't go to
  576. // thr trouble of making up or grabbing values:
  577. // shareDataHeader.shareControlHeader.pduSource
  578. pInput->shareDataHeader.shareControlHeader.pduType = TS_PROTOCOL_VERSION |
  579. TS_PDUTYPE_DATAPDU;
  580. pInput->shareDataHeader.shareID = scShareID;
  581. pInput->shareDataHeader.streamID = TS_STREAM_LOW;
  582. pInput->shareDataHeader.pduType2 = TS_PDUTYPE2_INPUT;
  583. // Loop while we need to send more PDUs.
  584. for (j = 0; j < NumEvents;) {
  585. // Reset the input PDU info.
  586. EventsThisPDU = min(NumEvents - j, MaxDefaultEvents);
  587. pInput->numberEvents = (TSUINT16)EventsThisPDU;
  588. PDUSize = sizeof(TS_INPUT_PDU) + sizeof(TS_INPUT_EVENT) *
  589. (EventsThisPDU - 1);
  590. pInput->shareDataHeader.shareControlHeader.totalLength =
  591. (TSUINT16)PDUSize;
  592. pInput->shareDataHeader.uncompressedLength =
  593. (TSUINT16)PDUSize;
  594. // For each event...
  595. for (i = 0; i < EventsThisPDU; i++) {
  596. if (DataLength >= 1) {
  597. switch (*pData & TS_INPUT_FASTPATH_EVENT_MASK) {
  598. case TS_INPUT_FASTPATH_EVENT_KEYBOARD:
  599. if (DataLength >= 2) {
  600. // Use a mask, shift, and OR to avoid branches for the
  601. // extended flags.
  602. pInput->eventList[i].messageType =
  603. TS_INPUT_EVENT_SCANCODE;
  604. pInput->eventList[i].u.key.keyboardFlags =
  605. (*pData & (BYTE)(
  606. TS_INPUT_FASTPATH_KBD_EXTENDED |
  607. TS_INPUT_FASTPATH_KBD_EXTENDED1)) << 7;
  608. if (*pData & TS_INPUT_FASTPATH_KBD_RELEASE)
  609. pInput->eventList[i].u.key.keyboardFlags |=
  610. TS_KBDFLAGS_RELEASE;
  611. pInput->eventList[i].u.key.keyCode = pData[1];
  612. pData += 2;
  613. DataLength -= 2;
  614. }
  615. else {
  616. goto ShortData;
  617. }
  618. break;
  619. case TS_INPUT_FASTPATH_EVENT_VKPACKET:
  620. if (DataLength >= 3) {
  621. // Use a mask, shift, and OR to avoid branches for the
  622. // extended flags.
  623. pInput->eventList[i].messageType =
  624. TS_INPUT_EVENT_VKPACKET;
  625. pInput->eventList[i].u.key.keyboardFlags =
  626. (*pData & (BYTE)(
  627. TS_INPUT_FASTPATH_KBD_EXTENDED |
  628. TS_INPUT_FASTPATH_KBD_EXTENDED1)) << 7;
  629. if (*pData & TS_INPUT_FASTPATH_KBD_RELEASE)
  630. pInput->eventList[i].u.key.keyboardFlags |=
  631. TS_KBDFLAGS_RELEASE;
  632. memcpy(&pInput->eventList[i].u.key.keyCode,
  633. &pData[1],
  634. 2);
  635. TRC_NRM((TB,"Shadow pass: 0x%x flags:0x%x\n",
  636. pInput->eventList[i].u.key.keyCode,
  637. pInput->eventList[i].u.key.keyboardFlags));
  638. pData += 3;
  639. DataLength -= 3;
  640. }
  641. else {
  642. goto ShortData;
  643. }
  644. break;
  645. case TS_INPUT_FASTPATH_EVENT_MOUSE:
  646. case TS_INPUT_FASTPATH_EVENT_MOUSEX:
  647. if (DataLength >= 7) {
  648. pInput->eventList[i].messageType =
  649. ((*pData & TS_INPUT_FASTPATH_EVENT_MASK) ==
  650. TS_INPUT_FASTPATH_EVENT_MOUSE ?
  651. TS_INPUT_EVENT_MOUSE :
  652. TS_INPUT_EVENT_MOUSEX);
  653. memcpy(&pInput->eventList[i].u.mouse, pData + 1,
  654. sizeof(TS_POINTER_EVENT));
  655. pData += 7;
  656. DataLength -= 7;
  657. }
  658. else {
  659. goto ShortData;
  660. }
  661. break;
  662. case TS_INPUT_FASTPATH_EVENT_SYNC:
  663. pInput->eventList[i].messageType = TS_INPUT_EVENT_SYNC;
  664. pInput->eventList[i].u.sync.toggleFlags =
  665. (*pData & (BYTE)TS_INPUT_FASTPATH_FLAGS_MASK);
  666. pData++;
  667. DataLength--;
  668. break;
  669. default:
  670. TRC_ERR((TB, "Unrecognized imPacket (%d)",
  671. *pData & TS_INPUT_FASTPATH_EVENT_MASK));
  672. DC_QUIT;
  673. }
  674. }
  675. else {
  676. TRC_ERR((TB,"Out of data reading input events"));
  677. goto ShortData;
  678. }
  679. } // end event loop
  680. j += i;
  681. // Launch the PDU.
  682. TRC_NRM((TB, "Forwarding shadow data: %ld", DataLength));
  683. Status = IcaRawInput(m_pTSWd->pContext, NULL, (BYTE *)pInput,
  684. PDUSize);
  685. if (!NT_SUCCESS(Status)) {
  686. TRC_ERR((TB, "Failed shadow input data [%ld]: %x",
  687. DataLength, Status));
  688. }
  689. }
  690. DC_EXIT_POINT:
  691. DC_END_FN();
  692. return;
  693. ShortData:
  694. TRC_ERR((TB,"Short PDU during passthru translation"));
  695. DC_END_FN();
  696. }
  697. /****************************************************************************/
  698. // IM_CheckUpdateCursor
  699. //
  700. // Called during output processing to check to see if we need to send
  701. // a mouse-moved packet to the client.
  702. /****************************************************************************/
  703. void RDPCALL SHCLASS IM_CheckUpdateCursor(
  704. PPDU_PACKAGE_INFO pPkgInfo,
  705. UINT32 currentTime)
  706. {
  707. PPOINTL pCursorPos;
  708. UINT32 timeDelta;
  709. DC_BEGIN_FN("IM_CheckUpdateCursor");
  710. // Check to see if the cursor has moved since last time we came
  711. // through - if not, then there's no point in doing any of the
  712. // following tests!
  713. if (!CM_CursorMoved()) {
  714. TRC_DBG((TB, "No move since last time through"));
  715. DC_QUIT;
  716. }
  717. // Get the current cursor position - we always need this.
  718. pCursorPos = CM_GetCursorPos();
  719. // Check to see if the mouse has been moved at the display driver level
  720. // yet - don't do anything until it has to avoid the mouse leaping to 0,0
  721. // on connection
  722. if (pCursorPos->x != 0xffffffff) {
  723. // Check to see if the cursor is hidden - we should do nothing
  724. // here if it is. In particular, the 'real' cursor is hidden
  725. // during dragging of a single file and a 'fake' is drawn (by
  726. // Explorer?). Ignoring the fact that it is hidden causes the
  727. // 'faked' cursor to keep leaping back to where the drag started!
  728. if (CM_IsCursorVisible()) {
  729. timeDelta = currentTime - imLastLowLevelMouseEventTime;
  730. TRC_NRM((TB, "SetCursorPos (%d:%d) lastEvent:%#lx "
  731. "delta:%#lx", pCursorPos->x, pCursorPos->y,
  732. imLastLowLevelMouseEventTime, timeDelta));
  733. CM_SendCursorMovedPacket(pPkgInfo);
  734. }
  735. else {
  736. TRC_NRM((TB, "Cursor hidden - skipping"));
  737. }
  738. }
  739. else {
  740. TRC_NRM((TB, "No mouse updates rec'd from client - not moving"));
  741. }
  742. // Clear the cursor moved flag.
  743. CM_ClearCursorMoved();
  744. DC_EXIT_POINT:
  745. DC_END_FN();
  746. }
  747. /****************************************************************************/
  748. /* API FUNCTION: IM_PartyJoiningShare */
  749. /* */
  750. /* Called by SC when a new party is joining the share */
  751. /* */
  752. /* PARAMETERS: */
  753. /* personID - the local ID of the new party. */
  754. /* oldShareSize - the number of the parties which were in the share (ie */
  755. /* excludes the joining party). */
  756. /* */
  757. /* RETURNS: */
  758. /* TRUE - the IM can accept the new party */
  759. /* FALSE - the IM cannot accept the new party */
  760. /****************************************************************************/
  761. BOOL RDPCALL SHCLASS IM_PartyJoiningShare(
  762. LOCALPERSONID personID,
  763. unsigned oldShareSize)
  764. {
  765. BOOL rc = FALSE;
  766. PTS_INPUT_CAPABILITYSET pIMCaps;
  767. DC_BEGIN_FN("IM_PartyJoiningShare");
  768. DC_IGNORE_PARAMETER(oldShareSize)
  769. // One-time init for each new share.
  770. if (oldShareSize == 0) {
  771. KEYBOARD_INDICATOR_PARAMETERS kip = {0};
  772. SD_IOCTL sdIoctl;
  773. // The keys will initially all be up.
  774. memset(imKeyStates, 0, sizeof(imKeyStates));
  775. // Reset when we last saw a low level mouse event.
  776. COM_GETTICKCOUNT(imLastLowLevelMouseEventTime);
  777. // Get the toggle key states.
  778. sdIoctl.IoControlCode = IOCTL_KEYBOARD_QUERY_INDICATORS;
  779. sdIoctl.InputBuffer = NULL;
  780. sdIoctl.InputBufferLength = 0;
  781. sdIoctl.OutputBuffer = &kip;
  782. sdIoctl.OutputBufferLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
  783. sdIoctl.BytesReturned = 0;
  784. if (WDW_QueryKeyboardIndicators(m_pTSWd, &sdIoctl) ==
  785. STATUS_SUCCESS) {
  786. TRC_NRM((TB, "Got toggle key states ok"));
  787. imKeyStates[IM_SC_CAPITAL] = kip.LedFlags & KEYBOARD_CAPS_LOCK_ON;
  788. imKeyStates[IM_SC_NUMLOCK] = kip.LedFlags & KEYBOARD_NUM_LOCK_ON;
  789. imKeyStates[IM_SC_SCROLL] = kip.LedFlags &
  790. KEYBOARD_SCROLL_LOCK_ON;
  791. }
  792. TRC_NRM((TB, "Toggle key states: Caps:%s, Num:%s, Scroll:%s",
  793. (imKeyStates[IM_SC_CAPITAL] & 0x01) ? "ON" : "OFF",
  794. (imKeyStates[IM_SC_NUMLOCK] & 0x01) ? "ON" : "OFF",
  795. (imKeyStates[IM_SC_SCROLL] & 0x01) ? "ON" : "OFF"));
  796. }
  797. // Make sure scancodes are supported by client.
  798. pIMCaps = (PTS_INPUT_CAPABILITYSET)
  799. CPC_GetCapabilitiesForPerson(personID, TS_CAPSETTYPE_INPUT);
  800. if (pIMCaps != NULL && pIMCaps->inputFlags & TS_INPUT_FLAG_SCANCODES) {
  801. rc = TRUE;
  802. }
  803. else {
  804. TRC_ERR((TB, "Rejecting join from [%u]: has no scancode support",
  805. personID));
  806. }
  807. DC_END_FN();
  808. return rc;
  809. }
  810. /****************************************************************************/
  811. /* API FUNCTION: IM_PartyLeftShare */
  812. /* */
  813. /* Called when a party has left the share. */
  814. /* */
  815. /* PARAMETERS: */
  816. /* personID - the local ID of the new party. */
  817. /* newShareSize - the number of the parties now in the share (ie excludes */
  818. /* the leaving party). */
  819. /****************************************************************************/
  820. void RDPCALL SHCLASS IM_PartyLeftShare(
  821. LOCALPERSONID personID,
  822. unsigned newShareSize)
  823. {
  824. DC_BEGIN_FN("IM_PartyLeftShare");
  825. if (newShareSize == 0) {
  826. // Need to make sure we set all keys up, just in case we were
  827. // shadowing a console session.
  828. if (m_pTSWd->StackClass == Stack_Shadow)
  829. IMResetKeyStateArray();
  830. }
  831. DC_END_FN();
  832. }
  833. /****************************************************************************/
  834. /* FUNCTION: IMConvertMousePacketToEvent */
  835. /* */
  836. /* Converts the TS_INPUT_EVENT format to a MOUSE_INPUT_DATA OS format */
  837. /* */
  838. /* PARAMETERS: */
  839. /* pInputEvent - the TS_INPUT_EVENT to be converted */
  840. /* pMouseData - the MOUSE_INPUT_DATA to modify */
  841. /* */
  842. /* RETURNS: */
  843. /* TRUE if the packet has been recognised and converted */
  844. /* FALSE if the packet was not recognised */
  845. /****************************************************************************/
  846. BOOL __fastcall SHCLASS IMConvertMousePacketToEvent(
  847. TS_POINTER_EVENT UNALIGNED *pInputEvent,
  848. MOUSE_INPUT_DATA *pMouseData,
  849. BOOL bMouseX)
  850. {
  851. BOOL rc = TRUE;
  852. DC_BEGIN_FN("IMConvertMousePacketToEvent");
  853. /************************************************************************/
  854. /* Set all the fields to zero */
  855. /************************************************************************/
  856. memset(pMouseData, 0, sizeof(MOUSE_INPUT_DATA));
  857. // Check for a wheel rotate, since this is easy to process.
  858. // (It cannot include any mouse movement as well).
  859. // MouseX events are not used for wheel events.
  860. if (!bMouseX && (pInputEvent->pointerFlags & TS_FLAG_MOUSE_WHEEL))
  861. {
  862. if (!(pInputEvent->pointerFlags &
  863. (TS_FLAG_MOUSE_BUTTON1 |
  864. TS_FLAG_MOUSE_BUTTON2 |
  865. TS_FLAG_MOUSE_BUTTON3)))
  866. {
  867. /****************************************************************/
  868. /* This is a wheel movement. */
  869. /****************************************************************/
  870. pMouseData->ButtonFlags = MOUSE_WHEEL;
  871. pMouseData->ButtonData = pInputEvent->pointerFlags &
  872. TS_FLAG_MOUSE_ROTATION_MASK;
  873. /****************************************************************/
  874. /* Sign extend the rotation amount up to the full 32 */
  875. /* bits */
  876. /****************************************************************/
  877. if (pMouseData->ButtonData & TS_FLAG_MOUSE_DIRECTION)
  878. {
  879. pMouseData->ButtonData |= ~TS_FLAG_MOUSE_ROTATION_MASK;
  880. }
  881. }
  882. DC_QUIT;
  883. }
  884. /************************************************************************/
  885. /* We are left now with non wheel-rotate events. Note that we could be */
  886. /* dealing with either a TS_INPUT_EVENT_MOUSE or a */
  887. /* TS_INPUT_EVENT_MOUSEX. Either way we must store the mouse position. */
  888. /************************************************************************/
  889. pMouseData->LastX = min( (int)(m_desktopWidth - 1),
  890. (int)(max(0, pInputEvent->x)) );
  891. pMouseData->LastY = min( (int)(m_desktopHeight - 1),
  892. (int)(max(0, pInputEvent->y)) );
  893. /************************************************************************/
  894. /* Add flags as appropriate. */
  895. /************************************************************************/
  896. /************************************************************************/
  897. /* Make all submitted events absolute moves (both clicks and moves) */
  898. /************************************************************************/
  899. pMouseData->Flags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP;
  900. //
  901. // Set the flags to indicate if this move is originating
  902. // from a shadow client
  903. //
  904. if (m_pTSWd->StackClass == Stack_Shadow ) {
  905. // this event is coming from a shadow client
  906. pMouseData->Flags |= MOUSE_TERMSRV_SRC_SHADOW;
  907. }
  908. /************************************************************************/
  909. /* Set click flags for click events (i.e. non-move events) */
  910. /************************************************************************/
  911. if (!(!bMouseX && (pInputEvent->pointerFlags & TS_FLAG_MOUSE_MOVE)))
  912. {
  913. if (!bMouseX)
  914. {
  915. /****************************************************************/
  916. /* A standard mouse event */
  917. /****************************************************************/
  918. switch (pInputEvent->pointerFlags &
  919. (TS_FLAG_MOUSE_BUTTON1 | TS_FLAG_MOUSE_BUTTON2 |
  920. TS_FLAG_MOUSE_BUTTON3 | TS_FLAG_MOUSE_DOWN))
  921. {
  922. case TS_FLAG_MOUSE_BUTTON1 | TS_FLAG_MOUSE_DOWN:
  923. {
  924. pMouseData->ButtonFlags = MOUSE_BUTTON_1_DOWN;
  925. // Update the key state array.
  926. IM_SET_KEY_DOWN(imKeyStates[IM_SC_LBUTTON]);
  927. }
  928. break;
  929. case TS_FLAG_MOUSE_BUTTON1:
  930. {
  931. pMouseData->ButtonFlags = MOUSE_BUTTON_1_UP;
  932. if (IM_KEY_STATE_IS_UP(imKeyStates[IM_SC_LBUTTON]))
  933. {
  934. /********************************************************/
  935. /* Discard unmatched mouse button up event */
  936. /********************************************************/
  937. TRC_NRM((TB, "discard mouse up event"));
  938. rc = FALSE;
  939. DC_QUIT;
  940. }
  941. // Update the key state array.
  942. IM_SET_KEY_UP(imKeyStates[IM_SC_LBUTTON]);
  943. }
  944. break;
  945. case TS_FLAG_MOUSE_BUTTON2 | TS_FLAG_MOUSE_DOWN:
  946. {
  947. pMouseData->ButtonFlags = MOUSE_BUTTON_2_DOWN;
  948. // Update the key state array.
  949. IM_SET_KEY_DOWN(imKeyStates[IM_SC_RBUTTON]);
  950. }
  951. break;
  952. case TS_FLAG_MOUSE_BUTTON2:
  953. {
  954. pMouseData->ButtonFlags = MOUSE_BUTTON_2_UP;
  955. if (IM_KEY_STATE_IS_UP(imKeyStates[IM_SC_RBUTTON]))
  956. {
  957. /********************************************************/
  958. /* Discard unmatched mouse button up event */
  959. /********************************************************/
  960. TRC_NRM((TB, "discard mouse up event"));
  961. rc = FALSE;
  962. DC_QUIT;
  963. }
  964. // Update the key state array.
  965. IM_SET_KEY_UP(imKeyStates[IM_SC_RBUTTON]);
  966. }
  967. break;
  968. case TS_FLAG_MOUSE_BUTTON3 | TS_FLAG_MOUSE_DOWN:
  969. {
  970. pMouseData->ButtonFlags = MOUSE_BUTTON_3_DOWN;
  971. IM_SET_KEY_DOWN(imKeyStates[IM_SC_MBUTTON]);
  972. }
  973. break;
  974. case TS_FLAG_MOUSE_BUTTON3:
  975. {
  976. pMouseData->ButtonFlags = MOUSE_BUTTON_3_UP;
  977. if (IM_KEY_STATE_IS_UP(imKeyStates[IM_SC_MBUTTON]))
  978. {
  979. /********************************************************/
  980. /* Discard unmatched mouse button up event */
  981. /********************************************************/
  982. TRC_NRM((TB, "discard mouse up event"));
  983. rc = FALSE;
  984. DC_QUIT;
  985. }
  986. IM_SET_KEY_UP(imKeyStates[IM_SC_MBUTTON]);
  987. }
  988. break;
  989. default:
  990. {
  991. /************************************************************/
  992. /* If we don't recognise this then don't play it back. This */
  993. /* should not be possible according to the T.128 spec, */
  994. /* which restricts the allowed flag combinations to the */
  995. /* above */
  996. /************************************************************/
  997. TRC_ERR((TB, "Unrecognized mouse flags (%04X)",
  998. pInputEvent->pointerFlags));
  999. WDW_LogAndDisconnect(m_pTSWd, TRUE,
  1000. Log_RDP_InvalidInputPDUMouse,
  1001. (PBYTE)pInputEvent,
  1002. sizeof(PTS_INPUT_EVENT));
  1003. rc = FALSE;
  1004. DC_QUIT;
  1005. }
  1006. }
  1007. }
  1008. else
  1009. {
  1010. /****************************************************************/
  1011. /* An extended mouse event */
  1012. /****************************************************************/
  1013. switch (pInputEvent->pointerFlags &
  1014. (TS_FLAG_MOUSEX_BUTTON1 | TS_FLAG_MOUSEX_BUTTON2 |
  1015. TS_FLAG_MOUSEX_DOWN))
  1016. {
  1017. case TS_FLAG_MOUSEX_BUTTON1 | TS_FLAG_MOUSEX_DOWN:
  1018. {
  1019. pMouseData->ButtonFlags = MOUSE_BUTTON_4_DOWN;
  1020. // Update the key state array.
  1021. IM_SET_KEY_DOWN(imKeyStates[IM_SC_XBUTTON1]);
  1022. }
  1023. break;
  1024. case TS_FLAG_MOUSEX_BUTTON1:
  1025. {
  1026. pMouseData->ButtonFlags = MOUSE_BUTTON_4_UP;
  1027. if (IM_KEY_STATE_IS_UP(imKeyStates[IM_SC_XBUTTON1]))
  1028. {
  1029. /********************************************************/
  1030. /* Discard unmatched mouse button up event */
  1031. /********************************************************/
  1032. TRC_NRM((TB, "discard mouse up event"));
  1033. rc = FALSE;
  1034. DC_QUIT;
  1035. }
  1036. // Update the key state array.
  1037. IM_SET_KEY_UP(imKeyStates[IM_SC_XBUTTON1]);
  1038. }
  1039. break;
  1040. case TS_FLAG_MOUSEX_BUTTON2 | TS_FLAG_MOUSEX_DOWN:
  1041. {
  1042. pMouseData->ButtonFlags = MOUSE_BUTTON_5_DOWN;
  1043. // Update the key state array.
  1044. IM_SET_KEY_DOWN(imKeyStates[IM_SC_XBUTTON2]);
  1045. }
  1046. break;
  1047. case TS_FLAG_MOUSEX_BUTTON2:
  1048. {
  1049. pMouseData->ButtonFlags = MOUSE_BUTTON_5_UP;
  1050. if (IM_KEY_STATE_IS_UP(imKeyStates[IM_SC_XBUTTON2]))
  1051. {
  1052. /********************************************************/
  1053. /* Discard unmatched mouse button up event */
  1054. /********************************************************/
  1055. TRC_NRM((TB, "discard mouse up event"));
  1056. rc = FALSE;
  1057. DC_QUIT;
  1058. }
  1059. // Update the key state array.
  1060. IM_SET_KEY_UP(imKeyStates[IM_SC_XBUTTON2]);
  1061. }
  1062. break;
  1063. default:
  1064. {
  1065. /********************************************************/
  1066. /* As for standard button clicks, if we don't recognise */
  1067. /* this then don't play it back. Capabilities should */
  1068. /* protect us from getting here. */
  1069. /********************************************************/
  1070. TRC_ERR((TB, "Unrecognized mouseX flags (%04X)",
  1071. pInputEvent->pointerFlags));
  1072. WDW_LogAndDisconnect(m_pTSWd, TRUE,
  1073. Log_RDP_InvalidInputPDUMouse,
  1074. (PBYTE)pInputEvent,
  1075. sizeof(PTS_INPUT_EVENT));
  1076. rc = FALSE;
  1077. DC_QUIT;
  1078. }
  1079. }
  1080. }
  1081. }
  1082. /************************************************************************/
  1083. /* Store the injection time for guessing at SetCursorPos calls. */
  1084. /************************************************************************/
  1085. COM_GETTICKCOUNT(imLastLowLevelMouseEventTime);
  1086. /************************************************************************/
  1087. /* Store the mouse position before conversion. */
  1088. /************************************************************************/
  1089. imLastKnownMousePos.x = pMouseData->LastX;
  1090. imLastKnownMousePos.y = pMouseData->LastY;
  1091. /************************************************************************/
  1092. /* Scale the logical screen co-ordinates to the full 16-bit */
  1093. /* range (0..65535). */
  1094. /************************************************************************/
  1095. TRC_DBG((TB, "Scale absolute mouse move"));
  1096. pMouseData->LastX = IM_MOUSEPOS_LOG_TO_OS_ABS(pMouseData->LastX,
  1097. m_desktopWidth);
  1098. pMouseData->LastY = IM_MOUSEPOS_LOG_TO_OS_ABS(pMouseData->LastY,
  1099. m_desktopHeight);
  1100. DC_EXIT_POINT:
  1101. DC_END_FN();
  1102. return rc;
  1103. }
  1104. /****************************************************************************/
  1105. // IMConvertFastPathKeyboardToEvent
  1106. //
  1107. // Converts the 2 or 3 byte representation of a fast-path keyboard event into
  1108. // a kernel keyboard event, taking care to save the key states. Byte 0 is
  1109. // the event code and flags byte, byte 1 is the scancode.
  1110. // In the case where this is a VK_PACKET input bytes 1 and 2 are the unicode
  1111. // character (contained in the scancode).
  1112. //
  1113. // This handles input of the form
  1114. // TS_INPUT_FASTPATH_EVENT_KEYBOARD and
  1115. // TS_INPUT_FASTPATH_EVENT_VKPACKET
  1116. //
  1117. /****************************************************************************/
  1118. BOOL __fastcall SHCLASS IMConvertFastPathKeyboardToEvent(
  1119. BYTE *pData,
  1120. KEYBOARD_INPUT_DATA *pKbdData)
  1121. {
  1122. BOOL rc = TRUE;
  1123. unsigned code = 0;
  1124. BOOL fHandlingVKPacket = FALSE;
  1125. DC_BEGIN_FN("IMConvertFastPathKeyboardToEvent");
  1126. // Set up basic params.
  1127. // We define the fastpath keyboard flags to be the same as the KEY_BREAK,
  1128. // KEY_E0, and KEY_E1 to allow us to simply copy the low-order 3 bits of
  1129. // the first byte into the KbdData.Flags field.
  1130. pKbdData->Flags = *pData & 0x07;
  1131. pKbdData->UnitId = 0;
  1132. if (TS_INPUT_FASTPATH_EVENT_KEYBOARD ==
  1133. (*pData & TS_INPUT_FASTPATH_EVENT_MASK))
  1134. {
  1135. code = pKbdData->MakeCode = pData[1];
  1136. }
  1137. else if (TS_INPUT_FASTPATH_EVENT_VKPACKET ==
  1138. (*pData & TS_INPUT_FASTPATH_EVENT_MASK))
  1139. {
  1140. fHandlingVKPacket = TRUE;
  1141. // Scancode is a 2 byte unicode char in this case
  1142. memcpy(&code, &pData[1], 2);
  1143. pKbdData->MakeCode = (USHORT)code;
  1144. pKbdData->Flags |= KEY_TERMSRV_VKPACKET;
  1145. }
  1146. pKbdData->ExtraInformation = 0;
  1147. if (m_pTSWd->StackClass == Stack_Shadow ) {
  1148. // this event is coming from a shadow client: tell the target to sync
  1149. pKbdData->Flags |= KEY_TERMSRV_SHADOW;
  1150. }
  1151. if (fHandlingVKPacket)
  1152. {
  1153. TRC_NRM((TB,"IH VKpkt Unicode val: 0x%x flags:0x%x\n",
  1154. code, pKbdData->Flags));
  1155. //No further processing
  1156. DC_QUIT;
  1157. }
  1158. // Special case control/ALT keys: distinguish L & R keys in the keystate
  1159. // array.
  1160. if (pData[0] & TS_INPUT_FASTPATH_KBD_EXTENDED) {
  1161. if (pData[1] == IM_SC_LCONTROL)
  1162. code = IM_SC_RCONTROL;
  1163. else if (pData[1] == IM_SC_LALT)
  1164. code = IM_SC_RALT;
  1165. }
  1166. // Check for the RELEASE flag, which is TRUE for a key release, FALSE
  1167. // for keypresses and repeats.
  1168. if (pData[0] & TS_INPUT_FASTPATH_KBD_RELEASE) {
  1169. #ifdef DELETE_UNMATCHED_KEYUPS
  1170. // Check whether this is an unmatched key up event (rather than
  1171. // a key event that's not been matched up!)
  1172. if (IM_KEY_STATE_IS_UP(imKeyStates[pData[1]])) {
  1173. // Discard unmatched key up event
  1174. TRC_NRM((TB, "discard up event %04hX", pData[1]));
  1175. rc = FALSE;
  1176. DC_QUIT;
  1177. }
  1178. #endif
  1179. // Update the key state array.
  1180. TRC_DBG((TB,"set sc %u state UP (%#x)", code, imKeyStates[code]));
  1181. IM_SET_KEY_UP(imKeyStates[code]);
  1182. }
  1183. else {
  1184. // Update the key state array.
  1185. TRC_DBG((TB,"set sc %u state DOWN (%#x)", code, imKeyStates[code]));
  1186. IM_SET_KEY_DOWN(imKeyStates[code]);
  1187. }
  1188. // Compile-time assertions to make sure the flags are okay.
  1189. #if (TS_INPUT_FASTPATH_KBD_RELEASE != KEY_BREAK)
  1190. #error TS RELEASE definition doesn't agree with driver flag
  1191. #endif
  1192. #if (TS_INPUT_FASTPATH_KBD_EXTENDED != KEY_E0)
  1193. #error TS EXTENDED definition doesn't agree with driver flag
  1194. #endif
  1195. #if (TS_INPUT_FASTPATH_KBD_EXTENDED1 != KEY_E1)
  1196. #error TS EXTENDED1 definition doesn't agree with driver flag
  1197. #endif
  1198. DC_EXIT_POINT:
  1199. DC_END_FN();
  1200. return rc;
  1201. }
  1202. /****************************************************************************/
  1203. // IMDoSync
  1204. //
  1205. // Encapsulates the actions for a sync for common use by regular and
  1206. // fastpath input.
  1207. /****************************************************************************/
  1208. NTSTATUS RDPCALL SHCLASS IMDoSync(unsigned ToggleFlags)
  1209. {
  1210. NTSTATUS Status;
  1211. KEYBOARD_INPUT_DATA KbdData;
  1212. DC_BEGIN_FN("IMDoSync");
  1213. // We just need to reset the key state.
  1214. IMResetKeyStateArray();
  1215. // Send special "reset keylight state" injection to win32k.
  1216. // The particular states to set are contained in ToggleFlags.
  1217. KbdData.MakeCode = 0xFF;
  1218. #ifdef _HYDRA_
  1219. KbdData.Flags = KEY_TERMSRV_SET_LED;
  1220. #else
  1221. KbdData.Flags = KEY_CITRIX_SET_LED;
  1222. #endif
  1223. if (m_pTSWd->StackClass == Stack_Shadow ) {
  1224. // this event is coming from a shadow client: tell the target to sync
  1225. KbdData.Flags |= KEY_TERMSRV_SHADOW;
  1226. }
  1227. KbdData.ExtraInformation = ToggleFlags;
  1228. TRC_NRM((TB, "Injecting toggle keys sync event %lx", ToggleFlags));
  1229. Status = IcaChannelInput(m_pTSWd->pContext, Channel_Keyboard, 0, NULL,
  1230. (unsigned char *)&KbdData, sizeof(KEYBOARD_INPUT_DATA));
  1231. TRC_DBG((TB, "Return from toggles input injection %lu",
  1232. Status));
  1233. DC_END_FN();
  1234. return Status;
  1235. }
  1236. /****************************************************************************/
  1237. /* FUNCTION: IMResetKeyStateArray */
  1238. /* */
  1239. /* Called to reset the keystate array */
  1240. /****************************************************************************/
  1241. void RDPCALL SHCLASS IMResetKeyStateArray()
  1242. {
  1243. BOOL rc = TRUE;
  1244. unsigned i;
  1245. NTSTATUS Status;
  1246. DC_BEGIN_FN("IMResetKeyStateArray");
  1247. /************************************************************************/
  1248. /* This function is called to reset all keys to a known state */
  1249. /* (up) before resetting the keys with new states. */
  1250. /************************************************************************/
  1251. /************************************************************************/
  1252. /* Loop through all keys looking for any that are not in a neutral */
  1253. /* state. In this case any key that is in a KEY_DOWN state is not */
  1254. /* considered neutral. */
  1255. /************************************************************************/
  1256. for (i = 0; i < IM_KEY_STATE_SIZE; i++)
  1257. {
  1258. if (IM_KEY_STATE_IS_DOWN(imKeyStates[i])) {
  1259. TRC_NRM((TB, "Key is down %u", i));
  1260. /****************************************************************/
  1261. /* Handle the mouse buttons first */
  1262. /****************************************************************/
  1263. if ((i == IM_SC_LBUTTON) ||
  1264. (i == IM_SC_RBUTTON) ||
  1265. (i == IM_SC_MBUTTON) ||
  1266. (i == IM_SC_XBUTTON1) ||
  1267. (i == IM_SC_XBUTTON2))
  1268. {
  1269. MOUSE_INPUT_DATA MouseData;
  1270. /************************************************************/
  1271. /* Generate a mouse event with the particular button type */
  1272. /* and a relative mouse move of zero. */
  1273. /************************************************************/
  1274. memset(&MouseData, 0, sizeof(MOUSE_INPUT_DATA));
  1275. if (i == IM_SC_LBUTTON)
  1276. {
  1277. MouseData.ButtonFlags = MOUSE_LEFT_BUTTON_UP;
  1278. }
  1279. else if (i == IM_SC_RBUTTON)
  1280. {
  1281. MouseData.ButtonFlags = MOUSE_RIGHT_BUTTON_UP;
  1282. }
  1283. else if (i == IM_SC_MBUTTON)
  1284. {
  1285. MouseData.ButtonFlags = MOUSE_MIDDLE_BUTTON_UP;
  1286. }
  1287. else if (i == IM_SC_XBUTTON1)
  1288. {
  1289. MouseData.ButtonFlags = MOUSE_BUTTON_4_UP;
  1290. }
  1291. else /* IM_SC_XBUTTON2 */
  1292. {
  1293. MouseData.ButtonFlags = MOUSE_BUTTON_5_UP;
  1294. }
  1295. /************************************************************/
  1296. /* Store the injection time for guessing at SetCursorPos */
  1297. /* calls. */
  1298. /************************************************************/
  1299. COM_GETTICKCOUNT(imLastLowLevelMouseEventTime);
  1300. TRC_NRM((TB, "Inject mouse event: x(%ld) y(%ld) flags(%#hx)"
  1301. "buttonFlags(%#hx)",
  1302. MouseData.LastX,
  1303. MouseData.LastY,
  1304. MouseData.Flags,
  1305. MouseData.ButtonFlags));
  1306. Status = IcaChannelInput(m_pTSWd->pContext,
  1307. Channel_Mouse,
  1308. 0,
  1309. NULL,
  1310. (unsigned char *)&MouseData,
  1311. sizeof(MOUSE_INPUT_DATA));
  1312. TRC_DBG((TB, "Return from mouse input injection %lu",
  1313. Status));
  1314. }
  1315. else {
  1316. KEYBOARD_INPUT_DATA KbdData;
  1317. /************************************************************/
  1318. /* Generate a keyboard key up event */
  1319. /************************************************************/
  1320. KbdData.UnitId = 0;
  1321. if (i == IM_SC_RCONTROL)
  1322. {
  1323. KbdData.Flags = KEY_BREAK | KEY_E0;
  1324. KbdData.MakeCode = IM_SC_LCONTROL;
  1325. }
  1326. else if (i == IM_SC_RALT)
  1327. {
  1328. KbdData.Flags = KEY_BREAK | KEY_E0;
  1329. KbdData.MakeCode = IM_SC_LALT;
  1330. }
  1331. else
  1332. {
  1333. KbdData.Flags = KEY_BREAK;
  1334. KbdData.MakeCode = (unsigned short)i;
  1335. }
  1336. KbdData.Reserved = 0;
  1337. KbdData.ExtraInformation = 0;
  1338. TRC_NRM((TB, "Inject keybd event: make code (%u) flags(%#x)",
  1339. KbdData.MakeCode, KbdData.Flags));
  1340. Status = IcaChannelInput(m_pTSWd->pContext,
  1341. Channel_Keyboard,
  1342. 0,
  1343. NULL,
  1344. (unsigned char *)&KbdData,
  1345. sizeof(KEYBOARD_INPUT_DATA));
  1346. TRC_DBG((TB, "Return from keyboard input injection %lu",
  1347. Status));
  1348. }
  1349. }
  1350. }
  1351. // Set all keys up.
  1352. memset((PVOID)imKeyStates, 0, IM_KEY_STATE_SIZE);
  1353. DC_END_FN();
  1354. }