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.

752 lines
21 KiB

  1. /* File: cloop.c (created 12/27/93, JKH)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 15 $
  7. * $Date: 7/12/02 8:06a $
  8. */
  9. #include <windows.h>
  10. #pragma hdrstop
  11. #include "features.h"
  12. // #define DEBUGSTR
  13. #include "stdtyp.h"
  14. #include "session.h"
  15. #include "globals.h"
  16. #include "timers.h"
  17. #include "com.h"
  18. #include "xfer_msc.h"
  19. #include <emu\emu.h>
  20. #if defined(CHARACTER_TRANSLATION)
  21. #include "translat.hh"
  22. #endif
  23. #include "cloop.h"
  24. #include "cloop.hh"
  25. #include "htchar.h"
  26. #include "assert.h"
  27. #include "chars.h"
  28. #if defined(INCL_VTUTF8)
  29. BOOL DoUTF8 = FALSE;
  30. #endif
  31. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  32. * FUNCTION: CLoop
  33. *
  34. * DESCRIPTION:
  35. * This function comprises the 'engine' of the engine thread. Its action
  36. * is controlled by a series of control bits that are set and cleared
  37. * by calls to CLoopRcvControl and CLoopControl
  38. *
  39. * ARGUMENTS:
  40. * pstCLoop -- Handle returned from CLoopCreateHandle
  41. *
  42. * RETURNS:
  43. * nothing
  44. */
  45. DWORD WINAPI CLoop(LPVOID pvData)
  46. {
  47. ST_CLOOP * const pstCLoop = (ST_CLOOP *)pvData;
  48. HCOM hCom;
  49. int nRcvCount;
  50. TCHAR chData = (TCHAR)0;
  51. ECHAR echData = (ECHAR)0;
  52. HSESSION hSession;
  53. HEMU hEmu;
  54. KEY_T keyOut;
  55. ST_FCHAIN *pstCurrent;
  56. CHAINFUNC pfChainFunc;
  57. int fValidChar;
  58. #if defined(CHARACTER_TRANSLATION)
  59. HHTRANSLATE hTrans = NULL;
  60. #endif
  61. int nCount;
  62. int nIndx;
  63. CHAR chBuffer[32]; /* Yes, it is supposed to be a CHAR */
  64. int mc;
  65. PVOID pvUserData;
  66. DWORD dwEventCount;
  67. HANDLE *pvEvents;
  68. DBGOUT_NORMAL("In CLoop(%lX)\r\n", pstCLoop,0,0,0,0);
  69. assert(pstCLoop);
  70. EnterCriticalSection(&pstCLoop->csect);
  71. hSession = pstCLoop->hSession;
  72. hCom = pstCLoop->hCom;
  73. hEmu = pstCLoop->hEmu;
  74. #if defined(CHARACTER_TRANSLATION)
  75. hTrans = (HHTRANSLATE)sessQueryTranslateHdl(pstCLoop->hSession);
  76. #endif
  77. assert(hSession);
  78. assert(hCom);
  79. assert(hEmu);
  80. DBGOUT_NORMAL("CLoop got critical section\r\n", 0,0,0,0,0);
  81. while (!bittest(pstCLoop->afControl, CLOOP_TERMINATE))
  82. {
  83. DWORD dwRet;
  84. // Normally, this CLoop function owns the critical section
  85. // controlling the CLoop data. We give it up at least once each
  86. // time through the loop to give other threads a change to call
  87. // control functions.
  88. dwEventCount = DIM(pstCLoop->ahEvents);
  89. pvEvents = pstCLoop->ahEvents;
  90. LeaveCriticalSection(&pstCLoop->csect);
  91. // Block if there is nothing to do
  92. DBGOUT_YIELD("W+ ", 0,0,0,0,0);
  93. dwRet = WaitForMultipleObjects(dwEventCount, pvEvents, FALSE, INFINITE);
  94. DBGOUT_YIELD("W(0x%x)", dwRet,0,0,0,0);
  95. EnterCriticalSection(&pstCLoop->csect);
  96. DBGOUT_YIELD(": ", 0,0,0,0,0);
  97. // See if a transfer has been initiated
  98. if (bittest(pstCLoop->afControl, CLOOP_TRANSFER_READY))
  99. {
  100. DBGOUT_NORMAL("CLoop calling xfer\r\n", 0,0,0,0,0);
  101. LeaveCriticalSection(&pstCLoop->csect);
  102. xfrDoTransfer(sessQueryXferHdl(hSession));
  103. DBGOUT_NORMAL("CLoop back from xfer\r\n", 0,0,0,0,0);
  104. EnterCriticalSection(&pstCLoop->csect);
  105. CLoopControl((HCLOOP)pstCLoop, CLOOP_CLEAR, CLOOP_TRANSFER_READY);
  106. }
  107. // If there is input waiting and we are not blocked from receiving
  108. if (!pstCLoop->afRcvBlocked)
  109. {
  110. // Give priority to receiving over sending since normally
  111. // we will receive more data than we send (CR becomes CR LF)
  112. // and since we have more control over the send rate
  113. // TODO: implement priority setting by adjusting rcv count
  114. for (nRcvCount = 10; nRcvCount--; )
  115. {
  116. fValidChar = FALSE;
  117. if (mComRcvChar(hCom, &chData))
  118. {
  119. DBGOUT_NORMAL("Recieved Char\r\n", 0,0,0,0,0);
  120. // Check for force to 7-bit ASCII
  121. if (pstCLoop->stWorkSettings.fASCII7)
  122. {
  123. chData &= 0x7F;
  124. }
  125. nCount = 0;
  126. #if defined(CHARACTER_TRANSLATION)
  127. if( nCount >= 0 && hTrans != NULL )
  128. {
  129. LeaveCriticalSection(&pstCLoop->csect);
  130. hTrans->pfnIn(hTrans->pDllHandle,
  131. chData,
  132. &nCount,
  133. sizeof(chBuffer),
  134. chBuffer);
  135. EnterCriticalSection(&pstCLoop->csect);
  136. }
  137. #else // defined(CHARACTER_TRANSLATION)
  138. if( nCount >= 0 )
  139. {
  140. chBuffer[0] = chData;
  141. nCount = 1;
  142. }
  143. #endif // defined(CHARACTER_TRANSLATION)
  144. for (nIndx = 0; nIndx < nCount; nIndx++)
  145. {
  146. if (pstCLoop->fDoMBCS)
  147. {
  148. if (pstCLoop->cLeadByte != 0)
  149. {
  150. chData = 0;
  151. echData = chBuffer[nIndx] & 0xFF;
  152. // There must be a macro for this somewhere
  153. echData |= (ECHAR)(pstCLoop->cLeadByte << 8);
  154. pstCLoop->cLeadByte = 0;
  155. fValidChar = TRUE;
  156. }
  157. else
  158. {
  159. if (IsDBCSLeadByte(chBuffer[nIndx]))
  160. {
  161. pstCLoop->cLeadByte = chBuffer[nIndx];
  162. }
  163. else
  164. {
  165. echData = chBuffer[nIndx] & 0xFF;
  166. pstCLoop->cLeadByte = 0;
  167. fValidChar = TRUE;
  168. }
  169. }
  170. } // if (fDoMBCS)
  171. else
  172. {
  173. echData = ETEXT(chBuffer[nIndx]);
  174. fValidChar = TRUE;
  175. } // else (fDoMBCS)
  176. if (fValidChar)
  177. {
  178. // Character translation/stripping
  179. //*if ((chData = pstCLoop->panFltrIn[chData]) == -1)
  180. //* continue;
  181. // walk remote input function chain if it exists
  182. if (pstCLoop->fRmtChain)
  183. {
  184. pstCLoop->pstRmtChainNext = pstCLoop->pstRmtChain;
  185. while (pstCLoop->pstRmtChainNext)
  186. {
  187. pstCurrent = pstCLoop->pstRmtChainNext;
  188. pstCLoop->pstRmtChainNext = pstCurrent->pstNext;
  189. pfChainFunc = pstCurrent->pfFunc;
  190. pvUserData = pstCurrent->pvUserData;
  191. LeaveCriticalSection(&pstCLoop->csect);
  192. mc = (*pfChainFunc)(chData, pvUserData);
  193. EnterCriticalSection(&pstCLoop->csect);
  194. if ( mc == CLOOP_DISCARD )
  195. break;
  196. }
  197. }
  198. if ( mc != CLOOP_DISCARD )
  199. {
  200. pstCLoop->fDataReceived = TRUE;
  201. CLoopCharIn(pstCLoop, echData);
  202. }
  203. if (pstCLoop->afRcvBlocked)
  204. {
  205. /*
  206. * This is necessary because a script may be
  207. * checking input and then stopping after it
  208. * finds what it is looking for. If the loop
  209. * count is still possitive, the remaining
  210. * characters will "slip thru" before this
  211. * loop terminates.
  212. * This won't break in any obvious way, so be
  213. * careful to preserve this feature if this
  214. * loop is rewritten.
  215. *
  216. * TODO: when scripts are added, make sure this
  217. * works correctly with character translation.
  218. */
  219. // Receiving has been blocked,
  220. // make sure any received
  221. // data gets displayed.
  222. LeaveCriticalSection(&pstCLoop->csect);
  223. emuComDone(hEmu);
  224. EnterCriticalSection(&pstCLoop->csect);
  225. break;
  226. }
  227. }
  228. }
  229. //
  230. // Clear the temporary input character buffer.
  231. // as the buffer has been copied into echData.
  232. // REV: 03/06/2001
  233. //
  234. memset(chBuffer, 0, sizeof(chBuffer));
  235. }
  236. else
  237. {
  238. CLoopRcvControl((HCLOOP)pstCLoop, CLOOP_SUSPEND,
  239. CLOOP_RB_NODATA);
  240. if (pstCLoop->fDataReceived)
  241. {
  242. // Notify emulator that there is a pause in the
  243. // stream of received data
  244. LeaveCriticalSection(&pstCLoop->csect);
  245. emuComDone(hEmu);
  246. EnterCriticalSection(&pstCLoop->csect);
  247. // If we had a delay timer already running, kill it
  248. if (pstCLoop->htimerRcvDelay)
  249. {
  250. TimerDestroy(&pstCLoop->htimerRcvDelay);
  251. }
  252. // The stream of incoming data has stopped, set a
  253. // timer so we can tell if it stops long enough to
  254. // do cursor tracking etc.
  255. if (TimerCreate(pstCLoop->hSession,
  256. &pstCLoop->htimerRcvDelay,
  257. CLOOP_TRACKING_DELAY,
  258. /* pstCLoop->pfRcvDelay, */
  259. CLoopRcvDelayProc,
  260. (void *)pstCLoop) != TIMER_OK)
  261. {
  262. pstCLoop->htimerRcvDelay = (HTIMER)0;
  263. assert(FALSE);
  264. }
  265. pstCLoop->fDataReceived = FALSE;
  266. }
  267. }
  268. }
  269. }
  270. // Check for outgoing data.
  271. if (!pstCLoop->afSndBlocked)
  272. {
  273. // (Taken verbatim from HA5G, by JMH 03-22-96):
  274. // This change was added to fix a deadlock problem. While sending
  275. // and receiving data simultaneously at high speed, it was
  276. // possible for us to issue a handshake stop at the same time
  277. // we would receive one from the host. Our code would wait
  278. // in the ComSendBufr call and stop processing. Because of this,
  279. // we would not be processing incoming data so we would never
  280. // clear the handshake stop we had issued to the other end. If
  281. // the other end was caught in the same state -- deadlock.
  282. // This test slows our text transmission down. We should
  283. // redesgin our transmission model to fix this. jkh, 1/19/95
  284. // if (CLoopGetNextOutput(pstCLoop, &keyOut)) DEADWOOD:jmh 03-22-96
  285. if (ComSndBufrBusy(hCom) == COM_BUSY)
  286. {
  287. //
  288. // Yield to other threads, but don't wait too long
  289. // to cause undo delay of data transfer. Time was
  290. // changed from 10 milliseconds to 0 millisecond
  291. // which will yield to other threads (so the CPU
  292. // doesn't peg), but will not cause undo delay in
  293. // the data transmission. This bug was reported
  294. // by customers after HTPE3 (and by Motorola to MS)
  295. // when sending data via text send. REV: 06/13/2001.
  296. //
  297. #if defined(DEADWOOD)
  298. Sleep(0); // jkh 04/29/1998 don't peg CPU
  299. #else // defined(DEADWOOD)
  300. //
  301. // We should wait for the COM/TAPI driver to write the
  302. // data before we continue. For now we will leave the
  303. // critical section so other threads can continue,
  304. // and loop back around. TODO:REV 7/11/2002
  305. //
  306. LeaveCriticalSection(&pstCLoop->csect);
  307. //ComSndBufrWait(hCom, 100);
  308. //WaitForSingleObject(hCom->hSndReady, 1000);
  309. EnterCriticalSection(&pstCLoop->csect);
  310. #endif // defined(DEADWOOD)
  311. }
  312. else if (CLoopGetNextOutput(pstCLoop, &keyOut))
  313. {
  314. // Check for tab expansion
  315. //DbgOutStr("C", 0,0,0,0,0);
  316. if (keyOut == TEXT('\t') &&
  317. pstCLoop->stWorkSettings.fExpandTabsOut &&
  318. pstCLoop->stWorkSettings.nTabSizeOut)
  319. {
  320. //* int i;
  321. //* POINT pt;
  322. //* mEmuGetCursorPos(
  323. //* mGetEmulatorHdl(pstCLoop->hSession),
  324. //* &pt);
  325. //* i = pstCLoop->stWorkSettings.usTabSizeOut -
  326. //* ((pt.x + 1) % pstCLoop->stWorkSettings.usTabSizeOut);
  327. //* while (i-- > 0)
  328. //* (VOID)mEmuKbdIn(hEmu, (KEY_T)TEXT(' '), FALSE);
  329. }
  330. else
  331. {
  332. //jmh 03-22-96 We need to unlock cloop around calls to
  333. // emuKbdIn and emuDataIn, because they call the com
  334. // thread, which may be stuck waiting to access cloop.
  335. //
  336. LeaveCriticalSection(&pstCLoop->csect);
  337. emuKbdIn(hEmu, keyOut, FALSE);
  338. EnterCriticalSection(&pstCLoop->csect);
  339. }
  340. //
  341. // The keyOut shouuld no longer be (VK_RETURN | VIRTUAL_KEY)
  342. // but if it is, then treat it like '\r'. REV: 5/16/2002
  343. //
  344. if (keyOut == TEXT('\r') ||
  345. keyOut == (VK_RETURN | VIRTUAL_KEY))
  346. {
  347. if (pstCLoop->stWorkSettings.fLineWait)
  348. {
  349. CLoopSndControl((HCLOOP)pstCLoop, CLOOP_SUSPEND,
  350. CLOOP_SB_LINEWAIT);
  351. }
  352. if (pstCLoop->stWorkSettings.fSendCRLF)
  353. {
  354. //DEADWOOD:jkh 8/18/97
  355. // Can't use CLoopSend here because the '\n' is placed
  356. // behind any other codes waiting in the output queue.
  357. // This caused all LF codes in a text file send to be
  358. // sent AFTER the whole file, rather than after each CR
  359. // CLoopSend((HCLOOP) pstCLoop, TEXT("\n"), 1, 0);
  360. LeaveCriticalSection(&pstCLoop->csect);
  361. emuKbdIn(hEmu, (KEY_T)'\n', FALSE);
  362. EnterCriticalSection(&pstCLoop->csect);
  363. #if 0 //DEADWOOD: RDE 20AUG98 MPT Fixed a local echo problem down in
  364. // CloopCharIn which then caused an extra linefeed
  365. // to be displayed on the local terminal.
  366. if (pstCLoop->stWorkSettings.fLocalEcho &&
  367. !pstCLoop->fSuppressDsp)
  368. {
  369. //jmh 03-22-96 We need to unlock cloop around calls to
  370. // emuKbdIn and emuDataIn, because they call the com
  371. // thread, which may be stuck waiting to access cloop.
  372. //
  373. LeaveCriticalSection(&pstCLoop->csect);
  374. emuDataIn(hEmu, TEXT('\n'));
  375. emuComDone(hEmu);
  376. EnterCriticalSection(&pstCLoop->csect);
  377. }
  378. #endif
  379. }
  380. if (pstCLoop->stWorkSettings.nLineDelay)
  381. {
  382. if (TimerCreate( pstCLoop->hSession,
  383. &pstCLoop->htimerCharDelay,
  384. pstCLoop->stWorkSettings.nLineDelay,
  385. pstCLoop->pfCharDelay,
  386. (void *)pstCLoop) == TIMER_OK)
  387. {
  388. CLoopSndControl((HCLOOP)pstCLoop, CLOOP_SUSPEND,
  389. CLOOP_SB_DELAY);
  390. }
  391. }
  392. }
  393. else
  394. {
  395. if (pstCLoop->stWorkSettings.nCharDelay)
  396. {
  397. if (TimerCreate(pstCLoop->hSession,
  398. &pstCLoop->htimerCharDelay,
  399. pstCLoop->stWorkSettings.nCharDelay,
  400. pstCLoop->pfCharDelay,
  401. (void *)pstCLoop) == TIMER_OK)
  402. {
  403. CLoopSndControl((HCLOOP)pstCLoop, CLOOP_SUSPEND,
  404. CLOOP_SB_DELAY);
  405. }
  406. }
  407. }
  408. //* if (pstCLoop->lpLearn)
  409. //* {
  410. //* CLearnSendChar(pstCLoop->lpLearn, (METACHAR)keyOut);
  411. //* }
  412. }
  413. }
  414. // Make sure any buffered output waiting gets sent.
  415. //* ComSendPush(pstCLoop->hCom);
  416. }
  417. DBGOUT_NORMAL("Leaving CLoop(%lX)\r\n", pstCLoop,0,0,0,0);
  418. LeaveCriticalSection(&pstCLoop->csect);
  419. return 0;
  420. }
  421. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  422. * FUNCTION: CLoopCharIn
  423. *
  424. * DESCRIPTION:
  425. * Does rec eive processing for characters received from the remote system
  426. *
  427. * ARGUMENTS:
  428. * pstCLoop -- Handle returned from CLoopCreateHandle
  429. * mc -- Character to be processed.
  430. *
  431. * RETURNS:
  432. * nothing
  433. */
  434. void CLoopCharIn(ST_CLOOP *pstCLoop, ECHAR chIn)
  435. {
  436. // Check for echoplex
  437. if (pstCLoop->stWorkSettings.fEchoplex)
  438. {
  439. //mpt:1-27-98 converting echars to tchar was converting
  440. // the character to a single byte. Consequently,
  441. // echoing of a dbcs character was only echoing
  442. // the second byte of the character.
  443. if ( (pstCLoop->fDoMBCS) && (chIn > 255) )
  444. {
  445. //send first byte
  446. ComSendCharNow(pstCLoop->hCom, (TCHAR) (chIn >> 8));
  447. //send second byte
  448. ComSendCharNow(pstCLoop->hCom, (TCHAR) (chIn & 0xFF));
  449. }
  450. else
  451. {
  452. ComSendCharNow(pstCLoop->hCom, (TCHAR) chIn);
  453. }
  454. //
  455. // See if we need to add a line feed to line end. REV: 5/21/2002
  456. //
  457. if ((chIn == ETEXT('\r') || chIn == (VK_RETURN | VIRTUAL_KEY)) &&
  458. pstCLoop->stWorkSettings.fAddLF)
  459. {
  460. ComSendCharNow(pstCLoop->hCom, TEXT('\n'));
  461. }
  462. }
  463. if (pstCLoop->stWorkSettings.fLineWait &&
  464. chIn == pstCLoop->stWorkSettings.chWaitChar)
  465. CLoopSndControl((HCLOOP)pstCLoop, CLOOP_RESUME, CLOOP_SB_LINEWAIT);
  466. // Display character in normal or image mode
  467. if (!pstCLoop->fSuppressDsp)
  468. {
  469. // DbgOutStr("Dsp %02X (%c)\r\n", chIn, chIn, 0,0,0);
  470. emuDataIn(pstCLoop->hEmu, chIn);
  471. //
  472. // See if we need to add a line feed to line end. REV: 5/21/2002
  473. //
  474. if ((chIn == ETEXT('\r') || chIn == (VK_RETURN | VIRTUAL_KEY)) &&
  475. pstCLoop->stWorkSettings.fAddLF)
  476. {
  477. emuDataIn(pstCLoop->hEmu, ETEXT('\n'));
  478. }
  479. }
  480. }
  481. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  482. * FUNCTION:
  483. * CLoopCharOut
  484. *
  485. * DESCRIPTION:
  486. * Called to send a character out the port with processing by the CLoop
  487. * routines. Note that this differs from CLoopSend.
  488. *
  489. * ARGUMENTS:
  490. *
  491. *
  492. * RETURNS:
  493. *
  494. */
  495. void CLoopCharOut(HCLOOP hCLoop, TCHAR chOut)
  496. {
  497. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  498. int fCharValid = FALSE;
  499. ECHAR echOut = (ECHAR)0;
  500. #if defined(CHARACTER_TRANSLATION)
  501. HHTRANSLATE hTrans = NULL;
  502. int nCount = 0;
  503. int nIndx;
  504. CHAR chBuffer[32]; /* Yes, it is supposed to be a CHAR */
  505. hTrans = (HHTRANSLATE)sessQueryTranslateHdl(pstCLoop->hSession);
  506. if (hTrans)
  507. {
  508. (*hTrans->pfnOut)(hTrans->pDllHandle,
  509. chOut,
  510. &nCount,
  511. sizeof(chBuffer)/sizeof(TCHAR),
  512. chBuffer);
  513. }
  514. else
  515. {
  516. StrCharCopyN(chBuffer, &chOut, sizeof(chBuffer)/sizeof(TCHAR));
  517. }
  518. for (nIndx = 0; nIndx < nCount; nIndx += 1)
  519. {
  520. chOut = chBuffer[nIndx];
  521. #endif //CHARACTER_TRANSLATION
  522. ComSendCharNow(pstCLoop->hCom, chOut);
  523. if (pstCLoop->stWorkSettings.fLocalEcho &&
  524. !pstCLoop->fSuppressDsp)
  525. {
  526. if (pstCLoop->fDoMBCS)
  527. {
  528. if (pstCLoop->cLocalEchoLeadByte)
  529. {
  530. echOut = chOut & 0xFF;
  531. echOut |= (ECHAR)(pstCLoop->cLocalEchoLeadByte << 8);
  532. pstCLoop->cLocalEchoLeadByte = 0;
  533. fCharValid = TRUE;
  534. }
  535. else
  536. {
  537. if (IsDBCSLeadByte(chOut))
  538. {
  539. pstCLoop->cLocalEchoLeadByte = chOut;
  540. }
  541. else
  542. {
  543. echOut = chOut & 0xFF;
  544. fCharValid = TRUE;
  545. }
  546. }
  547. }
  548. else
  549. {
  550. echOut = (ECHAR)chOut;
  551. fCharValid = TRUE;
  552. }
  553. if (fCharValid)
  554. {
  555. emuDataIn(pstCLoop->hEmu, echOut);
  556. emuComDone(pstCLoop->hEmu);
  557. }
  558. }
  559. #if defined(CHARACTER_TRANSLATION)
  560. }
  561. #endif
  562. return;
  563. }
  564. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  565. * FUNCTION:
  566. * CLoopBufrOut
  567. *
  568. * DESCRIPTION:
  569. * Called to send a buffer of characters out the port with processing by the CLoop
  570. * routines. Note that this differs from CLoopSend.
  571. *
  572. * ARGUMENTS:
  573. *
  574. *
  575. * RETURNS:
  576. * void
  577. *
  578. */
  579. void CLoopBufrOut(HCLOOP hCLoop, TCHAR *pchOut, int nLen)
  580. {
  581. ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
  582. int fCharValid = FALSE;
  583. while (nLen--)
  584. {
  585. ComSendChar(pstCLoop->hCom, *pchOut); // place chars in comsend buffer
  586. if (pstCLoop->stWorkSettings.fLocalEcho &&
  587. !pstCLoop->fSuppressDsp)
  588. {
  589. if (pstCLoop->fDoMBCS)
  590. {
  591. if (pstCLoop->cLocalEchoLeadByte != 0)
  592. {
  593. *pchOut |= (TCHAR)(pstCLoop->cLocalEchoLeadByte << 8);
  594. pstCLoop->cLocalEchoLeadByte = 0;
  595. fCharValid = TRUE;
  596. }
  597. else
  598. {
  599. if (IsDBCSLeadByte(*pchOut))
  600. {
  601. pstCLoop->cLocalEchoLeadByte = *pchOut;
  602. }
  603. else
  604. {
  605. fCharValid = TRUE;
  606. }
  607. }
  608. }
  609. else
  610. {
  611. fCharValid = TRUE;
  612. }
  613. if (fCharValid)
  614. {
  615. emuDataIn(pstCLoop->hEmu, *pchOut);
  616. emuComDone(pstCLoop->hEmu);
  617. }
  618. }
  619. ++pchOut;
  620. }
  621. ComSendPush(pstCLoop->hCom);
  622. }
  623. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  624. * FUNCTION: CLoopRcvDelayProc
  625. *
  626. * DESCRIPTION:
  627. *
  628. *
  629. * ARGUMENTS:
  630. *
  631. *
  632. * RETURNS:
  633. *
  634. */
  635. /* ARGSUSED */
  636. void CALLBACK CLoopRcvDelayProc(void *pvData, long lSince)
  637. {
  638. // This timer was set the last time data input stopped. If no data
  639. // has been received since, notify the display routines so they can
  640. // do cursor tracking or whatever silly thing it is they do.
  641. ST_CLOOP *pstCLoop = (ST_CLOOP *)pvData;
  642. EnterCriticalSection(&pstCLoop->csect);
  643. if (!pstCLoop->fDataReceived)
  644. {
  645. emuTrackingNotify(pstCLoop->hEmu);
  646. }
  647. TimerDestroy(&pstCLoop->htimerRcvDelay);
  648. (void)&lSince; // avoid compiler warnings
  649. LeaveCriticalSection(&pstCLoop->csect);
  650. }
  651. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  652. * FUNCTION: CLoopCharDelayProc
  653. *
  654. * DESCRIPTION:
  655. *
  656. *
  657. * ARGUMENTS:
  658. *
  659. *
  660. * RETURNS:
  661. *
  662. */
  663. /* ARGSUSED */
  664. void CALLBACK CLoopCharDelayProc(void *pvData, long lSince)
  665. {
  666. ST_CLOOP *pstCLoop = (ST_CLOOP *)pvData;
  667. EnterCriticalSection(&pstCLoop->csect);
  668. TimerDestroy(&pstCLoop->htimerCharDelay);
  669. CLoopSndControl((HCLOOP)pstCLoop, CLOOP_RESUME, CLOOP_SB_DELAY);
  670. LeaveCriticalSection(&pstCLoop->csect);
  671. (void)&lSince; // avoid compiler warnings
  672. }