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.

730 lines
17 KiB

  1. /* File: D:\WACKER\tdll\termmos.c (Created: 26-Jan-1994)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 4 $
  7. * $Date: 5/29/02 2:17p $
  8. */
  9. //#define DEBUGSTR 1
  10. #include <windows.h>
  11. #pragma hdrstop
  12. #include <stdlib.h>
  13. #include "stdtyp.h"
  14. #include "assert.h"
  15. #include "session.h"
  16. #include "timers.h"
  17. #include "cloop.h"
  18. #include "htchar.h"
  19. #include <emu\emu.h>
  20. #include "term.h"
  21. #include "term.hh"
  22. static int InMiddleofWideChar(ECHAR *pszRow, int iCol);
  23. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  24. * FUNCTION:
  25. * TP_WM_LBTNDN
  26. *
  27. * DESCRIPTION:
  28. * Message handler for left mouse button down.
  29. *
  30. * ARGUMENTS:
  31. * hwnd - terminal window handle
  32. * iFlags - mouse flags from message
  33. * xPos - x position from message
  34. * yPos - y position from message
  35. *
  36. * RETURNS:
  37. * void
  38. *
  39. */
  40. void TP_WM_LBTNDN(const HWND hwnd, const unsigned uFlags,
  41. const int xPos, const int yPos)
  42. {
  43. MSG msg;
  44. POINT ptTemp;
  45. unsigned i, t;
  46. #ifndef CHAR_NARROW
  47. int iRow;
  48. #endif
  49. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  50. // Need to wait here for the length of a double-click to see
  51. // if we are going to receive a double-click.
  52. i = GetDoubleClickTime();
  53. for (i += t = GetTickCount() ; t < i ; t = GetTickCount())
  54. {
  55. // In a double-click sequence, we get a WM_LBUTTONUP message.
  56. // We need to avoid checking for WM_LBUTTONUP. I tried to
  57. // do this by removing messages from the queue but things
  58. // got very sticky.
  59. if (PeekMessage(&msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
  60. PM_NOYIELD | PM_NOREMOVE))
  61. {
  62. if (msg.message == WM_LBUTTONDBLCLK)
  63. return;
  64. if (msg.message == WM_LBUTTONUP)
  65. continue;
  66. break;
  67. }
  68. }
  69. if (GetKeyState(VK_SHIFT) >= 0 || !hhTerm->fMarkingLock)
  70. {
  71. MarkText(hhTerm, &hhTerm->ptBeg, &hhTerm->ptEnd, FALSE, MARK_ABS);
  72. // Get new text caret position/marking region.
  73. hhTerm->ptBeg.x = hhTerm->ptEnd.x =
  74. min((xPos - hhTerm->xIndent - hhTerm->xBezel + (hhTerm->xChar/2))
  75. / hhTerm->xChar + hhTerm->iHScrlPos,
  76. hhTerm->iHScrlPos + (hhTerm->iCols - hhTerm->iHScrlMax));
  77. hhTerm->ptBeg.y = hhTerm->ptEnd.y =
  78. min(yPos / hhTerm->yChar + hhTerm->iVScrlPos,
  79. hhTerm->iVScrlPos + hhTerm->iTermHite - 1);
  80. //mpt:1-23-98 attempt to re-enable DBCS code
  81. #ifndef CHAR_NARROW
  82. termValidatePosition(hhTerm, VP_ADJUST_LEFT, &hhTerm->ptBeg);
  83. termValidatePosition(hhTerm, VP_ADJUST_LEFT, &hhTerm->ptEnd);
  84. #endif
  85. }
  86. else
  87. {
  88. // Shift key in conjunction with LBUTTONDOWN allows user
  89. // to adjust selection area.
  90. ptTemp = hhTerm->ptEnd;
  91. hhTerm->ptEnd.y =
  92. min(yPos / hhTerm->yChar + hhTerm->iVScrlPos,
  93. hhTerm->iVScrlPos + hhTerm->iTermHite - 1);
  94. //(hhTerm, VP_ADJUST_LEFT, &hhTerm->ptEnd);
  95. MarkText(hhTerm, &ptTemp, &hhTerm->ptEnd, TRUE, MARK_XOR);
  96. }
  97. TestForMarkingLock(hhTerm);
  98. if (hhTerm->hMarkingTimer == 0)
  99. {
  100. TimerCreate(hhTerm->hSession,
  101. &hhTerm->hMarkingTimer,
  102. 100,
  103. MarkingTimerProc,
  104. (void *)hwnd);
  105. }
  106. #ifndef CHAR_NARROW
  107. if (hhTerm->ptBeg.y > 0)
  108. {
  109. iRow = ((hhTerm->ptBeg.y - 1) + hhTerm->iTopline) % MAX_EMUROWS;
  110. if (hhTerm->fppstAttr[iRow][hhTerm->ptBeg.x].wirt == TRUE)
  111. {
  112. hhTerm->ptBeg.x--;
  113. hhTerm->ptEnd.x--;
  114. }
  115. }
  116. else
  117. {
  118. iRow = yPos / hhTerm->yChar;
  119. // If the backscroll buffer is not filling the entire display,
  120. // then we need to adjust the offset by the amount not showing.
  121. if (abs(hhTerm->iVScrlPos) < hhTerm->iPhysicalBkRows)
  122. iRow += hhTerm->iPhysicalBkRows + hhTerm->iVScrlPos;
  123. // Calculate the offset into the local backscroll display.
  124. if (hhTerm->iPhysicalBkRows > 0)
  125. {
  126. iRow = (hhTerm->iNextBkLn + hhTerm->iPhysicalBkRows + iRow) %
  127. hhTerm->iPhysicalBkRows;
  128. }
  129. else
  130. {
  131. iRow = 0;
  132. }
  133. if (InMiddleofWideChar(hhTerm->fplpstrBkTxt[iRow], hhTerm->ptBeg.x))
  134. {
  135. hhTerm->ptBeg.x--;
  136. hhTerm->ptEnd.x--;
  137. }
  138. }
  139. #endif
  140. SetLclCurPos(hhTerm, &hhTerm->ptBeg);
  141. SetCapture(hwnd);
  142. sessSetSuspend(hhTerm->hSession, SUSPEND_TERMINAL_LBTNDN);
  143. hhTerm->fCapture = TRUE;
  144. return;
  145. }
  146. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  147. * FUNCTION:
  148. * TP_WM_MOUSEMOVE
  149. *
  150. * DESCRIPTION:
  151. * Message handler for mouse move
  152. *
  153. * ARGUMENTS:
  154. * hwnd - terminal window handle
  155. * iFlags - mouse flags from message
  156. * xPos - x position from message
  157. * yPos - y position from message
  158. *
  159. * RETURNS:
  160. * void
  161. *
  162. */
  163. void TP_WM_MOUSEMOVE(const HWND hwnd, const unsigned uFlags,
  164. const int xPos, const int yPos)
  165. {
  166. int i, l; //iRow; mrw,3/1/95
  167. #ifndef CHAR_NARROW
  168. int iRow;
  169. #endif
  170. POINT ptTemp, ptBeg, ptEnd;
  171. ECHAR *pachTxt;
  172. long lBeg, lEnd, lOld;
  173. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  174. if (hhTerm->fCapture == FALSE)
  175. return;
  176. ptTemp = hhTerm->ptEnd;
  177. // Rather a subtle move here. If we are selecting by word, we
  178. // want to hightlight the word as soon as we touch the character.
  179. // In normal highlighting, we trigger at the half way point
  180. // on the character. This removes a bug where you could double
  181. // click on the first char of a word and not select the word.
  182. i = (hhTerm->fSelectByWord) ? hhTerm->xChar-1 : hhTerm->xChar/2;
  183. ptEnd.x =
  184. max(min(((xPos - hhTerm->xIndent - hhTerm->xBezel + i) /
  185. hhTerm->xChar) + hhTerm->iHScrlPos,
  186. hhTerm->iHScrlPos + (hhTerm->iCols - hhTerm->iHScrlPos)),
  187. hhTerm->iHScrlPos);
  188. ptEnd.y = (yPos / hhTerm->yChar) + hhTerm->iVScrlPos;
  189. // Boundary conditions need special treatment.
  190. if (ptEnd.y > hhTerm->iRows) // bottom of terminal
  191. {
  192. ptEnd.y = hhTerm->iRows;
  193. ptEnd.x = hhTerm->iCols;
  194. }
  195. else if (ptEnd.y < hhTerm->iVScrlMin) // top of backscroll
  196. {
  197. ptEnd.y = hhTerm->iVScrlPos;
  198. ptEnd.x = 0;
  199. }
  200. #if 0
  201. {
  202. char ach[20];
  203. wsprintf(ach, "x=%d, y=%d, yPos=%d", ptEnd.x, ptEnd.y, yPos);
  204. SetWindowText(sessQueryHwndStatusbar(hhTerm->hSession), ach);
  205. }
  206. #endif
  207. // Selection by word requires more work.
  208. if (hhTerm->fSelectByWord)
  209. {
  210. if (ptEnd.y > 0)
  211. {
  212. i = (ptEnd.y + hhTerm->iTopline - 1) % MAX_EMUROWS;
  213. pachTxt = hhTerm->fplpstrTxt[i];
  214. }
  215. else if (ptEnd.y < 0)
  216. {
  217. i = yPos / hhTerm->yChar;
  218. // If the backscroll buffer is not filling the entire display,
  219. // then we need to adjust the offset by the amount not showing.
  220. if (abs(hhTerm->iVScrlPos) < hhTerm->iPhysicalBkRows)
  221. i += hhTerm->iPhysicalBkRows + hhTerm->iVScrlPos;
  222. // Calculate the offset into the local backscroll display.
  223. if (hhTerm->iPhysicalBkRows)
  224. {
  225. i = (hhTerm->iNextBkLn + hhTerm->iPhysicalBkRows + i) %
  226. hhTerm->iPhysicalBkRows;
  227. }
  228. else
  229. {
  230. i = 0;
  231. }
  232. pachTxt = hhTerm->fplpstrBkTxt[i];
  233. }
  234. else
  235. {
  236. return;
  237. }
  238. ptBeg = hhTerm->ptBeg;
  239. lBeg = (ptBeg.y * hhTerm->iCols) + ptBeg.x;
  240. lEnd = (ptEnd.y * hhTerm->iCols) + ptEnd.x;
  241. lOld = (ptTemp.y * hhTerm->iCols) + ptTemp.x;
  242. // When selecting by word, we want to keep the word we first
  243. // highlighted, highlighted if we change directions. We do
  244. // this by swapping the beginning and end points. Actually,
  245. // this can get fooled if the user moves across the the
  246. // transition point but not across the word but the extra
  247. // logic to get this case seemed more work than its worth.
  248. if (lEnd <= lBeg && lOld > lBeg)
  249. hhTerm->ptBeg = ptTemp;
  250. else if (lEnd >= lBeg && lOld < lBeg)
  251. hhTerm->ptBeg = ptTemp;
  252. // How we select things depends on the direction unfortunatly.
  253. if (lEnd > lBeg)
  254. {
  255. if ((l = strlentrunc(pachTxt, hhTerm->iCols)) < ptEnd.x)
  256. {
  257. i = l;
  258. }
  259. else if (xPos < 0)
  260. {
  261. // Special hack when cursor is off to the
  262. // left of the window.
  263. i = 0;
  264. }
  265. else if (i = max(ptEnd.x-1, 0), pachTxt[i] == ETEXT(' '))
  266. {
  267. for (i = ptEnd.x-1 ; i > -1 ; --i)
  268. {
  269. /* This may not work correctly for DBCS characters */
  270. if (i == -1 || pachTxt[i] != ETEXT(' '))
  271. {
  272. i += 1;
  273. break;
  274. }
  275. }
  276. }
  277. else
  278. {
  279. for (i = max(ptEnd.x-1, 0) ; i < l ; ++i)
  280. {
  281. /* This may not work correctly for DBCS characters */
  282. if (pachTxt[i] == ETEXT(' '))
  283. break;
  284. }
  285. }
  286. }
  287. else // Select backwords case
  288. {
  289. if ((l = strlentrunc(pachTxt, hhTerm->iCols)) < ptEnd.x)
  290. {
  291. i = hhTerm->iCols;
  292. }
  293. else if (i = max(ptEnd.x-1, 0), pachTxt[i] == ETEXT(' '))
  294. {
  295. for (i = max(ptEnd.x-1, 0) ; i < l ; ++i)
  296. {
  297. if (pachTxt[i] != ETEXT(' '))
  298. break;
  299. }
  300. }
  301. else
  302. {
  303. for (i = ptEnd.x-1 ; i > -1 ; --i)
  304. {
  305. /* This may not work correctly for DBCS characters */
  306. if (pachTxt[i] == ETEXT(' '))
  307. {
  308. i += 1;
  309. break;
  310. }
  311. }
  312. }
  313. }
  314. ptEnd.x = max(i, 0);
  315. }
  316. lBeg = (ptBeg.y * hhTerm->iCols) + ptBeg.x;
  317. lEnd = (ptEnd.y * hhTerm->iCols) + ptEnd.x;
  318. #ifndef CHAR_NARROW
  319. // How we select things depends on the direction unfortunatly.
  320. if (ptEnd.y > 0)
  321. {
  322. iRow = ((ptEnd.y - 1) + hhTerm->iTopline) % MAX_EMUROWS;
  323. if (hhTerm->fppstAttr[iRow][ptEnd.x].wirt == TRUE)
  324. if (lEnd > lBeg)
  325. {
  326. ptEnd.x++;
  327. }
  328. else
  329. {
  330. ptEnd.x--;
  331. }
  332. }
  333. else
  334. {
  335. iRow = yPos / hhTerm->yChar;
  336. // If the backscroll buffer is not filling the entire display,
  337. // then we need to adjust the offset by the amount not showing.
  338. if (abs(hhTerm->iVScrlPos) < hhTerm->iPhysicalBkRows)
  339. iRow += hhTerm->iPhysicalBkRows + hhTerm->iVScrlPos;
  340. // Calculate the offset into the local backscroll display.
  341. if (hhTerm->iPhysicalBkRows > 0)
  342. {
  343. iRow = (hhTerm->iNextBkLn + hhTerm->iPhysicalBkRows + iRow) %
  344. hhTerm->iPhysicalBkRows;
  345. }
  346. else
  347. {
  348. iRow = 0;
  349. }
  350. if (InMiddleofWideChar(hhTerm->fplpstrBkTxt[iRow], ptEnd.x))
  351. {
  352. if (lEnd > lBeg)
  353. {
  354. ptEnd.x++;
  355. }
  356. else
  357. {
  358. ptEnd.x--;
  359. }
  360. }
  361. }
  362. #endif
  363. if (ptTemp.x == ptEnd.x && ptTemp.y == ptEnd.y)
  364. return;
  365. //(hhTerm, VP_ADJUST_LEFT, &ptEnd);
  366. hhTerm->ptEnd = ptEnd;
  367. SetLclCurPos(hhTerm, &ptEnd);
  368. MarkText(hhTerm, &ptTemp, &ptEnd, TRUE, MARK_XOR);
  369. return;
  370. }
  371. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  372. * FUNCTION:
  373. * TP_WM_LBTNUP
  374. *
  375. * DESCRIPTION:
  376. * Message handler for left mouse button up.
  377. *
  378. * ARGUMENTS:
  379. * hwnd - terminal window handle
  380. * iFlags - mouse flags from message
  381. * xPos - x position from message
  382. * yPos - y position from message
  383. *
  384. * RETURNS:
  385. * void
  386. *
  387. */
  388. void TP_WM_LBTNUP(const HWND hwnd, const unsigned uFlags,
  389. const int xPos, const int yPos)
  390. {
  391. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  392. if (hhTerm->fCapture == FALSE)
  393. return;
  394. // Let mousemove logic set the final end point.
  395. SendMessage(hwnd, WM_MOUSEMOVE, uFlags, MAKELONG(xPos, yPos));
  396. // Kill the marking timer!
  397. if (hhTerm->hMarkingTimer != (HTIMER)0)
  398. {
  399. TimerDestroy(&hhTerm->hMarkingTimer);
  400. }
  401. // Turnoff flags associated with text-marking and give back the mouse.
  402. ReleaseCapture();
  403. hhTerm->fCapture = FALSE;
  404. hhTerm->fSelectByWord = FALSE;
  405. sessClearSuspend(hhTerm->hSession, SUSPEND_TERMINAL_LBTNDN);
  406. return;
  407. }
  408. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  409. * FUNCTION:
  410. * TP_WM_LBTNDBLCLK
  411. *
  412. * DESCRIPTION:
  413. * Message handler for left mouse button double click.
  414. *
  415. * ARGUMENTS:
  416. * hwnd - terminal window handle
  417. * iFlags - mouse flags from message
  418. * xPos - x position from message
  419. * yPos - y position from message
  420. *
  421. * RETURNS:
  422. * void
  423. *
  424. */
  425. void TP_WM_LBTNDBLCLK(const HWND hwnd, const unsigned uFlags,
  426. const int xPos, const int yPos)
  427. {
  428. int i, j, k, l, m;
  429. ECHAR *pachTxt;
  430. POINT ptTemp, ptBeg, ptEnd;
  431. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  432. i = (yPos / hhTerm->yChar) + hhTerm->iVScrlPos;
  433. j = ((xPos - hhTerm->xIndent - hhTerm->xBezel) / hhTerm->xChar) + hhTerm->iHScrlPos;
  434. ptTemp.x = j;
  435. ptTemp.y = i;
  436. ptBeg = hhTerm->ptBeg;
  437. ptEnd = hhTerm->ptEnd;
  438. // If we double-clicked over selected text and we have the correct
  439. // options set, then send it to the host.
  440. if (hhTerm->iBtnOne == B1_COPYWORD || hhTerm->iBtnOne == B1_COPYWORDENTER)
  441. {
  442. if (PointInSelectionRange(&ptTemp, &ptBeg, &ptEnd, hhTerm->iCols))
  443. {
  444. //*CopyTextToHost(hSession,
  445. //* CopyTextFromTerminal(hSession, &ptBeg, &ptEnd, FALSE));
  446. if (hhTerm->iBtnOne == B1_COPYWORDENTER)
  447. CLoopSend(sessQueryCLoopHdl(hhTerm->hSession), TEXT("\r"), 1, 0);
  448. return;
  449. }
  450. }
  451. // Nope, just figure out what to highlight.
  452. if (i > 0)
  453. {
  454. m = (i + hhTerm->iTopline - 1) % MAX_EMUROWS;
  455. pachTxt = hhTerm->fplpstrTxt[m];
  456. }
  457. else if (i < 0)
  458. {
  459. m = yPos / hhTerm->yChar;
  460. // If the backscroll buffer is not filling the entire display,
  461. // then we need to adjust the offset by the amount not showing.
  462. if (abs(hhTerm->iVScrlPos) < hhTerm->iPhysicalBkRows)
  463. m += hhTerm->iPhysicalBkRows + hhTerm->iVScrlPos;
  464. // Calculate the offset into the local backscroll display.
  465. if (hhTerm->iPhysicalBkRows > 0)
  466. {
  467. m = (hhTerm->iNextBkLn + hhTerm->iPhysicalBkRows + m) %
  468. hhTerm->iPhysicalBkRows;
  469. }
  470. else
  471. {
  472. m = 0;
  473. }
  474. pachTxt = hhTerm->fplpstrBkTxt[m];
  475. }
  476. else
  477. {
  478. return;
  479. }
  480. // Determine where the the word starts and ends. If the user
  481. // clicks on white space, do the else case below.
  482. if ((m = strlentrunc(pachTxt, hhTerm->iCols)) > j)
  483. {
  484. if (pachTxt[j] != ETEXT(' '))
  485. {
  486. for (k = j ; k > 0 ; --k)
  487. {
  488. /* This may not work correctly for DBCS characters */
  489. if (pachTxt[k] == ETEXT(' '))
  490. {
  491. k += 1;
  492. break;
  493. }
  494. }
  495. for (l = j ; l < m ; ++l)
  496. {
  497. /* This may not work correctly for DBCS characters */
  498. if (pachTxt[l] == ETEXT(' '))
  499. break;
  500. }
  501. MarkText(hhTerm, &ptBeg, &ptEnd, FALSE, MARK_ABS);
  502. ptBeg.x = k;
  503. ptBeg.y = i;
  504. ptEnd.x = l;
  505. ptEnd.y = i;
  506. hhTerm->ptBeg = ptBeg;
  507. hhTerm->ptEnd = ptEnd;
  508. MarkText(hhTerm, &ptBeg, &ptEnd, TRUE, MARK_ABS);
  509. // If we have any kind of a sending operation selected,
  510. // then override marking
  511. if (hhTerm->iBtnOne == B1_COPYWORD || hhTerm->iBtnOne == B1_COPYWORDENTER)
  512. {
  513. if (PointInSelectionRange(&ptTemp, &ptBeg, &ptEnd, hhTerm->iCols))
  514. {
  515. //* CopyTextToHost(hSession,
  516. //* CopyTextFromTerminal(hSession, &ptBeg, &ptEnd,
  517. //* FALSE));
  518. if (hhTerm->iBtnOne == B1_COPYWORDENTER)
  519. CLoopSend(sessQueryCLoopHdl(hhTerm->hSession), TEXT("\r"), 1, 0);
  520. return;
  521. }
  522. }
  523. SetLclCurPos(hhTerm, &ptEnd);
  524. if (hhTerm->hMarkingTimer == 0)
  525. {
  526. TimerCreate(hhTerm->hSession,
  527. &hhTerm->hMarkingTimer,
  528. 100,
  529. MarkingTimerProc,
  530. (void *)hwnd);
  531. }
  532. hhTerm->fSelectByWord = TRUE;
  533. SetCapture(hwnd);
  534. hhTerm->fCapture = TRUE;
  535. }
  536. }
  537. else /* --- white-space case. --- */
  538. {
  539. if (hhTerm->iBtnOne == B1_COPYWORDENTER)
  540. CLoopSend(sessQueryCLoopHdl(hhTerm->hSession), TEXT("\r"), 1, 0);
  541. }
  542. return;
  543. }
  544. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  545. * FUNCTION:
  546. * InMiddleofWideChar
  547. *
  548. * DESCRIPTION:
  549. * Determines if we are in the middle of a wide character in the row. We can do this because:
  550. * 1: The image is in ECHARS, which means that we can deal with individual col. positions.
  551. * 2: The characters are doubled in the image, being displayed as left/right pairs, we are
  552. * just trying to find out if we are in the middle of one of these pairs
  553. *
  554. * ARGUMENTS:
  555. * ECHAR *pszString - emulator/backscroll row image
  556. *
  557. * RETURNS:
  558. * TRUE: we are in the middle of a character
  559. * FALSE: no we are not
  560. *
  561. * AUTHOR: JFH:1/28/94 - yes this was a saturday, oh well it's cold out right now anyways.
  562. */
  563. static int InMiddleofWideChar(ECHAR *pszRow, int iCol)
  564. {
  565. ECHAR *pszChar;
  566. int nRet = FALSE;
  567. int nPos;
  568. BOOL fDBCSFlag = FALSE;
  569. if (pszRow == NULL)
  570. {
  571. assert(FALSE);
  572. return nRet;
  573. }
  574. // If we are in col. 0, we can not be in the middle of a character
  575. if (iCol == 0)
  576. {
  577. return FALSE;
  578. }
  579. pszChar = pszRow;
  580. for (nPos = 0; nPos <= iCol ; nPos++)
  581. {
  582. if (isDBCSChar(*pszChar))
  583. {
  584. if (fDBCSFlag)
  585. {
  586. if ((nPos == iCol) && (*(pszChar - 1) == *pszChar))
  587. {
  588. nRet = TRUE;
  589. }
  590. fDBCSFlag = FALSE;
  591. }
  592. else
  593. {
  594. fDBCSFlag = TRUE;
  595. }
  596. }
  597. else
  598. {
  599. fDBCSFlag = FALSE;
  600. }
  601. pszChar++;
  602. }
  603. return nRet;
  604. }