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.

1968 lines
62 KiB

  1. /****************************************************************************\
  2. * edECRare.c - EC Edit controls Routines Called rarely are to be
  3. * put in a seperate segment _EDECRare. This file contains
  4. * these routines.
  5. *
  6. * Copyright (c) 1985 - 1999, Microsoft Corporation
  7. *
  8. * Support Routines common to Single-line and Multi-Line edit controls
  9. * called Rarely.
  10. *
  11. * Created: 02-08-89 sankar
  12. \****************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. extern LOOKASIDE EditLookaside;
  16. #define WS_EX_EDGEMASK (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)
  17. /*
  18. * Those two macros assume PED can be referred as "ped."
  19. */
  20. #define GetCharABCWidthsAorW ((ped)->fAnsi ? GetCharABCWidthsA : GetCharABCWidthsW)
  21. #define GetCharWidthAorW ((ped)->fAnsi ? GetCharWidthA : GetCharWidthW)
  22. #define umin(a, b) ((unsigned)(a) < (unsigned)(b) ? (unsigned)(a) : (unsigned)(b))
  23. typedef BOOL (*PFNABCWIDTHS)(HDC, UINT, UINT, LPABC);
  24. typedef BOOL (*PFNCHARWIDTH)(HDC, UINT, UINT, LPINT);
  25. /***************************************************************************\
  26. *
  27. * GetMaxOverlapChars - Gives maximum number of overlapping characters due to
  28. * negative A or C widths.
  29. *
  30. \***************************************************************************/
  31. DWORD GetMaxOverlapChars( void )
  32. {
  33. return (DWORD) MAKELONG( gpsi->wMaxLeftOverlapChars, gpsi->wMaxRightOverlapChars ) ;
  34. }
  35. /***************************************************************************\
  36. *
  37. * ECSetMargin()
  38. *
  39. \***************************************************************************/
  40. void ECSetMargin(PED ped, UINT wFlags, long lMarginValues, BOOL fRedraw)
  41. {
  42. BOOL fUseFontInfo = FALSE;
  43. UINT wValue, wOldLeftMargin, wOldRightMargin;
  44. if (wFlags & EC_LEFTMARGIN) /* Set the left margin */ {
  45. if ((int) (wValue = (int)(short)LOWORD(lMarginValues)) < 0) {
  46. fUseFontInfo = TRUE;
  47. wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegA);
  48. }
  49. ped->rcFmt.left += wValue - ped->wLeftMargin;
  50. wOldLeftMargin = ped->wLeftMargin;
  51. ped->wLeftMargin = wValue;
  52. }
  53. if (wFlags & EC_RIGHTMARGIN) /* Set the Right margin */ {
  54. if ((int) (wValue = (int)(short)HIWORD(lMarginValues)) < 0) {
  55. fUseFontInfo = TRUE;
  56. wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegC);
  57. }
  58. ped->rcFmt.right -= wValue - ped->wRightMargin;
  59. wOldRightMargin = ped->wRightMargin;
  60. ped->wRightMargin = wValue;
  61. }
  62. if (fUseFontInfo) {
  63. if (ped->rcFmt.right - ped->rcFmt.left < 2 * ped->aveCharWidth) {
  64. RIPMSG0(RIP_WARNING, "ECSetMargin: rcFmt is too narrow for EC_USEFONTINFO");
  65. if (wFlags & EC_LEFTMARGIN) /* Reset the left margin */ {
  66. ped->rcFmt.left += wOldLeftMargin - ped->wLeftMargin;
  67. ped->wLeftMargin = wOldLeftMargin;
  68. }
  69. if (wFlags & EC_RIGHTMARGIN) /* Reset the Right margin */ {
  70. ped->rcFmt.right -= wOldRightMargin - ped->wRightMargin;
  71. ped->wRightMargin = wOldRightMargin;
  72. }
  73. return;
  74. }
  75. }
  76. // NtUserInvalidateRect(ped->hwnd, NULL, TRUE);
  77. if (fRedraw) {
  78. ECInvalidateClient(ped, TRUE);
  79. }
  80. }
  81. // --------------------------------------------------------------------------
  82. //
  83. // ECCalcMarginfForDBCSFont()
  84. //
  85. // Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (edecrare.c)
  86. // --------------------------------------------------------------------------
  87. void ECCalcMarginForDBCSFont(PED ped, BOOL fRedraw)
  88. {
  89. if (!ped->fTrueType)
  90. return;
  91. if (!ped->fSingle) {
  92. // wMaxNegA came from ABC CharWidth.
  93. if (ped->wMaxNegA != 0) {
  94. ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  95. MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO),fRedraw);
  96. }
  97. } else {
  98. int iMaxNegA = 0, iMaxNegC = 0;
  99. int i;
  100. PVOID lpBuffer;
  101. LPABC lpABCBuff;
  102. ABC ABCInfo;
  103. HFONT hOldFont;
  104. HDC hdc = NtUserGetDC(ped->hwnd);
  105. if (!ped->hFont || !(hOldFont = SelectFont(hdc, ped->hFont))) {
  106. ReleaseDC(ped->hwnd, hdc);
  107. return;
  108. }
  109. if (lpBuffer = UserLocalAlloc(0,sizeof(ABC) * 256)) {
  110. lpABCBuff = lpBuffer;
  111. GetCharABCWidthsAorW(hdc, 0, 255, lpABCBuff);
  112. } else {
  113. lpABCBuff = &ABCInfo;
  114. GetCharABCWidthsAorW(hdc, 0, 0, lpABCBuff);
  115. }
  116. i = 0;
  117. while (TRUE) {
  118. iMaxNegA = min(iMaxNegA, lpABCBuff->abcA);
  119. iMaxNegC = min(iMaxNegC, lpABCBuff->abcC);
  120. if (++i == 256)
  121. break;
  122. if (lpBuffer) {
  123. lpABCBuff++;
  124. } else {
  125. GetCharABCWidthsAorW(hdc, i, i, lpABCBuff);
  126. }
  127. }
  128. SelectFont(hdc, hOldFont);
  129. if (lpBuffer) UserLocalFree(lpBuffer);
  130. ReleaseDC(ped->hwnd, hdc);
  131. if ((iMaxNegA != 0) || (iMaxNegC != 0))
  132. ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  133. MAKELONG((UINT)(-iMaxNegC), (UINT)(-iMaxNegA)),fRedraw);
  134. }
  135. return;
  136. }
  137. // --------------------------------------------------------------------------
  138. //
  139. // GetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
  140. //
  141. // Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (wmclient.c)
  142. // --------------------------------------------------------------------------
  143. CONST WCHAR AveCharWidthData[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  144. //
  145. // if an app set a font for vertical writing, even though we don't
  146. // handle it with EC, the escapement of tm can be NON 0. Then cxWidth from
  147. // GetCharDimenstions() could be 0 in GetCharDimensions().
  148. // This will break our caller who don't expect 0 at return. So I created
  149. // this entry for the case the caller set vertical font.
  150. //
  151. //
  152. int UserGetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
  153. {
  154. int cxWidth;
  155. TEXTMETRIC tm;
  156. LOGFONTW lf;
  157. WCHAR wchFaceName[LF_FACESIZE];
  158. //
  159. // Is this font vertical font ??
  160. //
  161. wchFaceName[0] = 0;
  162. GetTextFaceW(hDC, LF_FACESIZE, wchFaceName);
  163. if (wchFaceName[0] != L'@') {
  164. //
  165. // if not call GDI...
  166. //
  167. return(GdiGetCharDimensions(hDC, lptm, lpcy));
  168. }
  169. if (!lptm)
  170. lptm = &tm;
  171. GetTextMetrics(hDC, lptm);
  172. // TMPF_FIXED_PITCH
  173. //
  174. // If this bit is set the font is a variable pitch font.
  175. // If this bit is clear the font is a fixed pitch font.
  176. // Note very carefully that those meanings are the opposite of what the constant name implies.
  177. //
  178. if (!(lptm->tmPitchAndFamily & TMPF_FIXED_PITCH)) { // If !variable_width font
  179. // This is fixed pitch font....
  180. cxWidth = lptm->tmAveCharWidth;
  181. } else {
  182. // This is variable pitch font...
  183. if (hfont && GetObjectW(hfont, sizeof(LOGFONTW), &lf) && (lf.lfEscapement != 0)) {
  184. cxWidth = lptm->tmAveCharWidth;
  185. } else {
  186. SIZE size;
  187. GetTextExtentPointW(hDC, AveCharWidthData, 52, &size);
  188. cxWidth = ((size.cx / 26) + 1) / 2;
  189. }
  190. }
  191. if (lpcy)
  192. *lpcy = lptm->tmHeight;
  193. return(cxWidth);
  194. }
  195. /***************************************************************************\
  196. * ECGetText AorW
  197. *
  198. * Copies at most maxCchToCopy chars to the buffer lpBuffer. Returns
  199. * how many chars were actually copied. Null terminates the string based
  200. * on the fNullTerminate flag:
  201. * fNullTerminate --> at most (maxCchToCopy - 1) characters will be copied
  202. * !fNullTerminate --> at most (maxCchToCopy) characters will be copied
  203. *
  204. * History:
  205. \***************************************************************************/
  206. ICH ECGetText(
  207. PED ped,
  208. ICH maxCchToCopy,
  209. LPSTR lpBuffer,
  210. BOOL fNullTerminate)
  211. {
  212. PSTR pText;
  213. if (maxCchToCopy) {
  214. /*
  215. * Zero terminator takes the extra byte
  216. */
  217. if (fNullTerminate)
  218. maxCchToCopy--;
  219. maxCchToCopy = min(maxCchToCopy, ped->cch);
  220. /*
  221. * Zero terminate the string
  222. */
  223. if (ped->fAnsi)
  224. *(LPSTR)(lpBuffer + maxCchToCopy) = 0;
  225. else
  226. *(((LPWSTR)lpBuffer) + maxCchToCopy) = 0;
  227. pText = ECLock(ped);
  228. RtlCopyMemory(lpBuffer, pText, maxCchToCopy*ped->cbChar);
  229. ECUnlock(ped);
  230. }
  231. return maxCchToCopy;
  232. }
  233. /***************************************************************************\
  234. * ECNcCreate AorW
  235. *
  236. * History:
  237. \***************************************************************************/
  238. BOOL ECNcCreate(
  239. PED ped,
  240. PWND pwnd,
  241. LPCREATESTRUCT lpCreateStruct)
  242. {
  243. HWND hwnd = HWq(pwnd);
  244. BOOL fAnsi;
  245. fAnsi = TestWF(pwnd, WFANSICREATOR);
  246. /*
  247. * Initialize the ped
  248. */
  249. ped->fEncoded = FALSE;
  250. ped->iLockLevel = 0;
  251. ped->chLines = NULL;
  252. ped->pTabStops = NULL;
  253. ped->charWidthBuffer = NULL;
  254. ped->fAnsi = fAnsi ? 1 : 0; // Force TRUE to be 1 because its a 1 bit field
  255. ped->cbChar = (WORD)(fAnsi ? sizeof(CHAR) : sizeof(WCHAR));
  256. ped->hInstance = KHANDLE_TO_HANDLE(pwnd->hModule);
  257. // IME
  258. ped->hImcPrev = NULL_HIMC;
  259. {
  260. DWORD dwVer = GETEXPWINVER(lpCreateStruct->hInstance);
  261. ped->fWin31Compat = (dwVer >= 0x030a);
  262. ped->f40Compat = (dwVer >= 0x0400);
  263. }
  264. //
  265. // NOTE:
  266. // The order of the following two checks is important. People can
  267. // create edit fields with a 3D and a normal border, and we don't
  268. // want to disallow that. But we need to detect the "no 3D border"
  269. // border case too.
  270. //
  271. if (TestWF(pwnd, WEFEDGEMASK))
  272. {
  273. ped->fBorder = TRUE;
  274. }
  275. else if (TestWF(pwnd, WFBORDER))
  276. {
  277. ClearWindowState(pwnd, WFBORDER);
  278. ped->fFlatBorder = TRUE;
  279. ped->fBorder = TRUE;
  280. }
  281. if (!TestWF(pwnd, EFMULTILINE))
  282. ped->fSingle = TRUE;
  283. if (TestWF(pwnd, WFDISABLED))
  284. ped->fDisabled = TRUE;
  285. if (TestWF(pwnd, EFREADONLY)) {
  286. if (!ped->fWin31Compat) {
  287. /*
  288. * BACKWARD COMPATIBILITY HACK
  289. *
  290. * "MileStone" unknowingly sets the ES_READONLY style. So, we strip this
  291. * style here for all Win3.0 apps (this style is new for Win3.1).
  292. * Fix for Bug #12982 -- SANKAR -- 01/24/92 --
  293. */
  294. ClearWindowState(pwnd, EFREADONLY);
  295. } else
  296. ped->fReadOnly = TRUE;
  297. }
  298. /*
  299. * Allocate storage for the text for the edit controls. Storage for single
  300. * line edit controls will always get allocated in the local data segment.
  301. * Multiline will allocate in the local ds but the app may free this and
  302. * allocate storage elsewhere...
  303. */
  304. ped->hText = LOCALALLOC(LHND, CCHALLOCEXTRA*ped->cbChar, ped->hInstance);
  305. if (!ped->hText) {
  306. FreeLookasideEntry(&EditLookaside, ped);
  307. NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT); /* No ped for this window */
  308. return FALSE;
  309. }
  310. ped->cchAlloc = CCHALLOCEXTRA;
  311. ped->lineHeight = 1;
  312. ped->hwnd = hwnd;
  313. ped->hwndParent = lpCreateStruct->hwndParent;
  314. ped->wImeStatus = 0;
  315. return (BOOL)DefWindowProcWorker(pwnd,
  316. WM_NCCREATE,
  317. 0,
  318. (LPARAM)lpCreateStruct,
  319. fAnsi);
  320. }
  321. /***************************************************************************\
  322. * ECCreate AorW
  323. *
  324. * History:
  325. \***************************************************************************/
  326. BOOL ECCreate(
  327. PED ped,
  328. LONG windowStyle)
  329. {
  330. HDC hdc;
  331. /*
  332. * Get values from the window instance data structure and put them in the
  333. * ped so that we can access them easier.
  334. */
  335. if (windowStyle & ES_AUTOHSCROLL)
  336. ped->fAutoHScroll = 1;
  337. if (windowStyle & ES_NOHIDESEL)
  338. ped->fNoHideSel = 1;
  339. ped->format = (LOWORD(windowStyle) & LOWORD(ES_FMTMASK));
  340. if (TestWF(ped->pwnd, WEFRIGHT) && !ped->format)
  341. ped->format = ES_RIGHT;
  342. ped->cchTextMax = MAXTEXT; /* Max # chars we will initially allow */
  343. /*
  344. * Set up undo initial conditions... (ie. nothing to undo)
  345. */
  346. ped->ichDeleted = (ICH)-1;
  347. ped->ichInsStart = (ICH)-1;
  348. ped->ichInsEnd = (ICH)-1;
  349. // initial charset value - need to do this BEFORE MLCreate is called
  350. // so that we know not to fool with scrollbars if nessacary
  351. hdc = ECGetEditDC(ped, TRUE);
  352. ped->charSet = (BYTE)GetTextCharset(hdc);
  353. ECReleaseEditDC(ped, hdc, TRUE);
  354. // FE_IME
  355. // EC_INSERT_COMPOSITION_CHARACTER: ECCreate() - call ECInitInsert()
  356. ECInitInsert(ped, THREAD_HKL());
  357. if(ped->pLpkEditCallout = fpLpkEditControl) {
  358. return ped->pLpkEditCallout->EditCreate(ped, HW(ped->pwnd));
  359. } else
  360. return TRUE;
  361. }
  362. /***************************************************************************\
  363. * ECNcDestroyHandler AorW
  364. *
  365. * Destroys the edit control ped by freeing up all memory used by it.
  366. *
  367. * History:
  368. \***************************************************************************/
  369. VOID ECNcDestroyHandler(
  370. PWND pwnd,
  371. PED ped)
  372. {
  373. PWND pwndParent;
  374. /*
  375. * Ped could be NULL if WM_NCCREATE failed to create it.
  376. */
  377. if (ped) {
  378. /*
  379. * Free the text buffer.
  380. */
  381. LOCALFREE(ped->hText, ped->hInstance);
  382. /*
  383. * Free up undo buffer and line start array (if present).
  384. */
  385. if (ped->hDeletedText != NULL) {
  386. UserGlobalFree(ped->hDeletedText);
  387. }
  388. /*
  389. * Free tab stop buffer (if present)
  390. */
  391. if (ped->pTabStops) {
  392. UserLocalFree(ped->pTabStops);
  393. }
  394. /*
  395. * Free line start array (if present)
  396. */
  397. if (ped->chLines) {
  398. UserLocalFree(ped->chLines);
  399. }
  400. /*
  401. * Free the character width buffer (if present).
  402. */
  403. if (ped->charWidthBuffer) {
  404. UserLocalFree(ped->charWidthBuffer);
  405. }
  406. /*
  407. * Free the cursor bitmap.
  408. */
  409. if (ped->pLpkEditCallout && ped->hCaretBitmap) {
  410. DeleteObject(ped->hCaretBitmap);
  411. }
  412. /*
  413. * Last but not least, free the ped.
  414. */
  415. FreeLookasideEntry(&EditLookaside, ped);
  416. }
  417. /*
  418. * Set the window's fnid status so that we can ignore rogue messages.
  419. */
  420. NtUserSetWindowFNID(HWq(pwnd), FNID_CLEANEDUP_BIT);
  421. /*
  422. * If we're part of a combo box, let it know we're gone.
  423. */
  424. pwndParent = REBASEPWND(pwnd, spwndParent);
  425. if (pwndParent && GETFNID(pwndParent) == FNID_COMBOBOX) {
  426. ComboBoxWndProcWorker(pwndParent,
  427. WM_PARENTNOTIFY,
  428. MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)),
  429. (LPARAM)HWq(pwnd),
  430. FALSE);
  431. }
  432. }
  433. /***************************************************************************\
  434. * ECSetPasswordChar AorW
  435. *
  436. * Sets the password char to display.
  437. *
  438. * History:
  439. \***************************************************************************/
  440. void ECSetPasswordChar(
  441. PED ped,
  442. UINT pwchar)
  443. {
  444. HDC hdc;
  445. SIZE size;
  446. ped->charPasswordChar = pwchar;
  447. if (pwchar) {
  448. hdc = ECGetEditDC(ped, TRUE);
  449. if (ped->fAnsi)
  450. GetTextExtentPointA(hdc, (LPSTR)&pwchar, 1, &size);
  451. else
  452. GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
  453. GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
  454. ped->cPasswordCharWidth = max(size.cx, 1);
  455. ECReleaseEditDC(ped, hdc, TRUE);
  456. }
  457. if (pwchar)
  458. SetWindowState(ped->pwnd, EFPASSWORD);
  459. else
  460. ClearWindowState(ped->pwnd, EFPASSWORD);
  461. ECEnableDisableIME(ped);
  462. }
  463. /***************************************************************************\
  464. * GetNegABCwidthInfo()
  465. * This function fills up the ped->charWidthBuffer buffer with the
  466. * negative A,B and C widths for all the characters below 0x7f in the
  467. * currently selected font.
  468. * Returns:
  469. * TRUE, if the function succeeded.
  470. * FALSE, if GDI calls to get the char widths have failed.
  471. *
  472. * Note: not used if LPK installed
  473. \***************************************************************************/
  474. BOOL GetNegABCwidthInfo(
  475. PED ped,
  476. HDC hdc)
  477. {
  478. LPABC lpABCbuff;
  479. int i;
  480. int CharWidthBuff[CHAR_WIDTH_BUFFER_LENGTH]; // Local char width buffer.
  481. int iOverhang;
  482. if (!GetCharABCWidthsA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPABC)ped->charWidthBuffer)) {
  483. RIPMSG0(RIP_WARNING, "GetNegABCwidthInfo: GetCharABCWidthsA Failed");
  484. return FALSE;
  485. }
  486. // The (A+B+C) returned for some fonts (eg: Lucida Caligraphy) does not
  487. // equal the actual advanced width returned by GetCharWidths() minus overhang.
  488. // This is due to font bugs. So, we adjust the 'B' width so that this
  489. // discrepancy is removed.
  490. // Fix for Bug #2932 --sankar-- 02/17/93
  491. iOverhang = ped->charOverhang;
  492. GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPINT)CharWidthBuff);
  493. lpABCbuff = (LPABC)ped->charWidthBuffer;
  494. for(i = 0; i < CHAR_WIDTH_BUFFER_LENGTH; i++) {
  495. lpABCbuff->abcB = CharWidthBuff[i] - iOverhang
  496. - lpABCbuff->abcA
  497. - lpABCbuff->abcC;
  498. lpABCbuff++;
  499. }
  500. return(TRUE);
  501. }
  502. /***************************************************************************\
  503. *
  504. * ECSize() -
  505. *
  506. * Handle sizing for an edit control's client rectangle.
  507. * Use lprc as the bounding rectangle if specified; otherwise use the current
  508. * client rectangle.
  509. *
  510. \***************************************************************************/
  511. void ECSize(
  512. PED ped,
  513. LPRECT lprc,
  514. BOOL fRedraw)
  515. {
  516. RECT rc;
  517. /*
  518. * BiDi VB32 Creates an Edit Control and immediately sends a WM_SIZE
  519. * message which causes EXSize to be called before ECSetFont, which
  520. * in turn causes a divide by zero exception below. This check for
  521. * ped->lineHeight will pick it up safely. [samera] 3/5/97
  522. */
  523. if(ped->lineHeight == 0)
  524. return;
  525. // assume that we won't be able to display the caret
  526. ped->fCaretHidden = TRUE;
  527. if ( lprc )
  528. CopyRect(&rc, lprc);
  529. else
  530. _GetClientRect(ped->pwnd, &rc);
  531. if (!(rc.right - rc.left) || !(rc.bottom - rc.top)) {
  532. if (ped->rcFmt.right - ped->rcFmt.left)
  533. return;
  534. rc.left = 0;
  535. rc.top = 0;
  536. rc.right = ped->aveCharWidth * 10;
  537. rc.bottom = ped->lineHeight;
  538. }
  539. if (!lprc) {
  540. // subtract the margins from the given rectangle --
  541. // make sure that this rectangle is big enough to have these margins.
  542. if ((rc.right - rc.left) > (int)(ped->wLeftMargin + ped->wRightMargin)) {
  543. rc.left += ped->wLeftMargin;
  544. rc.right -= ped->wRightMargin;
  545. }
  546. }
  547. //
  548. // Leave space so text doesn't touch borders.
  549. // For 3.1 compatibility, don't subtract out vertical borders unless
  550. // there is room.
  551. //
  552. if (ped->fBorder) {
  553. int cxBorder = SYSMET(CXBORDER);
  554. int cyBorder = SYSMET(CYBORDER);
  555. if (ped->fFlatBorder)
  556. {
  557. cxBorder *= 2;
  558. cyBorder *= 2;
  559. }
  560. if (rc.bottom < rc.top + ped->lineHeight + 2*cyBorder)
  561. cyBorder = 0;
  562. InflateRect(&rc, -cxBorder, -cyBorder);
  563. }
  564. // Is the resulting rectangle too small? Don't change it then.
  565. if ((!ped->fSingle) && ((rc.right - rc.left < (int) ped->aveCharWidth) ||
  566. ((rc.bottom - rc.top) / ped->lineHeight == 0)))
  567. return;
  568. // now, we know we're safe to display the caret
  569. ped->fCaretHidden = FALSE;
  570. CopyRect(&ped->rcFmt, &rc);
  571. if (ped->fSingle)
  572. ped->rcFmt.bottom = min(rc.bottom, rc.top + ped->lineHeight);
  573. else
  574. MLSize(ped, fRedraw);
  575. if (fRedraw) {
  576. NtUserInvalidateRect(ped->hwnd, NULL, TRUE);
  577. // UpdateWindow31(ped->hwnd); Evaluates to NOP in Chicago - Johnl
  578. }
  579. // FE_IME
  580. // ECSize() - call ECImmSetCompositionWindow()
  581. //
  582. // normally this isn't needed because WM_SIZE will cause
  583. // WM_PAINT and the paint handler will take care of IME
  584. // composition window. However when the edit window is
  585. // restored from maximized window and client area is out
  586. // of screen, the window will not be redrawn.
  587. //
  588. if (ped->fFocus && fpImmIsIME(THREAD_HKL())) {
  589. POINT pt;
  590. NtUserGetCaretPos(&pt);
  591. ECImmSetCompositionWindow(ped, pt.x, pt.y);
  592. }
  593. }
  594. /***************************************************************************\
  595. *
  596. * ECSetFont AorW () -
  597. *
  598. * Sets the font used in the edit control. Warning: Memory compaction may
  599. * occur if the font wasn't previously loaded. If the font handle passed
  600. * in is NULL, assume the system font.
  601. *
  602. \***************************************************************************/
  603. void ECSetFont(
  604. PED ped,
  605. HFONT hfont,
  606. BOOL fRedraw)
  607. {
  608. short i;
  609. TEXTMETRIC TextMetrics;
  610. HDC hdc;
  611. HFONT hOldFont=NULL;
  612. UINT wBuffSize;
  613. LPINT lpCharWidthBuff;
  614. DWORD dwMaxOverlapChars;
  615. CHWIDTHINFO cwi;
  616. UINT uExtracharPos;
  617. hdc = NtUserGetDC(ped->hwnd);
  618. if (ped->hFont = hfont) {
  619. //
  620. // Since the default font is the system font, no need to select it in
  621. // if that's what the user wants.
  622. //
  623. if (!(hOldFont = SelectObject(hdc, hfont))) {
  624. hfont = ped->hFont = NULL;
  625. }
  626. //
  627. // Get the metrics and ave char width for the currently selected font
  628. //
  629. //
  630. // Call Vertical font-aware AveWidth compute function...
  631. //
  632. // FE_SB
  633. ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight);
  634. /*
  635. * This might fail when people uses network fonts (or bad fonts).
  636. */
  637. if (ped->aveCharWidth == 0) {
  638. RIPMSG0(RIP_WARNING, "ECSetFont: GdiGetCharDimensions failed");
  639. if (hOldFont != NULL) {
  640. SelectObject(hdc, hOldFont);
  641. }
  642. /*
  643. * We've messed up the ped so let's reset the font.
  644. * Note that we won't recurse more than once because we'll
  645. * pass hfont == NULL.
  646. * Too bad WM_SETFONT doesn't return a value.
  647. */
  648. ECSetFont(ped, NULL, fRedraw);
  649. return;
  650. }
  651. } else {
  652. ped->aveCharWidth = gpsi->cxSysFontChar;
  653. ped->lineHeight = gpsi->cySysFontChar;
  654. TextMetrics = gpsi->tmSysFont;
  655. }
  656. ped->charOverhang = TextMetrics.tmOverhang;
  657. //assume that they don't have any negative widths at all.
  658. ped->wMaxNegA = ped->wMaxNegC = ped->wMaxNegAcharPos = ped->wMaxNegCcharPos = 0;
  659. // Check if Proportional Width Font
  660. //
  661. // NOTE: as SDK doc says about TEXTMETRIC:
  662. // TMPF_FIXED_PITCH
  663. // If this bit is set the font is a variable pitch font. If this bit is clear
  664. // the font is a fixed pitch font. Note very carefully that those meanings are
  665. // the opposite of what the constant name implies.
  666. //
  667. // Thus we have to reverse the value using logical not (fNonPropFont has 1 bit width)
  668. //
  669. ped->fNonPropFont = !(TextMetrics.tmPitchAndFamily & FIXED_PITCH);
  670. // Check for a TrueType font
  671. // Older app OZWIN chokes if we allocate a bigger buffer for TrueType fonts
  672. // So, for apps older than 4.0, no special treatment for TrueType fonts.
  673. if (ped->f40Compat && (TextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
  674. ped->fTrueType = GetCharWidthInfo(hdc, &cwi);
  675. #if DBG
  676. if (!ped->fTrueType) {
  677. RIPMSG0(RIP_WARNING, "ECSetFont: GetCharWidthInfo Failed");
  678. }
  679. #endif
  680. } else {
  681. ped->fTrueType = FALSE;
  682. }
  683. // FE_SB
  684. //
  685. // In DBCS Windows, Edit Control must handle Double Byte Character
  686. // if tmCharSet field of textmetrics is double byte character set
  687. // such as SHIFTJIS_CHARSET(128:Japan), HANGEUL_CHARSET(129:Korea).
  688. //
  689. // We call ECGetDBCSVector even when fAnsi is false so that we could
  690. // treat ped->fAnsi and ped->fDBCS indivisually. I changed ECGetDBCSVector
  691. // function so that it returns 0 or 1, because I would like to set ped->fDBCS
  692. // bit field here.
  693. //
  694. ped->fDBCS = ECGetDBCSVector(ped,hdc,TextMetrics.tmCharSet);
  695. ped->charSet = TextMetrics.tmCharSet;
  696. if (ped->fDBCS) {
  697. //
  698. // Free the character width buffer if ped->fDBCS.
  699. //
  700. // I expect single GetTextExtentPoint call is faster than multiple
  701. // GetTextExtentPoint call (because the graphic engine has a cache buffer).
  702. // See editec.c/ECTabTheTextOut().
  703. //
  704. if (ped->charWidthBuffer) {
  705. UserLocalFree(ped->charWidthBuffer);
  706. ped->charWidthBuffer = NULL;
  707. }
  708. //
  709. // if FullWidthChar : HalfWidthChar == 2 : 1....
  710. //
  711. // TextMetrics.tmMaxCharWidth = FullWidthChar width
  712. // ped->aveCharWidth = HalfWidthChar width
  713. //
  714. if (ped->fNonPropFont &&
  715. ((ped->aveCharWidth * 2) == TextMetrics.tmMaxCharWidth)) {
  716. ped->fNonPropDBCS = TRUE;
  717. } else {
  718. ped->fNonPropDBCS = FALSE;
  719. }
  720. } else {
  721. //
  722. // Since the font has changed, let us obtain and save the character width
  723. // info for this font.
  724. //
  725. // First left us find out if the maximum chars that can overlap due to
  726. // negative widths. Since we can't access USER globals, we make a call here.
  727. //
  728. if (!(ped->fSingle || ped->pLpkEditCallout)) { // Is this a multiline edit control with no LPK present?
  729. //
  730. // For multiline edit controls, we maintain a buffer that contains
  731. // the character width information.
  732. //
  733. wBuffSize = (ped->fTrueType) ? (CHAR_WIDTH_BUFFER_LENGTH * sizeof(ABC)) :
  734. (CHAR_WIDTH_BUFFER_LENGTH * sizeof(int));
  735. if (ped->charWidthBuffer) { /* If buffer already present */
  736. lpCharWidthBuff = ped->charWidthBuffer;
  737. ped->charWidthBuffer = UserLocalReAlloc(lpCharWidthBuff, wBuffSize, HEAP_ZERO_MEMORY);
  738. if (ped->charWidthBuffer == NULL) {
  739. UserLocalFree((HANDLE)lpCharWidthBuff);
  740. }
  741. } else {
  742. ped->charWidthBuffer = UserLocalAlloc(HEAP_ZERO_MEMORY, wBuffSize);
  743. }
  744. if (ped->charWidthBuffer != NULL) {
  745. if (ped->fTrueType) {
  746. ped->fTrueType = GetNegABCwidthInfo(ped, hdc);
  747. }
  748. /*
  749. * It is possible that the above attempts could have failed and reset
  750. * the value of fTrueType. So, let us check that value again.
  751. */
  752. if (!ped->fTrueType) {
  753. if (!GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, ped->charWidthBuffer)) {
  754. UserLocalFree((HANDLE)ped->charWidthBuffer);
  755. ped->charWidthBuffer=NULL;
  756. } else {
  757. /*
  758. * We need to subtract out the overhang associated with
  759. * each character since GetCharWidth includes it...
  760. */
  761. for (i=0;i < CHAR_WIDTH_BUFFER_LENGTH;i++)
  762. ped->charWidthBuffer[i] -= ped->charOverhang;
  763. }
  764. }
  765. } /* if (ped->charWidthBuffer != NULL) */
  766. } /* if (!ped->fSingle) */
  767. } /* if (ped->fDBCS) */
  768. {
  769. /*
  770. * Calculate MaxNeg A C metrics
  771. */
  772. dwMaxOverlapChars = GetMaxOverlapChars();
  773. if (ped->fTrueType) {
  774. if (cwi.lMaxNegA < 0)
  775. ped->wMaxNegA = -cwi.lMaxNegA;
  776. else
  777. ped->wMaxNegA = 0;
  778. if (cwi.lMaxNegC < 0)
  779. ped->wMaxNegC = -cwi.lMaxNegC;
  780. else
  781. ped->wMaxNegC = 0;
  782. if (cwi.lMinWidthD != 0) {
  783. ped->wMaxNegAcharPos = (ped->wMaxNegA + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
  784. ped->wMaxNegCcharPos = (ped->wMaxNegC + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
  785. if (ped->wMaxNegA + ped->wMaxNegC > (UINT)cwi.lMinWidthD) {
  786. uExtracharPos = (ped->wMaxNegA + ped->wMaxNegC - 1) / cwi.lMinWidthD;
  787. ped->wMaxNegAcharPos += uExtracharPos;
  788. ped->wMaxNegCcharPos += uExtracharPos;
  789. }
  790. } else {
  791. ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
  792. ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
  793. }
  794. } else if (ped->charOverhang != 0) {
  795. /*
  796. * Some bitmaps fonts (i.e., italic) have under/overhangs;
  797. * this is pretty much like having negative A and C widths.
  798. */
  799. ped->wMaxNegA = ped->wMaxNegC = ped->charOverhang;
  800. ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
  801. ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
  802. }
  803. } /* if (ped->fDBCS) */
  804. if (!hfont) {
  805. //
  806. // We are getting the stats for the system font so update the system
  807. // font fields in the ed structure since we use these when calculating
  808. // some spacing.
  809. //
  810. ped->cxSysCharWidth = ped->aveCharWidth;
  811. ped->cySysCharHeight= ped->lineHeight;
  812. } else if (hOldFont)
  813. SelectObject(hdc, hOldFont);
  814. if (ped->fFocus) {
  815. //
  816. // Update the caret.
  817. //
  818. NtUserHideCaret(ped->hwnd);
  819. NtUserDestroyCaret();
  820. if (ped->pLpkEditCallout) {
  821. ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(), ped->lineHeight, 0);
  822. } else {
  823. NtUserCreateCaret(ped->hwnd, (HBITMAP)NULL, ECGetCaretWidth(), ped->lineHeight);
  824. }
  825. NtUserShowCaret(ped->hwnd);
  826. }
  827. ReleaseDC(ped->hwnd, hdc);
  828. //
  829. // Update password character.
  830. //
  831. if (ped->charPasswordChar)
  832. ECSetPasswordChar(ped, ped->charPasswordChar);
  833. //
  834. // If it is a TrueType font and it's a new app, set both the margins at the
  835. // max negative width values for all types of the edit controls.
  836. // (NOTE: Can't use ped->f40Compat here because edit-controls inside dialog
  837. // boxes without DS_LOCALEDIT style are always marked as 4.0 compat.
  838. // This is the fix for NETBENCH 3.0)
  839. //
  840. if (ped->fTrueType && (GETAPPVER() >= VER40))
  841. if (ped->fDBCS) {
  842. // For DBCS TrueType Font, we calc margin from ABC width.
  843. ECCalcMarginForDBCSFont(ped, fRedraw);
  844. } else {
  845. ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  846. MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO), fRedraw);
  847. }
  848. //
  849. // We need to calc maxPixelWidth when font changes.
  850. // If the word-wrap is ON, then this is done in MLSize() called later.
  851. //
  852. if((!ped->fSingle) && (!ped->fWrap))
  853. MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL);
  854. //
  855. // Recalc the layout.
  856. //
  857. ECSize(ped, NULL, fRedraw);
  858. if ( ped->fFocus && fpImmIsIME(THREAD_HKL()) ) {
  859. ECImmSetCompositionFont( ped );
  860. }
  861. }
  862. /***************************************************************************\
  863. *
  864. * ECIsCharNumeric AorW () -
  865. *
  866. * Tests whether the character entered is a numeral.
  867. * For multiline and singleline edit controls with the ES_NUMBER style.
  868. *
  869. \***************************************************************************/
  870. BOOL ECIsCharNumeric(
  871. PED ped,
  872. DWORD keyPress)
  873. {
  874. WORD wCharType;
  875. if (ped->fAnsi) {
  876. char ch = (char)keyPress;
  877. LCID lcid = (LCID)((ULONG_PTR)THREAD_HKL() & 0xFFFF);
  878. GetStringTypeA(lcid, CT_CTYPE1, &ch, 1, &wCharType);
  879. } else {
  880. WCHAR wch = (WCHAR)keyPress;
  881. GetStringTypeW(CT_CTYPE1, &wch, 1, &wCharType);
  882. }
  883. return (wCharType & C1_DIGIT ? TRUE : FALSE);
  884. }
  885. /***************************************************************************\
  886. *
  887. * ECEnableDisableIME( PED ped )
  888. *
  889. *
  890. * xx/xx/9x by somebody Created for Win95
  891. * xx/xx/95 by kazum Ported to NT-J 3.51
  892. * 04/15/96 by takaok Ported to NT 4.0
  893. *
  894. \***************************************************************************/
  895. VOID ECEnableDisableIME( PED ped )
  896. {
  897. if ( ped->fReadOnly || ped->charPasswordChar ) {
  898. //
  899. // IME should be disabled
  900. //
  901. HIMC hImc;
  902. hImc = fpImmGetContext( ped->hwnd );
  903. if ( hImc != NULL_HIMC ) {
  904. fpImmReleaseContext( ped->hwnd, hImc );
  905. ped->hImcPrev = fpImmAssociateContext( ped->hwnd, NULL_HIMC );
  906. }
  907. } else {
  908. //
  909. // IME should be enabled
  910. //
  911. if ( ped->hImcPrev != NULL_HIMC ) {
  912. ped->hImcPrev = fpImmAssociateContext( ped->hwnd, ped->hImcPrev );
  913. //
  914. // Font and the caret position might be changed while
  915. // IME was being disabled. Set those now if the window
  916. // has the focus.
  917. //
  918. if ( ped->fFocus ) {
  919. POINT pt;
  920. ECImmSetCompositionFont( ped );
  921. NtUserGetCaretPos( &pt );
  922. ECImmSetCompositionWindow( ped, pt.x, pt.y );
  923. }
  924. }
  925. }
  926. ECInitInsert(ped, THREAD_HKL());
  927. }
  928. /***************************************************************************\
  929. *
  930. * ECImmSetCompositionWindow( PED ped, LONG x, LONG y )
  931. *
  932. * xx/xx/9x by somebody Created for Win95
  933. * xx/xx/95 by kazum Ported to NT-J 3.51
  934. * 04/15/96 by takaok Ported to NT 4.0
  935. \***************************************************************************/
  936. VOID ECImmSetCompositionWindow( PED ped, LONG x, LONG y )
  937. {
  938. COMPOSITIONFORM cf;
  939. COMPOSITIONFORM cft;
  940. RECT rcScreenWindow;
  941. HIMC hImc;
  942. hImc = fpImmGetContext( ped->hwnd );
  943. if ( hImc != NULL_HIMC ) {
  944. if ( ped->fFocus ) {
  945. GetWindowRect( ped->hwnd, &rcScreenWindow);
  946. // assuming RECT.left is the first and and RECT.top is the second field
  947. MapWindowPoints( ped->hwnd, HWND_DESKTOP, (LPPOINT)&rcScreenWindow, 2);
  948. if (ped->fInReconversion) {
  949. DWORD dwPoint = (DWORD)(ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_POSFROMCHAR, ped->ichMinSel, 0);
  950. x = GET_X_LPARAM(dwPoint);
  951. y = GET_Y_LPARAM(dwPoint);
  952. RIPMSG2(RIP_WARNING, "ECImmSetCompositionWindow: fInReconversion (%d,%d)", x, y);
  953. }
  954. //
  955. // The window currently has the focus.
  956. //
  957. if (ped->fSingle) {
  958. //
  959. // Single line edit control.
  960. //
  961. cf.dwStyle = CFS_POINT;
  962. cf.ptCurrentPos.x = x;
  963. cf.ptCurrentPos.y = y;
  964. SetRectEmpty(&cf.rcArea);
  965. } else {
  966. //
  967. // Multi line edit control.
  968. //
  969. cf.dwStyle = CFS_RECT;
  970. cf.ptCurrentPos.x = x;
  971. cf.ptCurrentPos.y = y;
  972. cf.rcArea = ped->rcFmt;
  973. }
  974. fpImmGetCompositionWindow( hImc, &cft );
  975. if ( (!RtlEqualMemory(&cf,&cft,sizeof(COMPOSITIONFORM))) ||
  976. (ped->ptScreenBounding.x != rcScreenWindow.left) ||
  977. (ped->ptScreenBounding.y != rcScreenWindow.top) ) {
  978. ped->ptScreenBounding.x = rcScreenWindow.left;
  979. ped->ptScreenBounding.y = rcScreenWindow.top;
  980. fpImmSetCompositionWindow( hImc, &cf );
  981. }
  982. }
  983. fpImmReleaseContext( ped->hwnd, hImc );
  984. }
  985. }
  986. /***************************************************************************\
  987. *
  988. * ECImmSetCompositionFont( PED ped )
  989. *
  990. * xx/xx/9x by somebody Created for Win95
  991. * xx/xx/95 by kazum Ported to NT-J 3.51
  992. * 04/15/96 by takaok Ported to NT 4.0
  993. \***************************************************************************/
  994. VOID ECImmSetCompositionFont( PED ped )
  995. {
  996. HIMC hImc;
  997. LOGFONTW lf;
  998. if ( (hImc = fpImmGetContext( ped->hwnd )) != NULL_HIMC ) {
  999. if (ped->hFont) {
  1000. GetObjectW( ped->hFont,
  1001. sizeof(LOGFONTW),
  1002. (LPLOGFONTW)&lf);
  1003. } else {
  1004. GetObjectW( GetStockObject(SYSTEM_FONT),
  1005. sizeof(LOGFONTW),
  1006. (LPLOGFONTW)&lf);
  1007. }
  1008. fpImmSetCompositionFontW( hImc, &lf );
  1009. fpImmReleaseContext( ped->hwnd, hImc );
  1010. }
  1011. }
  1012. /***************************************************************************\
  1013. *
  1014. * ECInitInsert( PED ped, HKL hkl )
  1015. *
  1016. * this function is called when:
  1017. * 1) a edit control window is initialized
  1018. * 2) active keyboard layout of current thread is changed
  1019. * 3) read only attribute of this edit control is changed
  1020. *
  1021. * 04/15/96 by takaok Created
  1022. \***************************************************************************/
  1023. VOID ECInitInsert( PED ped, HKL hkl )
  1024. {
  1025. ped->fKorea = FALSE;
  1026. ped->fInsertCompChr = FALSE;
  1027. ped->fNoMoveCaret = FALSE;
  1028. ped->fResultProcess = FALSE;
  1029. if ( fpImmIsIME(hkl) ) {
  1030. if ( PRIMARYLANGID(LOWORD(HandleToUlong(hkl))) == LANG_KOREAN ) {
  1031. ped->fKorea = TRUE;
  1032. }
  1033. //
  1034. // LATER:this flag should be set based on the IME caps
  1035. // retrieved from IME. (Such IME caps should be defined)
  1036. // For now, we can safely assume that only Korean IMEs
  1037. // set CS_INSERTCHAR.
  1038. //
  1039. if ( ped->fKorea ) {
  1040. ped->fInsertCompChr = TRUE;
  1041. }
  1042. }
  1043. //
  1044. // if we had a composition character, the shape of caret
  1045. // is changed. We need to reset the caret shape.
  1046. //
  1047. if ( ped->fReplaceCompChr ) {
  1048. ped->fReplaceCompChr = FALSE;
  1049. ECSetCaretHandler( ped );
  1050. }
  1051. }
  1052. /***************************************************************************\
  1053. *
  1054. * ECSetCaretHandler( PED ped )
  1055. *
  1056. * History:
  1057. * 07/16/96 by takaok ported from NT 3.51
  1058. *
  1059. \***************************************************************************/
  1060. void ECSetCaretHandler(PED ped)
  1061. {
  1062. HDC hdc;
  1063. SIZE size;
  1064. PSTR pText;
  1065. // if (!ped->fInsertCompChr || ped->fReadOnly)
  1066. // return;
  1067. // In any case destroy caret beforehand otherwise SetCaretPos()
  1068. // will get crazy.. win95d-B#992,B#2370
  1069. //
  1070. if (ped->fFocus) {
  1071. NtUserHideCaret(ped->hwnd);
  1072. DestroyCaret();
  1073. if ( ped->fReplaceCompChr ) {
  1074. hdc = ECGetEditDC(ped, TRUE );
  1075. pText = ECLock(ped);
  1076. if ( ped->fAnsi)
  1077. GetTextExtentPointA(hdc, pText + ped->ichCaret, 2, &size);
  1078. else
  1079. GetTextExtentPointW(hdc, (LPWSTR)pText + ped->ichCaret, 1, &size);
  1080. ECUnlock(ped);
  1081. ECReleaseEditDC(ped, hdc, TRUE);
  1082. CreateCaret(ped->hwnd, (HBITMAP)NULL, size.cx, ped->lineHeight);
  1083. }
  1084. else {
  1085. CreateCaret(ped->hwnd,
  1086. (HBITMAP)NULL,
  1087. (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
  1088. ped->lineHeight);
  1089. }
  1090. hdc = ECGetEditDC(ped, TRUE );
  1091. if ( ped->fSingle )
  1092. SLSetCaretPosition( ped, hdc );
  1093. else
  1094. MLSetCaretPosition( ped, hdc );
  1095. ECReleaseEditDC(ped, hdc, TRUE);
  1096. NtUserShowCaret(ped->hwnd);
  1097. }
  1098. }
  1099. /***************************************************************************\
  1100. *
  1101. * LONG ECImeCompoistion( PED ped, WPARAM wParam, LPARAM lParam )
  1102. *
  1103. * WM_IME_COMPOSITION handler for Korean IME
  1104. *
  1105. * History:
  1106. \***************************************************************************/
  1107. extern void MLReplaceSel(PED, LPSTR);
  1108. #define GET_COMPOSITION_STRING (ped->fAnsi ? fpImmGetCompositionStringA : fpImmGetCompositionStringW)
  1109. BOOL FAR PASCAL ECResultStrHandler(PED ped)
  1110. {
  1111. HIMC himc;
  1112. LPSTR lpStr;
  1113. LONG dwLen;
  1114. ped->fInsertCompChr = FALSE; // clear the state
  1115. ped->fNoMoveCaret = FALSE;
  1116. if ((himc = fpImmGetContext(ped->hwnd)) == 0) {
  1117. return FALSE;
  1118. }
  1119. dwLen = GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, NULL, 0);
  1120. if (dwLen == 0) {
  1121. fpImmReleaseContext(ped->hwnd, himc);
  1122. return FALSE;
  1123. }
  1124. dwLen *= ped->cbChar;
  1125. dwLen += ped->cbChar;
  1126. lpStr = (LPSTR)UserGlobalAlloc(GPTR, dwLen);
  1127. if (lpStr == NULL) {
  1128. fpImmReleaseContext(ped->hwnd, himc);
  1129. return FALSE;
  1130. }
  1131. GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, lpStr, dwLen);
  1132. if (ped->fSingle) {
  1133. SLReplaceSel(ped, lpStr);
  1134. } else {
  1135. MLReplaceSel(ped, lpStr);
  1136. }
  1137. UserGlobalFree((HGLOBAL)lpStr);
  1138. fpImmReleaseContext(ped->hwnd, himc);
  1139. ped->fReplaceCompChr = FALSE;
  1140. ped->fNoMoveCaret = FALSE;
  1141. ped->fResultProcess = FALSE;
  1142. ECSetCaretHandler(ped);
  1143. return TRUE;
  1144. }
  1145. LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
  1146. {
  1147. INT ich;
  1148. LRESULT lReturn = 1;
  1149. HDC hdc;
  1150. BOOL fSLTextUpdated = FALSE;
  1151. ICH iResult;
  1152. HIMC hImc;
  1153. BYTE TextBuf[4];
  1154. if (!ped->fInsertCompChr) {
  1155. if (lParam & GCS_RESULTSTR) {
  1156. ECInOutReconversionMode(ped, FALSE);
  1157. if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) {
  1158. ResultAtOnce:
  1159. ECResultStrHandler(ped);
  1160. lParam &= ~GCS_RESULTSTR;
  1161. }
  1162. }
  1163. return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
  1164. }
  1165. // In case of Ansi edit control, the length of minimum composition string
  1166. // is 2. Check here maximum byte of edit control.
  1167. if( ped->fAnsi && ped->cchTextMax == 1 ) {
  1168. HIMC hImc;
  1169. hImc = fpImmGetContext( ped->hwnd );
  1170. fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
  1171. fpImmReleaseContext( ped->hwnd, hImc );
  1172. NtUserMessageBeep(MB_ICONEXCLAMATION);
  1173. return lReturn;
  1174. }
  1175. // Don't move this after CS_NOMOVECARET check.
  1176. // In case if skip the message, fNoMoveCaret should not be set.
  1177. if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) {
  1178. // Now we're in result processing. GCS_RESULTSTR ends up
  1179. // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
  1180. // the message(s) will come later than this CS_INSERTCHAR
  1181. // message. This composition character should be handled
  1182. // after the WM_CHAR message(s).
  1183. //
  1184. if(ped->fAnsi)
  1185. PostMessageA(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1186. else
  1187. PostMessageW(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1188. ped->fResultProcess = FALSE;
  1189. return lReturn;
  1190. }
  1191. //
  1192. // If fReplaceCompChr is TRUE, we change the shape of caret. A block
  1193. // caret is displayed on the composition character. From the user's
  1194. // point of view, there is no difference if the caret is before the
  1195. // composition character or after the composition character. When
  1196. // the composition character is finalized, the insertion point should
  1197. // be moved to after the character, any way. Therefore checking
  1198. // CS_NOMOVECARET bit doesn't make sense in our current implementation.
  1199. // [takaok]
  1200. //
  1201. #if 0
  1202. if (lParam & CS_NOMOVECARET)
  1203. ped->fNoMoveCaret=TRUE; // stick to current caret pos.
  1204. else
  1205. ped->fNoMoveCaret=FALSE;
  1206. #endif
  1207. if (lParam & GCS_RESULTSTR) {
  1208. if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) {
  1209. goto ResultAtOnce;
  1210. }
  1211. ped->fResultProcess=TRUE;
  1212. if ( ped->fReplaceCompChr ) {
  1213. //
  1214. // we have a DBCS character to be replaced.
  1215. // let's delete it before inserting the new one.
  1216. //
  1217. ich = (ped->fAnsi) ? 2 : 1;
  1218. ped->fReplaceCompChr = FALSE;
  1219. ped->ichMaxSel = min(ped->ichCaret + ich, ped->cch);
  1220. ped->ichMinSel = ped->ichCaret;
  1221. if ( ECDeleteText( ped ) > 0 ) {
  1222. if ( ped->fSingle ) {
  1223. //
  1224. // Update the display
  1225. //
  1226. ECNotifyParent(ped, EN_UPDATE);
  1227. hdc = ECGetEditDC(ped,FALSE);
  1228. SLDrawText(ped, hdc, 0);
  1229. ECReleaseEditDC(ped,hdc,FALSE);
  1230. //
  1231. // Tell parent our text contents changed.
  1232. //
  1233. ECNotifyParent(ped, EN_CHANGE);
  1234. }
  1235. }
  1236. ECSetCaretHandler( ped );
  1237. }
  1238. } else if(lParam & CS_INSERTCHAR) {
  1239. //
  1240. // If we are in the middle of a mousedown command, don't do anything.
  1241. //
  1242. if (ped->fMouseDown) {
  1243. return lReturn;
  1244. }
  1245. //
  1246. // We can safely assume that interimm character is always DBCS.
  1247. //
  1248. ich = ( ped->fAnsi ) ? 2 : 1;
  1249. if ( ped->fReplaceCompChr ) {
  1250. //
  1251. // we have a character to be replaced.
  1252. // let's delete it before inserting the new one.
  1253. // when we have a composition characters, the
  1254. // caret is placed before the composition character.
  1255. //
  1256. ped->ichMaxSel = min(ped->ichCaret+ich, ped->cch);
  1257. ped->ichMinSel = ped->ichCaret;
  1258. }
  1259. //
  1260. // let's delete current selected text or composition character
  1261. //
  1262. if ( ped->fSingle ) {
  1263. if ( ECDeleteText( ped ) > 0 ) {
  1264. fSLTextUpdated = TRUE;
  1265. }
  1266. } else {
  1267. MLDeleteText( ped );
  1268. }
  1269. //
  1270. // When the composition charcter is canceled, IME may give us NULL wParam,
  1271. // with CS_INSERTCHAR flag on. We shouldn't insert a NULL character.
  1272. //
  1273. if ( wParam != 0 ) {
  1274. if ( ped->fAnsi ) {
  1275. TextBuf[0] = HIBYTE(LOWORD(wParam)); // leading byte
  1276. TextBuf[1] = LOBYTE(LOWORD(wParam)); // trailing byte
  1277. TextBuf[2] = '\0';
  1278. } else {
  1279. TextBuf[0] = LOBYTE(LOWORD(wParam));
  1280. TextBuf[1] = HIBYTE(LOWORD(wParam));
  1281. TextBuf[2] = '\0';
  1282. TextBuf[3] = '\0';
  1283. }
  1284. if ( ped->fSingle ) {
  1285. iResult = SLInsertText( ped, (LPSTR)TextBuf, ich );
  1286. if (iResult == 0) {
  1287. /*
  1288. * Couldn't insert the text, for e.g. the text exceeded the limit.
  1289. */
  1290. NtUserMessageBeep(0);
  1291. } else if (iResult > 0) {
  1292. /*
  1293. * Remember we need to update the text.
  1294. */
  1295. fSLTextUpdated = TRUE;
  1296. }
  1297. } else {
  1298. iResult = MLInsertText( ped, (LPSTR)TextBuf, ich, TRUE);
  1299. }
  1300. if ( iResult > 0 ) {
  1301. //
  1302. // ped->fReplaceCompChr will be reset:
  1303. //
  1304. // 1) when the character is finalized.
  1305. // we will receive GCS_RESULTSTR
  1306. //
  1307. // 2) when the character is canceled.
  1308. //
  1309. // we will receive WM_IME_COMPOSITION|CS_INSERTCHAR
  1310. // with wParam == 0 (in case of user types backspace
  1311. // at the first element of composition character).
  1312. //
  1313. // or
  1314. //
  1315. // we will receive WM_IME_ENDCOMPOSITION message
  1316. //
  1317. ped->fReplaceCompChr = TRUE;
  1318. //
  1319. // Caret should be placed BEFORE the composition
  1320. // character.
  1321. //
  1322. ped->ichCaret = max( 0, (INT)(ped->ichCaret - ich));
  1323. ECSetCaretHandler( ped );
  1324. } else {
  1325. //
  1326. // We failed to insert a character. We might run out
  1327. // of memory, or reached to the text size limit. let's
  1328. // cancel the composition character.
  1329. //
  1330. hImc = fpImmGetContext(ped->hwnd);
  1331. fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
  1332. fpImmReleaseContext(ped->hwnd, hImc);
  1333. ped->fReplaceCompChr = FALSE;
  1334. ECSetCaretHandler( ped );
  1335. }
  1336. } else {
  1337. //
  1338. // the composition character is canceled.
  1339. //
  1340. ped->fReplaceCompChr = FALSE;
  1341. ECSetCaretHandler( ped );
  1342. }
  1343. //
  1344. // We won't notify parent the text change
  1345. // because the composition character has
  1346. // not been finalized.
  1347. //
  1348. if ( fSLTextUpdated ) {
  1349. //
  1350. // Update the display
  1351. //
  1352. ECNotifyParent(ped, EN_UPDATE);
  1353. hdc = ECGetEditDC(ped,FALSE);
  1354. if ( ped->fReplaceCompChr ) {
  1355. //
  1356. // move back the caret to the original position
  1357. // temporarily so that our new block cursor can
  1358. // be located within the visible area of window.
  1359. //
  1360. ped->ichCaret = min( ped->cch, ped->ichCaret + ich);
  1361. SLScrollText(ped, hdc);
  1362. ped->ichCaret = max( 0, (INT)(ped->ichCaret - ich));
  1363. } else {
  1364. SLScrollText(ped, hdc);
  1365. }
  1366. SLDrawText(ped, hdc, 0);
  1367. ECReleaseEditDC(ped,hdc,FALSE);
  1368. //
  1369. // Tell parent our text contents changed.
  1370. //
  1371. ECNotifyParent(ped, EN_CHANGE);
  1372. }
  1373. return lReturn;
  1374. }
  1375. return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
  1376. }
  1377. #ifdef LATER // fyi: window 98 equiv.
  1378. LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
  1379. {
  1380. INT ich;
  1381. LRESULT lReturn = 1;
  1382. HDC hdc;
  1383. BOOL fSLTextUpdated = FALSE;
  1384. ICH iResult;
  1385. HIMC hImc;
  1386. BYTE TextBuf[4];
  1387. // In case of Ansi edit control, the length of minimum composition string
  1388. // is 2. Check here maximum byte of edit control.
  1389. if( ped->fAnsi && ped->cchTextMax == 1 ) {
  1390. HIMC hImc;
  1391. hImc = fpImmGetContext( ped->hwnd );
  1392. fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
  1393. fpImmReleaseContext( ped->hwnd, hImc );
  1394. MessageBeep(MB_ICONEXCLAMATION);
  1395. return lReturn;
  1396. }
  1397. // Don't move this after CS_NOMOVECARET check.
  1398. // In case if skip the message, fNoMoveCaret should not be set.
  1399. if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) {
  1400. // Now we're in result processing. GCS_RESULTSTR ends up
  1401. // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
  1402. // the message(s) will come later than this CS_INSERTCHAR
  1403. // message. This composition character should be handled
  1404. // after the WM_CHAR message(s).
  1405. //
  1406. (ped->fAnsi ? PostMessageA : PostMessageW)(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1407. ped->fResultProcess = FALSE;
  1408. return lReturn;
  1409. }
  1410. ped->fNoMoveCaret = (lParam & CS_NOMOVECARET) != 0;
  1411. if (lParam & GCS_RESULTSTR) {
  1412. ECInOutReconversionMode(ped, FALSE);
  1413. if (ped->wImeStatus & EIMS_GETCOMPSTRATONCE) {
  1414. ECGetCompStrAtOnce(ped);
  1415. goto PassToDefaultWindowProc;
  1416. }
  1417. // Getting into result processing
  1418. ped->fResultProcess = TRUE;
  1419. }
  1420. else if (lParam & CS_INSERTCHAR) {
  1421. ped->fInsertCompChr = TRUE; // Process this composition character.
  1422. (ped->fSingleLine ? SLChar : MLChar)(ped, wParam, 0);
  1423. if (ped->fInsretCompChr) {
  1424. ped->fReplaceCompChr = TRUE; // The next character will replace this.
  1425. ped->fInsertCompChr = FALSE; // Clear the state for the next character.
  1426. }
  1427. ECSetCaretHandler(ped);
  1428. return 0;
  1429. }
  1430. PassToDefaultWindowProc:
  1431. return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
  1432. }
  1433. #endif
  1434. /***************************************************************************\
  1435. *
  1436. * BOOL HanjaKeyHandler( PED ped )
  1437. *
  1438. * VK_HANJA handler - Korean only
  1439. *
  1440. * History: July 15,1996 takaok ported from NT 3.51
  1441. \***************************************************************************/
  1442. BOOL HanjaKeyHandler( PED ped )
  1443. {
  1444. BOOL changeSelection = FALSE;
  1445. if (ped->fKorea && !ped->fReadOnly) {
  1446. ICH oldCaret = ped->ichCaret;
  1447. if (ped->fReplaceCompChr)
  1448. return FALSE;
  1449. if (ped->ichMinSel < ped->ichMaxSel)
  1450. ped->ichCaret = ped->ichMinSel;
  1451. if (!ped->cch || ped->cch == ped->ichCaret) {
  1452. ped->ichCaret = oldCaret;
  1453. NtUserMessageBeep(MB_ICONEXCLAMATION);
  1454. return FALSE;
  1455. }
  1456. if (ped->fAnsi) {
  1457. if (fpImmEscapeA(THREAD_HKL(), fpImmGetContext(ped->hwnd),
  1458. IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) {
  1459. changeSelection = TRUE;
  1460. }
  1461. else
  1462. ped->ichCaret = oldCaret;
  1463. ECUnlock(ped);
  1464. }
  1465. else {
  1466. if (fpImmEscapeW(THREAD_HKL(), fpImmGetContext(ped->hwnd),
  1467. IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) {
  1468. changeSelection = TRUE;
  1469. }
  1470. else
  1471. ped->ichCaret = oldCaret;
  1472. ECUnlock(ped);
  1473. }
  1474. }
  1475. return changeSelection;
  1476. }
  1477. //////////////////////////////////////////////////////////////////////////////
  1478. // EcImeRequestHandler()
  1479. //
  1480. // Handles WM_IME_REQUEST message originated by IME
  1481. //
  1482. // Histroy:
  1483. // 27-Mar-97 Hiroyama Created
  1484. //////////////////////////////////////////////////////////////////////////////
  1485. #ifdef CUAS_ENABLE
  1486. #define MAX_ECDOCFEED 20
  1487. ICH EcImeGetDocFeedMin(PED ped, LPSTR lpstr)
  1488. {
  1489. ICH ich;
  1490. if (!IS_CICERO_ENABLED())
  1491. return ped->ichMinSel;
  1492. if (ped->ichMinSel > MAX_ECDOCFEED) {
  1493. ich = ped->ichMinSel - MAX_ECDOCFEED;
  1494. ich = ECAdjustIch(ped, lpstr, ich);
  1495. } else {
  1496. ich = 0;
  1497. }
  1498. return ich;
  1499. }
  1500. ICH EcImeGetDocFeedMax(PED ped, LPSTR lpstr)
  1501. {
  1502. ICH ich;
  1503. if (!IS_CICERO_ENABLED())
  1504. return ped->ichMinSel;
  1505. if ((ped->cch - ped->ichMaxSel) > MAX_ECDOCFEED) {
  1506. ich = ped->ichMaxSel + MAX_ECDOCFEED;
  1507. ich = ECAdjustIch(ped, lpstr, ich);
  1508. } else {
  1509. ich = ped->cch;
  1510. }
  1511. return ich;
  1512. }
  1513. #endif // CUAS_ENABLE
  1514. LRESULT EcImeRequestHandler(PED ped, WPARAM dwSubMsg, LPARAM lParam)
  1515. {
  1516. LRESULT lreturn = 0L;
  1517. switch (dwSubMsg) {
  1518. case IMR_CONFIRMRECONVERTSTRING:
  1519. #if !defined(CUAS_ENABLE)
  1520. // Edit control does not allow IME to change it.
  1521. break;
  1522. #else
  1523. // Edit control does not allow IME to change it if it is not CUAS.
  1524. if (!IS_CICERO_ENABLED())
  1525. return 0L;
  1526. //
  1527. // CHECK VERSION of the structure
  1528. //
  1529. if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0) {
  1530. RIPMSG1(RIP_WARNING, "EcImeRequestHandler: RECONVERTSTRING dwVersion is not expected.",
  1531. ((LPRECONVERTSTRING)lParam)->dwVersion);
  1532. return 0L;
  1533. }
  1534. if (lParam && ped && ped->fFocus && ped->hText && fpImmIsIME(THREAD_HKL())) {
  1535. LPVOID lpSrc;
  1536. lpSrc = ECLock(ped);
  1537. if (lpSrc == NULL) {
  1538. RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed.");
  1539. } else {
  1540. LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
  1541. ICH ichStart;
  1542. ICH ichEnd;
  1543. UINT cchLen;
  1544. ichStart = EcImeGetDocFeedMin(ped, lpSrc);
  1545. ichEnd = EcImeGetDocFeedMax(ped, lpSrc);
  1546. UserAssert(ichEnd >= ichStart);
  1547. cchLen = ichEnd - ichStart; // holds character count.
  1548. ECUnlock(ped);
  1549. if (lpRCS->dwStrLen != cchLen) {
  1550. RIPMSG0(RIP_WARNING, "EcImeRequestHandler: the given string length is not expected.");
  1551. } else {
  1552. ICH ichSelStart;
  1553. ICH ichSelEnd;
  1554. ichSelStart = ichStart + (lpRCS->dwCompStrOffset / ped->cbChar);
  1555. ichSelEnd = ichSelStart + lpRCS->dwCompStrLen;
  1556. (ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_SETSEL, ichSelStart, ichSelEnd);
  1557. lreturn = 1L;
  1558. }
  1559. }
  1560. }
  1561. break;
  1562. #endif // CUAS_ENABLE
  1563. case IMR_RECONVERTSTRING:
  1564. //
  1565. // CHECK VERSION of the structure
  1566. //
  1567. if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0) {
  1568. RIPMSG1(RIP_WARNING, "EcImeRequestHandler: RECONVERTSTRING dwVersion is not expected.",
  1569. ((LPRECONVERTSTRING)lParam)->dwVersion);
  1570. return 0L;
  1571. }
  1572. if (ped && ped->fFocus && ped->hText && fpImmIsIME(THREAD_HKL())) {
  1573. #if !defined(CUAS_ENABLE)
  1574. UINT cchLen = ped->ichMaxSel - ped->ichMinSel; // holds character count.
  1575. #else
  1576. ICH ichStart;
  1577. ICH ichEnd;
  1578. UINT cchLen;
  1579. UINT cchSelLen;
  1580. LPVOID lpSrc;
  1581. lpSrc = ECLock(ped);
  1582. if (lpSrc == NULL) {
  1583. RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed.");
  1584. return 0L;
  1585. }
  1586. ichStart = EcImeGetDocFeedMin(ped, lpSrc);
  1587. ichEnd = EcImeGetDocFeedMax(ped, lpSrc);
  1588. UserAssert(ichEnd >= ichStart);
  1589. cchLen = ichEnd - ichStart; // holds character count.
  1590. cchSelLen = ped->ichMaxSel - ped->ichMinSel; // holds character count.
  1591. #endif
  1592. if (cchLen == 0) {
  1593. #if defined(CUAS_ENABLE)
  1594. ECUnlock(ped);
  1595. #endif
  1596. // if we have no selection,
  1597. // just return 0.
  1598. break;
  1599. }
  1600. UserAssert(ped->cbChar == sizeof(BYTE) || ped->cbChar == sizeof(WCHAR));
  1601. // This Edit Control has selection.
  1602. if (lParam == 0) {
  1603. //
  1604. // IME just want to get required size for buffer.
  1605. // cchLen + 1 is needed to reserve room for trailing L'\0'.
  1606. // ~~~~
  1607. lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
  1608. #if defined(CUAS_ENABLE)
  1609. ECUnlock(ped);
  1610. #endif
  1611. } else {
  1612. LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
  1613. #if !defined(CUAS_ENABLE)
  1614. LPVOID lpSrc;
  1615. #endif
  1616. LPVOID lpDest = (LPBYTE)lpRCS + sizeof(RECONVERTSTRING);
  1617. // check buffer size
  1618. // if the given buffer is smaller than actual needed size,
  1619. // shrink our size to fit the buffer
  1620. if ((INT)lpRCS->dwSize <= sizeof(RECONVERTSTRING) + cchLen * ped->cbChar) {
  1621. RIPMSG0(RIP_WARNING, "EcImeRequest: ERR09");
  1622. cchLen = (lpRCS->dwSize - sizeof(RECONVERTSTRING)) / ped->cbChar - ped->cbChar;
  1623. }
  1624. lpRCS->dwStrOffset = sizeof(RECONVERTSTRING); // buffer begins just after RECONVERTSTRING
  1625. #if !defined(CUAS_ENABLE)
  1626. lpRCS->dwCompStrOffset =
  1627. lpRCS->dwTargetStrOffset = 0;
  1628. lpRCS->dwStrLen =
  1629. lpRCS->dwCompStrLen =
  1630. lpRCS->dwTargetStrLen = cchLen; // StrLen means TCHAR count
  1631. lpSrc = ECLock(ped);
  1632. if (lpSrc == NULL) {
  1633. RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed.");
  1634. } else
  1635. #else
  1636. lpRCS->dwCompStrOffset =
  1637. lpRCS->dwTargetStrOffset = (ped->ichMinSel - ichStart) * ped->cbChar; // BYTE count offset
  1638. lpRCS->dwStrLen = cchLen; // TCHAR count
  1639. lpRCS->dwCompStrLen =
  1640. lpRCS->dwTargetStrLen = cchSelLen; // TCHAR count
  1641. #endif
  1642. {
  1643. #if !defined(CUAS_ENABLE)
  1644. RtlCopyMemory(lpDest,
  1645. (LPBYTE)lpSrc + ped->ichMinSel * ped->cbChar,
  1646. cchLen * ped->cbChar);
  1647. #else
  1648. RtlCopyMemory(lpDest,
  1649. (LPBYTE)lpSrc + ichStart * ped->cbChar,
  1650. cchLen * ped->cbChar);
  1651. #endif
  1652. // Null-Terminate the string
  1653. if (ped->fAnsi) {
  1654. LPBYTE psz = (LPBYTE)lpDest;
  1655. psz[cchLen] = '\0';
  1656. } else {
  1657. LPWSTR pwsz = (LPWSTR)lpDest;
  1658. pwsz[cchLen] = L'\0';
  1659. }
  1660. ECUnlock(ped);
  1661. // final buffer size
  1662. lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
  1663. ECInOutReconversionMode(ped, TRUE);
  1664. ECImmSetCompositionWindow(ped, 0, 0);
  1665. }
  1666. }
  1667. }
  1668. break;
  1669. }
  1670. return lreturn;
  1671. }