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.

2234 lines
63 KiB

  1. #include "ctlspriv.h"
  2. #pragma hdrstop
  3. #include "usrctl32.h"
  4. #include "edit.h"
  5. //---------------------------------------------------------------------------//
  6. #define WS_EX_EDGEMASK (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)
  7. #define GetCharABCWidthsAorW ((ped)->fAnsi ? GetCharABCWidthsA : GetCharABCWidthsW)
  8. #define GetCharWidthAorW ((ped)->fAnsi ? GetCharWidthA : GetCharWidthW)
  9. //---------------------------------------------------------------------------//
  10. INT Edit_GetStateId(PED ped)
  11. {
  12. INT iStateId;
  13. if (ped->fDisabled)
  14. {
  15. iStateId = ETS_DISABLED;
  16. }
  17. else if (ped->fReadOnly)
  18. {
  19. iStateId = ETS_READONLY;
  20. }
  21. else if (ped->fFocus)
  22. {
  23. iStateId = ETS_FOCUSED;
  24. }
  25. else if (ped->fHot)
  26. {
  27. iStateId = ETS_HOT;
  28. }
  29. else
  30. {
  31. iStateId = ETS_NORMAL;
  32. }
  33. return iStateId;
  34. }
  35. //---------------------------------------------------------------------------//
  36. VOID Edit_SetMargin(PED ped, UINT wFlags, long lMarginValues, BOOL fRedraw)
  37. {
  38. BOOL fUseFontInfo = FALSE;
  39. UINT wValue, wOldLeftMargin, wOldRightMargin;
  40. if (wFlags & EC_LEFTMARGIN)
  41. {
  42. //
  43. // Set the left margin
  44. //
  45. if ((int) (wValue = (int)(short)LOWORD(lMarginValues)) < 0)
  46. {
  47. fUseFontInfo = TRUE;
  48. wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegA);
  49. }
  50. ped->rcFmt.left += wValue - ped->wLeftMargin;
  51. wOldLeftMargin = ped->wLeftMargin;
  52. ped->wLeftMargin = wValue;
  53. }
  54. if (wFlags & EC_RIGHTMARGIN)
  55. {
  56. //
  57. // Set the Right margin
  58. //
  59. if ((int) (wValue = (int)(short)HIWORD(lMarginValues)) < 0)
  60. {
  61. fUseFontInfo = TRUE;
  62. wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegC);
  63. }
  64. ped->rcFmt.right -= wValue - ped->wRightMargin;
  65. wOldRightMargin = ped->wRightMargin;
  66. ped->wRightMargin = wValue;
  67. }
  68. if (fUseFontInfo)
  69. {
  70. if (ped->rcFmt.right - ped->rcFmt.left < 2 * ped->aveCharWidth)
  71. {
  72. TraceMsg(TF_STANDARD, "EDIT: Edit_SetMargin: rcFmt is too narrow for EC_USEFONTINFO");
  73. if (wFlags & EC_LEFTMARGIN)
  74. {
  75. //
  76. // Reset the left margin
  77. //
  78. ped->rcFmt.left += wOldLeftMargin - ped->wLeftMargin;
  79. ped->wLeftMargin = wOldLeftMargin;
  80. }
  81. if (wFlags & EC_RIGHTMARGIN)
  82. {
  83. //
  84. // Reset the Right margin
  85. //
  86. ped->rcFmt.right -= wOldRightMargin - ped->wRightMargin;
  87. ped->wRightMargin = wOldRightMargin;
  88. }
  89. return;
  90. }
  91. }
  92. if (fRedraw)
  93. {
  94. Edit_InvalidateClient(ped, TRUE);
  95. }
  96. }
  97. //---------------------------------------------------------------------------//
  98. VOID Edit_CalcMarginForDBCSFont(PED ped, BOOL fRedraw)
  99. {
  100. if (ped->fTrueType)
  101. {
  102. if (!ped->fSingle)
  103. {
  104. //
  105. // wMaxNegA came from ABC CharWidth.
  106. //
  107. if (ped->wMaxNegA != 0)
  108. {
  109. Edit_SetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  110. MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO),fRedraw);
  111. }
  112. }
  113. else
  114. {
  115. int iMaxNegA = 0, iMaxNegC = 0;
  116. int i;
  117. PVOID lpBuffer;
  118. LPABC lpABCBuff;
  119. ABC ABCInfo;
  120. HFONT hOldFont;
  121. HDC hdc = GetDC(ped->hwnd);
  122. if (!ped->hFont || !(hOldFont = SelectFont(hdc, ped->hFont)))
  123. {
  124. ReleaseDC(ped->hwnd, hdc);
  125. return;
  126. }
  127. if (lpBuffer = UserLocalAlloc(0,sizeof(ABC) * 256))
  128. {
  129. lpABCBuff = lpBuffer;
  130. GetCharABCWidthsAorW(hdc, 0, 255, lpABCBuff);
  131. }
  132. else
  133. {
  134. lpABCBuff = &ABCInfo;
  135. GetCharABCWidthsAorW(hdc, 0, 0, lpABCBuff);
  136. }
  137. i = 0;
  138. while (TRUE)
  139. {
  140. iMaxNegA = min(iMaxNegA, lpABCBuff->abcA);
  141. iMaxNegC = min(iMaxNegC, lpABCBuff->abcC);
  142. if (++i == 256)
  143. {
  144. break;
  145. }
  146. if (lpBuffer)
  147. {
  148. lpABCBuff++;
  149. }
  150. else
  151. {
  152. GetCharABCWidthsAorW(hdc, i, i, lpABCBuff);
  153. }
  154. }
  155. SelectFont(hdc, hOldFont);
  156. if (lpBuffer)
  157. {
  158. UserLocalFree(lpBuffer);
  159. }
  160. ReleaseDC(ped->hwnd, hdc);
  161. if ((iMaxNegA != 0) || (iMaxNegC != 0))
  162. {
  163. Edit_SetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  164. MAKELONG((UINT)(-iMaxNegC), (UINT)(-iMaxNegA)),fRedraw);
  165. }
  166. }
  167. }
  168. }
  169. //---------------------------------------------------------------------------//
  170. //
  171. // GetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
  172. //
  173. // if an app set a font for vertical writing, even though we don't
  174. // handle it with EC, the escapement of tm can be NON 0. Then cxWidth from
  175. // GetCharDimenstions() could be 0 in GetCharDimensions().
  176. // This will break our caller who don't expect 0 at return. So I created
  177. // this entry for the case the caller set vertical font.
  178. //
  179. //
  180. // PORTPORT: Duplicates functionality of GetCharDimensions() in prsht.c
  181. int UserGetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRICW lptm, LPINT lpcy)
  182. {
  183. static CONST WCHAR AveCharWidthData[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  184. int cxWidth;
  185. TEXTMETRICW tm;
  186. LOGFONTW lf;
  187. WCHAR wchFaceName[LF_FACESIZE];
  188. //
  189. // Is this font vertical font ??
  190. //
  191. wchFaceName[0] = 0;
  192. GetTextFaceW(hDC, LF_FACESIZE, wchFaceName);
  193. if (wchFaceName[0] != L'@')
  194. {
  195. //
  196. // if not call GDI...
  197. //
  198. return(GdiGetCharDimensions(hDC, lptm, lpcy));
  199. }
  200. if (!lptm)
  201. {
  202. lptm = &tm;
  203. }
  204. GetTextMetricsW(hDC, lptm);
  205. // TMPF_FIXED_PITCH
  206. //
  207. // If this bit is set the font is a variable pitch font.
  208. // If this bit is clear the font is a fixed pitch font.
  209. // Note very carefully that those meanings are the opposite of what the constant name implies.
  210. //
  211. if (!(lptm->tmPitchAndFamily & TMPF_FIXED_PITCH))
  212. {
  213. //
  214. // This is fixed pitch font....
  215. //
  216. cxWidth = lptm->tmAveCharWidth;
  217. }
  218. else
  219. {
  220. //
  221. // This is variable pitch font...
  222. //
  223. if (hfont && GetObjectW(hfont, sizeof(LOGFONTW), &lf) && (lf.lfEscapement != 0))
  224. {
  225. cxWidth = lptm->tmAveCharWidth;
  226. }
  227. else
  228. {
  229. SIZE size;
  230. GetTextExtentPointW(hDC, AveCharWidthData, 52, &size);
  231. cxWidth = ((size.cx / 26) + 1) / 2;
  232. }
  233. }
  234. if (lpcy)
  235. {
  236. *lpcy = lptm->tmHeight;
  237. }
  238. return cxWidth;
  239. }
  240. //---------------------------------------------------------------------------//
  241. //
  242. // Edit_GetTextHandler AorW
  243. //
  244. // Copies at most maxCchToCopy chars to the buffer lpBuffer. Returns
  245. // how many chars were actually copied. Null terminates the string based
  246. // on the fNullTerminate flag:
  247. // fNullTerminate --> at most (maxCchToCopy - 1) characters will be copied
  248. // !fNullTerminate --> at most (maxCchToCopy) characters will be copied
  249. //
  250. ICH Edit_GetTextHandler(PED ped, ICH maxCchToCopy, LPSTR lpBuffer, BOOL fNullTerminate)
  251. {
  252. PSTR pText;
  253. if (maxCchToCopy)
  254. {
  255. //
  256. // Zero terminator takes the extra byte
  257. //
  258. if (fNullTerminate)
  259. {
  260. maxCchToCopy--;
  261. }
  262. maxCchToCopy = min(maxCchToCopy, ped->cch);
  263. //
  264. // Zero terminate the string
  265. //
  266. if (ped->fAnsi)
  267. {
  268. *(LPSTR)(lpBuffer + maxCchToCopy) = 0;
  269. }
  270. else
  271. {
  272. *(((LPWSTR)lpBuffer) + maxCchToCopy) = 0;
  273. }
  274. pText = Edit_Lock(ped);
  275. RtlCopyMemory(lpBuffer, pText, maxCchToCopy * ped->cbChar);
  276. Edit_Unlock(ped);
  277. }
  278. return maxCchToCopy;
  279. }
  280. //---------------------------------------------------------------------------//
  281. BOOL Edit_NcCreate( PED ped, HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  282. {
  283. BOOL fAnsi;
  284. ULONG ulStyle;
  285. ULONG ulStyleEx;
  286. //
  287. // Initialize the ped
  288. //
  289. ped->hwnd = hwnd;
  290. ped->pww = (PWW)GetWindowLongPtr(hwnd, GWLP_WOWWORDS);
  291. ulStyle = GET_STYLE(ped);
  292. ulStyleEx = GET_EXSTYLE(ped);
  293. //
  294. // (phellyar) All strings sent to us via standard WM_* messages or
  295. // control specific EM_* messages are expanded to unicode
  296. // for us by user. Therefore we need worry about
  297. // whether be are created by and ANSI app.
  298. //
  299. //fAnsi = TESTFLAG(GET_STATE(ped), WS_ST_ANSICREATOR);
  300. fAnsi = 0;
  301. ped->fEncoded = FALSE;
  302. ped->iLockLevel = 0;
  303. ped->chLines = NULL;
  304. ped->pTabStops = NULL;
  305. ped->charWidthBuffer = NULL;
  306. ped->fAnsi = fAnsi ? 1 : 0; // Force TRUE to be 1 because its a 1 bit field
  307. ped->cbChar = (WORD)(fAnsi ? sizeof(CHAR) : sizeof(WCHAR));
  308. ped->hInstance = lpCreateStruct->hInstance;
  309. // IME
  310. ped->hImcPrev = NULL_HIMC;
  311. {
  312. DWORD dwVer = UserGetVersion();
  313. ped->fWin31Compat = Is310Compat(dwVer);
  314. ped->f40Compat = Is400Compat(dwVer);
  315. }
  316. //
  317. // NOTE:
  318. // The order of the following two checks is important. People can
  319. // create edit fields with a 3D and a normal border, and we don't
  320. // want to disallow that. But we need to detect the "no 3D border"
  321. // border case too.
  322. //
  323. if ( ulStyleEx & WS_EX_EDGEMASK )
  324. {
  325. ped->fBorder = TRUE;
  326. }
  327. else if ( ulStyle & WS_BORDER )
  328. {
  329. ClearWindowState(hwnd, WS_BORDER);
  330. ped->fFlatBorder = TRUE;
  331. ped->fBorder = TRUE;
  332. }
  333. if ( !(ulStyle & ES_MULTILINE) )
  334. {
  335. ped->fSingle = TRUE;
  336. }
  337. if ( ulStyle & WS_DISABLED )
  338. {
  339. ped->fDisabled = TRUE;
  340. }
  341. if ( ulStyle & ES_READONLY)
  342. {
  343. if (!ped->fWin31Compat)
  344. {
  345. //
  346. // BACKWARD COMPATIBILITY HACK
  347. //
  348. // "MileStone" unknowingly sets the ES_READONLY style. So, we strip this
  349. // style here for all Win3.0 apps (this style is new for Win3.1).
  350. // Fix for Bug #12982 -- SANKAR -- 01/24/92 --
  351. //
  352. ClearWindowState(hwnd, ES_READONLY);
  353. }
  354. else
  355. {
  356. ped->fReadOnly = TRUE;
  357. }
  358. }
  359. //
  360. // Allocate storage for the text for the edit controls. Storage for single
  361. // line edit controls will always get allocated in the local data segment.
  362. // Multiline will allocate in the local ds but the app may free this and
  363. // allocate storage elsewhere...
  364. //
  365. ped->hText = LocalAlloc(LHND, CCHALLOCEXTRA*ped->cbChar);
  366. if (!ped->hText)
  367. {
  368. return FALSE;
  369. }
  370. ped->cchAlloc = CCHALLOCEXTRA;
  371. ped->lineHeight = 1;
  372. ped->hwndParent = lpCreateStruct->hwndParent;
  373. ped->hTheme = OpenThemeData(ped->hwnd, L"Edit");
  374. ped->wImeStatus = 0;
  375. return (BOOL)DefWindowProc(hwnd, WM_NCCREATE, 0, (LPARAM)lpCreateStruct);
  376. }
  377. //---------------------------------------------------------------------------//
  378. BOOL Edit_Create(PED ped, LONG windowStyle)
  379. {
  380. HDC hdc;
  381. //
  382. // Get values from the window instance data structure and put
  383. // them in the ped so that we can access them easier.
  384. //
  385. if ( windowStyle & ES_AUTOHSCROLL )
  386. {
  387. ped->fAutoHScroll = 1;
  388. }
  389. if ( windowStyle & ES_NOHIDESEL )
  390. {
  391. ped->fNoHideSel = 1;
  392. }
  393. ped->format = (LOWORD(windowStyle) & LOWORD(ES_FMTMASK));
  394. if ((windowStyle & ES_RIGHT) && !ped->format)
  395. {
  396. ped->format = ES_RIGHT;
  397. }
  398. //
  399. // Max # chars we will initially allow
  400. //
  401. ped->cchTextMax = MAXTEXT;
  402. //
  403. // Set up undo initial conditions... (ie. nothing to undo)
  404. //
  405. ped->ichDeleted = (ICH)-1;
  406. ped->ichInsStart = (ICH)-1;
  407. ped->ichInsEnd = (ICH)-1;
  408. //
  409. // initial charset value - need to do this BEFORE EditML_Create is called
  410. // so that we know not to fool with scrollbars if nessacary
  411. //
  412. hdc = Edit_GetDC(ped, TRUE);
  413. ped->charSet = (BYTE)GetTextCharset(hdc);
  414. Edit_ReleaseDC(ped, hdc, TRUE);
  415. //
  416. // FE_IME
  417. // EC_INSERT_COMPOSITION_CHARACTER: Edit_Create() - call Edit_InitInsert()
  418. //
  419. Edit_InitInsert(ped, GetKeyboardLayout(0));
  420. if( g_pLpkEditCallout )
  421. {
  422. ped->pLpkEditCallout = g_pLpkEditCallout;
  423. }
  424. else
  425. {
  426. ped->pLpkEditCallout = NULL;
  427. }
  428. return ped->pLpkEditCallout ? ped->pLpkEditCallout->EditCreate((PED0)ped, ped->hwnd) : TRUE;
  429. }
  430. //---------------------------------------------------------------------------//
  431. //
  432. // Do this once at process startup. The edit control has special
  433. // callouts in lpk.dll to help it render complex script languages
  434. // such as Arabic. The registry probing alg executed here is the same
  435. // as the one performed in win32k!InitializeGre.
  436. //
  437. // We then call GetModuleHandle rather than LoadLibrary, since lpk.dll
  438. // will be guaranteed to be loaded and initialized already by gdi32. This
  439. // fixes the scenario in which the user turns on complex scripts but
  440. // doesn't reboot, which caused us to try and load lpk without it having
  441. // been initialized on the kernel side.
  442. //
  443. VOID InitEditLpk()
  444. {
  445. LONG lError;
  446. HKEY hKey;
  447. lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  448. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\LanguagePack"),
  449. 0,
  450. KEY_QUERY_VALUE,
  451. &hKey);
  452. if (lError == ERROR_SUCCESS)
  453. {
  454. HANDLE hLpk;
  455. DWORD dwLpkShapingDlls;
  456. DWORD dwIndex;
  457. TCHAR szTemp[256];
  458. DWORD dwTempSize;
  459. DWORD dwValueType;
  460. DWORD dwValue;
  461. DWORD dwValueSize;
  462. dwLpkShapingDlls = 0;
  463. dwIndex = 0;
  464. do
  465. {
  466. dwTempSize = ARRAYSIZE(szTemp);
  467. dwValueSize = SIZEOF(DWORD);
  468. lError = RegEnumValue(hKey,
  469. dwIndex++,
  470. szTemp,
  471. &dwTempSize,
  472. NULL,
  473. &dwValueType,
  474. (LPVOID)&dwValue,
  475. &dwValueSize);
  476. if ((lError == ERROR_SUCCESS) && (dwValueType == REG_DWORD))
  477. {
  478. dwLpkShapingDlls |= 1 << dwValue;
  479. }
  480. }
  481. while (lError != ERROR_NO_MORE_ITEMS);
  482. if (dwLpkShapingDlls != 0)
  483. {
  484. hLpk = GetModuleHandle(TEXT("LPK"));
  485. if (hLpk != NULL)
  486. {
  487. g_pLpkEditCallout = (PLPKEDITCALLOUT)GetProcAddress(hLpk, "LpkEditControl");
  488. if (g_pLpkEditCallout == NULL)
  489. {
  490. FreeLibrary(hLpk);
  491. }
  492. }
  493. }
  494. RegCloseKey(hKey);
  495. }
  496. }
  497. //---------------------------------------------------------------------------//
  498. //
  499. // Destroys the edit control ped by freeing up all memory used by it.
  500. //
  501. VOID Edit_NcDestroyHandler(HWND hwnd, PED ped)
  502. {
  503. //
  504. // ped could be NULL if WM_NCCREATE failed to create it...
  505. //
  506. if (ped)
  507. {
  508. //
  509. // Free the text buffer (always present?)
  510. //
  511. if (TESTFLAG(GET_STYLE(ped), ES_PASSWORD))
  512. {
  513. LPWSTR pszText = LocalLock(ped->hText);
  514. RtlSecureZeroMemory(pszText, LocalSize(ped->hText));
  515. LocalUnlock(ped->hText);
  516. }
  517. LocalFree(ped->hText);
  518. //
  519. // Free up undo buffer and line start array (if present)
  520. //
  521. if (ped->hDeletedText != NULL)
  522. {
  523. GlobalFree(ped->hDeletedText);
  524. }
  525. //
  526. // Free tab stop buffer (if present)
  527. //
  528. if (ped->pTabStops)
  529. {
  530. UserLocalFree(ped->pTabStops);
  531. }
  532. //
  533. // Free line start array (if present)
  534. //
  535. if (ped->chLines)
  536. {
  537. UserLocalFree(ped->chLines);
  538. }
  539. //
  540. // Free the character width buffer (if present)
  541. //
  542. if (ped->charWidthBuffer)
  543. {
  544. UserLocalFree(ped->charWidthBuffer);
  545. }
  546. //
  547. // Free the cursor bitmap
  548. //
  549. if (ped->pLpkEditCallout && ped->hCaretBitmap)
  550. {
  551. DeleteObject(ped->hCaretBitmap);
  552. }
  553. //
  554. // Free the cached font handle
  555. //
  556. if ( ped->hFontSave )
  557. {
  558. DeleteObject(ped->hFontSave);
  559. }
  560. //
  561. // Close an open theme handle
  562. //
  563. if ( ped->hTheme )
  564. {
  565. CloseThemeData(ped->hTheme);
  566. }
  567. //
  568. // Free the memory used by CueBannerText
  569. //
  570. Str_SetPtr(&(ped->pszCueBannerText), NULL);
  571. //
  572. // free the allocated password font
  573. //
  574. if ( ped->hFontPassword )
  575. {
  576. DeleteObject(ped->hFontPassword);
  577. }
  578. //
  579. // Last but not least, free the ped
  580. //
  581. UserLocalFree(ped);
  582. }
  583. TraceMsg(TF_STANDARD, "EDIT: Clearing edit instance pointer.");
  584. Edit_SetPtr(hwnd, NULL);
  585. }
  586. //---------------------------------------------------------------------------//
  587. //
  588. // Edit_SetPasswordCharHandler AorW
  589. //
  590. // Sets the password char to display.
  591. //
  592. VOID Edit_SetPasswordCharHandler(PED ped, UINT pwchar)
  593. {
  594. HDC hdc;
  595. SIZE size = {0};
  596. ped->charPasswordChar = pwchar;
  597. if (pwchar)
  598. {
  599. hdc = Edit_GetDC(ped, TRUE);
  600. if (ped->fAnsi)
  601. {
  602. GetTextExtentPointA(hdc, (LPSTR)&pwchar, 1, &size);
  603. }
  604. else
  605. {
  606. GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
  607. }
  608. GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
  609. ped->cPasswordCharWidth = max(size.cx, 1);
  610. Edit_ReleaseDC(ped, hdc, TRUE);
  611. }
  612. if (pwchar)
  613. {
  614. SetWindowState(ped->hwnd, ES_PASSWORD);
  615. }
  616. else
  617. {
  618. ClearWindowState(ped->hwnd, ES_PASSWORD);
  619. }
  620. if ( g_fIMMEnabled )
  621. {
  622. Edit_EnableDisableIME(ped);
  623. }
  624. }
  625. //---------------------------------------------------------------------------//
  626. //
  627. // GetNegABCwidthInfo()
  628. //
  629. // This function fills up the ped->charWidthBuffer buffer with the
  630. // negative A,B and C widths for all the characters below 0x7f in the
  631. // currently selected font.
  632. //
  633. // Returns:
  634. // TRUE, if the function succeeded.
  635. // FALSE, if GDI calls to get the char widths have failed.
  636. //
  637. // Note: not used if LPK installed
  638. //
  639. BOOL GetNegABCwidthInfo(PED ped, HDC hdc)
  640. {
  641. LPABC lpABCbuff;
  642. int i;
  643. int CharWidthBuff[CHAR_WIDTH_BUFFER_LENGTH]; // Local char width buffer.
  644. int iOverhang;
  645. if (!GetCharABCWidthsA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPABC)ped->charWidthBuffer))
  646. {
  647. TraceMsg(TF_STANDARD, "UxEdit: GetNegABCwidthInfo: GetCharABCWidthsA Failed");
  648. return FALSE;
  649. }
  650. //
  651. // The (A+B+C) returned for some fonts (eg: Lucida Caligraphy) does not
  652. // equal the actual advanced width returned by GetCharWidths() minus overhang.
  653. // This is due to font bugs. So, we adjust the 'B' width so that this
  654. // discrepancy is removed.
  655. // Fix for Bug #2932 --sankar-- 02/17/93
  656. //
  657. iOverhang = ped->charOverhang;
  658. GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPINT)CharWidthBuff);
  659. lpABCbuff = (LPABC)ped->charWidthBuffer;
  660. for(i = 0; i < CHAR_WIDTH_BUFFER_LENGTH; i++)
  661. {
  662. lpABCbuff->abcB = CharWidthBuff[i] - iOverhang
  663. - lpABCbuff->abcA
  664. - lpABCbuff->abcC;
  665. lpABCbuff++;
  666. }
  667. return TRUE;
  668. }
  669. //---------------------------------------------------------------------------//
  670. //
  671. // Edit_Size() -
  672. //
  673. // Handle sizing for an edit control's client rectangle.
  674. // Use lprc as the bounding rectangle if specified; otherwise use the current
  675. // client rectangle.
  676. //
  677. VOID Edit_Size(PED ped, LPRECT lprc, BOOL fRedraw)
  678. {
  679. RECT rc;
  680. //
  681. // BiDi VB32 Creates an Edit Control and immediately sends a WM_SIZE
  682. // message which causes EXSize to be called before Edit_SetFont, which
  683. // in turn causes a divide by zero exception below. This check for
  684. // ped->lineHeight will pick it up safely. [samera] 3/5/97
  685. //
  686. if(ped->lineHeight == 0)
  687. {
  688. return;
  689. }
  690. //
  691. // assume that we won't be able to display the caret
  692. //
  693. ped->fCaretHidden = TRUE;
  694. if ( lprc )
  695. {
  696. CopyRect(&rc, lprc);
  697. }
  698. else
  699. {
  700. GetClientRect(ped->hwnd, &rc);
  701. }
  702. if (!(rc.right - rc.left) || !(rc.bottom - rc.top))
  703. {
  704. if (ped->rcFmt.right - ped->rcFmt.left)
  705. {
  706. return;
  707. }
  708. rc.left = 0;
  709. rc.top = 0;
  710. rc.right = ped->aveCharWidth * 10;
  711. rc.bottom = ped->lineHeight;
  712. }
  713. if (!lprc)
  714. {
  715. //
  716. // subtract the margins from the given rectangle --
  717. // make sure that this rectangle is big enough to have these margins.
  718. //
  719. if ((rc.right - rc.left) > (int)(ped->wLeftMargin + ped->wRightMargin))
  720. {
  721. rc.left += ped->wLeftMargin;
  722. rc.right -= ped->wRightMargin;
  723. }
  724. }
  725. //
  726. // Leave space so text doesn't touch borders.
  727. // For 3.1 compatibility, don't subtract out vertical borders unless
  728. // there is room.
  729. //
  730. if (ped->fBorder)
  731. {
  732. INT cxBorder = GetSystemMetrics(SM_CXBORDER);
  733. INT cyBorder = GetSystemMetrics(SM_CYBORDER);
  734. if (ped->fFlatBorder)
  735. {
  736. cxBorder *= 2;
  737. cyBorder *= 2;
  738. }
  739. if (rc.bottom < rc.top + ped->lineHeight + 2*cyBorder)
  740. {
  741. cyBorder = 0;
  742. }
  743. InflateRect(&rc, -cxBorder, -cyBorder);
  744. }
  745. //
  746. // Is the resulting rectangle too small? Don't change it then.
  747. //
  748. if ((!ped->fSingle) && ((rc.right - rc.left < (int) ped->aveCharWidth) ||
  749. ((rc.bottom - rc.top) / ped->lineHeight == 0)))
  750. {
  751. return;
  752. }
  753. //
  754. // now, we know we're safe to display the caret
  755. //
  756. ped->fCaretHidden = FALSE;
  757. CopyRect(&ped->rcFmt, &rc);
  758. if (ped->fSingle)
  759. {
  760. ped->rcFmt.bottom = min(rc.bottom, rc.top + ped->lineHeight);
  761. }
  762. else
  763. {
  764. EditML_Size(ped, fRedraw);
  765. }
  766. if (fRedraw)
  767. {
  768. InvalidateRect(ped->hwnd, NULL, TRUE);
  769. }
  770. //
  771. // FE_IME
  772. // Edit_Size() - call Edit_ImmSetCompositionWindow()
  773. //
  774. // normally this isn't needed because WM_SIZE will cause
  775. // WM_PAINT and the paint handler will take care of IME
  776. // composition window. However when the edit window is
  777. // restored from maximized window and client area is out
  778. // of screen, the window will not be redrawn.
  779. //
  780. if (ped->fFocus && g_fIMMEnabled && ImmIsIME(GetKeyboardLayout(0)))
  781. {
  782. POINT pt;
  783. GetCaretPos(&pt);
  784. Edit_ImmSetCompositionWindow(ped, pt.x, pt.y);
  785. }
  786. }
  787. //---------------------------------------------------------------------------//
  788. //
  789. // Edit_SetFont AorW
  790. //
  791. // Sets the font used in the edit control. Warning: Memory compaction may
  792. // occur if the font wasn't previously loaded. If the font handle passed
  793. // in is NULL, assume the system font.
  794. //
  795. BOOL Edit_SetFont(PED ped, HFONT hfont, BOOL fRedraw)
  796. {
  797. TEXTMETRICW TextMetrics = {0};
  798. HDC hdc;
  799. HFONT hOldFont=NULL;
  800. DWORD dwMaxOverlapChars;
  801. CHWIDTHINFO cwi;
  802. UINT uExtracharPos;
  803. BOOL fRet = FALSE;
  804. hdc = GetDC(ped->hwnd);
  805. if (hdc)
  806. {
  807. #ifdef _USE_DRAW_THEME_TEXT_
  808. if (hfont)
  809. {
  810. ped->hFontSave = hfont;
  811. }
  812. if ( ped->hTheme )
  813. {
  814. //
  815. // use the theme font if we're themed
  816. //
  817. HRESULT hr;
  818. LOGFONT lf;
  819. hr = GetThemeFont(ped->hTheme, hdc, EP_EDITTEXT, 0, TMT_FONT, &lf);
  820. if ( SUCCEEDED(hr) )
  821. {
  822. hfont = CreateFontIndirect(&lf);
  823. }
  824. }
  825. #endif // _USE_DRAW_THEME_TEXT_
  826. ped->hFont = hfont;
  827. if (ped->hFont)
  828. {
  829. //
  830. // Since the default font is the system font, no need to select it in
  831. // if that's what the user wants.
  832. //
  833. hOldFont = SelectObject(hdc, hfont);
  834. if (!hOldFont)
  835. {
  836. hfont = ped->hFont = NULL;
  837. }
  838. //
  839. // Get the metrics and ave char width for the currently selected font
  840. //
  841. //
  842. // Call Vertical font-aware AveWidth compute function...
  843. //
  844. // FE_SB
  845. ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight);
  846. //
  847. // This might fail when people uses network fonts (or bad fonts).
  848. //
  849. if (ped->aveCharWidth == 0)
  850. {
  851. TraceMsg(TF_STANDARD, "EDIT: Edit_SetFont: GdiGetCharDimensions failed");
  852. if (hOldFont != NULL)
  853. {
  854. SelectObject(hdc, hOldFont);
  855. }
  856. //
  857. // We've messed up the ped so let's reset the font.
  858. // Note that we won't recurse more than once because we'll
  859. // pass hfont == NULL.
  860. // Too bad WM_SETFONT doesn't return a value.
  861. //
  862. return Edit_SetFont(ped, NULL, fRedraw);
  863. }
  864. }
  865. else
  866. {
  867. ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight);
  868. // We should always be able to get the dimensions of the system font. Just in case
  869. // set these guys to known system font constants
  870. if ( ped->aveCharWidth == 0 )
  871. {
  872. ped->aveCharWidth = SYSFONT_CXCHAR;
  873. ped->lineHeight = SYSFONT_CYCHAR;
  874. }
  875. }
  876. ped->charOverhang = TextMetrics.tmOverhang;
  877. //
  878. // assume that they don't have any negative widths at all.
  879. //
  880. ped->wMaxNegA = ped->wMaxNegC = ped->wMaxNegAcharPos = ped->wMaxNegCcharPos = 0;
  881. //
  882. // Check if Proportional Width Font
  883. //
  884. // NOTE: as SDK doc says about TEXTMETRIC:
  885. // TMPF_FIXED_PITCH
  886. // If this bit is set the font is a variable pitch font. If this bit is clear
  887. // the font is a fixed pitch font. Note very carefully that those meanings are
  888. // the opposite of what the constant name implies.
  889. //
  890. // Thus we have to reverse the value using logical not (fNonPropFont has 1 bit width)
  891. //
  892. ped->fNonPropFont = !(TextMetrics.tmPitchAndFamily & FIXED_PITCH);
  893. //
  894. // Check for a TrueType font
  895. // Older app OZWIN chokes if we allocate a bigger buffer for TrueType fonts
  896. // So, for apps older than 4.0, no special treatment for TrueType fonts.
  897. //
  898. if (ped->f40Compat && (TextMetrics.tmPitchAndFamily & TMPF_TRUETYPE))
  899. {
  900. ped->fTrueType = GetCharWidthInfo(hdc, &cwi);
  901. #if DBG
  902. if (!ped->fTrueType)
  903. {
  904. TraceMsg(TF_STANDARD, "EDIT: Edit_SetFont: GetCharWidthInfo Failed");
  905. }
  906. #endif
  907. }
  908. else
  909. {
  910. ped->fTrueType = FALSE;
  911. }
  912. // FE_SB
  913. //
  914. // In DBCS Windows, Edit Control must handle Double Byte Character
  915. // if tmCharSet field of textmetrics is double byte character set
  916. // such as SHIFTJIS_CHARSET(128:Japan), HANGEUL_CHARSET(129:Korea).
  917. //
  918. // We call Edit_GetDBCSVector even when fAnsi is false so that we could
  919. // treat ped->fAnsi and ped->fDBCS indivisually. I changed Edit_GetDBCSVector
  920. // function so that it returns 0 or 1, because I would like to set ped->fDBCS
  921. // bit field here.
  922. //
  923. ped->fDBCS = Edit_GetDBCSVector(ped,hdc,TextMetrics.tmCharSet);
  924. ped->charSet = TextMetrics.tmCharSet;
  925. if (ped->fDBCS)
  926. {
  927. //
  928. // Free the character width buffer if ped->fDBCS.
  929. //
  930. // I expect single GetTextExtentPoint call is faster than multiple
  931. // GetTextExtentPoint call (because the graphic engine has a cache buffer).
  932. // See editec.c/ECTabTheTextOut().
  933. //
  934. if (ped->charWidthBuffer)
  935. {
  936. LocalFree(ped->charWidthBuffer);
  937. ped->charWidthBuffer = NULL;
  938. }
  939. //
  940. // if FullWidthChar : HalfWidthChar == 2 : 1....
  941. //
  942. // TextMetrics.tmMaxCharWidth = FullWidthChar width
  943. // ped->aveCharWidth = HalfWidthChar width
  944. //
  945. if (ped->fNonPropFont &&
  946. ((ped->aveCharWidth * 2) == TextMetrics.tmMaxCharWidth))
  947. {
  948. ped->fNonPropDBCS = TRUE;
  949. }
  950. else
  951. {
  952. ped->fNonPropDBCS = FALSE;
  953. }
  954. }
  955. else
  956. {
  957. //
  958. // Since the font has changed, let us obtain and save the character width
  959. // info for this font.
  960. //
  961. // First left us find out if the maximum chars that can overlap due to
  962. // negative widths. Since we can't access USER globals, we make a call here.
  963. //
  964. if (!(ped->fSingle || ped->pLpkEditCallout))
  965. {
  966. //
  967. // Is this a multiline edit control with no LPK present?
  968. //
  969. UINT wBuffSize;
  970. LPINT lpCharWidthBuff;
  971. SHORT i;
  972. //
  973. // For multiline edit controls, we maintain a buffer that contains
  974. // the character width information.
  975. //
  976. wBuffSize = (ped->fTrueType) ? (CHAR_WIDTH_BUFFER_LENGTH * sizeof(ABC)) :
  977. (CHAR_WIDTH_BUFFER_LENGTH * sizeof(int));
  978. if (ped->charWidthBuffer)
  979. {
  980. //
  981. // If buffer already present
  982. //
  983. lpCharWidthBuff = ped->charWidthBuffer;
  984. ped->charWidthBuffer = UserLocalReAlloc(lpCharWidthBuff, wBuffSize, HEAP_ZERO_MEMORY);
  985. if (ped->charWidthBuffer == NULL)
  986. {
  987. UserLocalFree((HANDLE)lpCharWidthBuff);
  988. }
  989. }
  990. else
  991. {
  992. ped->charWidthBuffer = UserLocalAlloc(HEAP_ZERO_MEMORY, wBuffSize);
  993. }
  994. if (ped->charWidthBuffer != NULL)
  995. {
  996. if (ped->fTrueType)
  997. {
  998. ped->fTrueType = GetNegABCwidthInfo(ped, hdc);
  999. }
  1000. //
  1001. // It is possible that the above attempts could have failed and reset
  1002. // the value of fTrueType. So, let us check that value again.
  1003. //
  1004. if (!ped->fTrueType)
  1005. {
  1006. if (!GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, ped->charWidthBuffer))
  1007. {
  1008. UserLocalFree((HANDLE)ped->charWidthBuffer);
  1009. ped->charWidthBuffer=NULL;
  1010. }
  1011. else
  1012. {
  1013. //
  1014. // We need to subtract out the overhang associated with
  1015. // each character since GetCharWidth includes it...
  1016. //
  1017. for (i=0;i < CHAR_WIDTH_BUFFER_LENGTH;i++)
  1018. {
  1019. ped->charWidthBuffer[i] -= ped->charOverhang;
  1020. }
  1021. }
  1022. }
  1023. }
  1024. }
  1025. }
  1026. {
  1027. //
  1028. // Calculate MaxNeg A C metrics
  1029. //
  1030. dwMaxOverlapChars = 0;
  1031. if (ped->fTrueType)
  1032. {
  1033. if (cwi.lMaxNegA < 0)
  1034. {
  1035. ped->wMaxNegA = -cwi.lMaxNegA;
  1036. }
  1037. else
  1038. {
  1039. ped->wMaxNegA = 0;
  1040. }
  1041. if (cwi.lMaxNegC < 0)
  1042. {
  1043. ped->wMaxNegC = -cwi.lMaxNegC;
  1044. }
  1045. else
  1046. {
  1047. ped->wMaxNegC = 0;
  1048. }
  1049. if (cwi.lMinWidthD != 0)
  1050. {
  1051. ped->wMaxNegAcharPos = (ped->wMaxNegA + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
  1052. ped->wMaxNegCcharPos = (ped->wMaxNegC + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
  1053. if (ped->wMaxNegA + ped->wMaxNegC > (UINT)cwi.lMinWidthD)
  1054. {
  1055. uExtracharPos = (ped->wMaxNegA + ped->wMaxNegC - 1) / cwi.lMinWidthD;
  1056. ped->wMaxNegAcharPos += uExtracharPos;
  1057. ped->wMaxNegCcharPos += uExtracharPos;
  1058. }
  1059. }
  1060. else
  1061. {
  1062. ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
  1063. ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
  1064. }
  1065. }
  1066. else if (ped->charOverhang != 0)
  1067. {
  1068. //
  1069. // Some bitmaps fonts (i.e., italic) have under/overhangs;
  1070. // this is pretty much like having negative A and C widths.
  1071. //
  1072. ped->wMaxNegA = ped->wMaxNegC = ped->charOverhang;
  1073. ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
  1074. ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
  1075. }
  1076. }
  1077. if (!hfont)
  1078. {
  1079. //
  1080. // We are getting the stats for the system font so update the system
  1081. // font fields in the ed structure since we use these when calculating
  1082. // some spacing.
  1083. //
  1084. ped->cxSysCharWidth = ped->aveCharWidth;
  1085. ped->cySysCharHeight= ped->lineHeight;
  1086. }
  1087. else if (hOldFont)
  1088. {
  1089. SelectObject(hdc, hOldFont);
  1090. }
  1091. if (ped->fFocus)
  1092. {
  1093. UINT cxCaret;
  1094. SystemParametersInfo(SPI_GETCARETWIDTH, 0, (LPVOID)&cxCaret, 0);
  1095. //
  1096. // Update the caret.
  1097. //
  1098. HideCaret(ped->hwnd);
  1099. DestroyCaret();
  1100. if (ped->pLpkEditCallout)
  1101. {
  1102. ped->pLpkEditCallout->EditCreateCaret((PED0)ped, hdc, cxCaret, ped->lineHeight, 0);
  1103. }
  1104. else
  1105. {
  1106. CreateCaret(ped->hwnd, (HBITMAP)NULL, cxCaret, ped->lineHeight);
  1107. }
  1108. ShowCaret(ped->hwnd);
  1109. }
  1110. ReleaseDC(ped->hwnd, hdc);
  1111. //
  1112. // Update password character.
  1113. //
  1114. if (ped->charPasswordChar)
  1115. {
  1116. Edit_SetPasswordCharHandler(ped, ped->charPasswordChar);
  1117. }
  1118. //
  1119. // If it is a TrueType font and it's a new app, set both the margins at the
  1120. // max negative width values for all types of the edit controls.
  1121. // (NOTE: Can't use ped->f40Compat here because edit-controls inside dialog
  1122. // boxes without DS_LOCALEDIT style are always marked as 4.0 compat.
  1123. // This is the fix for NETBENCH 3.0)
  1124. //
  1125. if (ped->fTrueType && ped->f40Compat)
  1126. {
  1127. if (ped->fDBCS)
  1128. {
  1129. //
  1130. // For DBCS TrueType Font, we calc margin from ABC width.
  1131. //
  1132. Edit_CalcMarginForDBCSFont(ped, fRedraw);
  1133. }
  1134. else
  1135. {
  1136. Edit_SetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  1137. MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO), fRedraw);
  1138. }
  1139. }
  1140. //
  1141. // We need to calc maxPixelWidth when font changes.
  1142. // If the word-wrap is ON, then this is done in EditML_Size() called later.
  1143. //
  1144. if((!ped->fSingle) && (!ped->fWrap))
  1145. {
  1146. EditML_BuildchLines(ped, 0, 0, FALSE, NULL, NULL);
  1147. }
  1148. //
  1149. // Recalc the layout.
  1150. //
  1151. Edit_Size(ped, NULL, fRedraw);
  1152. if ( ped->fFocus && ImmIsIME(GetKeyboardLayout(0)) )
  1153. {
  1154. Edit_SetCompositionFont( ped );
  1155. }
  1156. fRet = TRUE;
  1157. }
  1158. return fRet;
  1159. }
  1160. //---------------------------------------------------------------------------//
  1161. //
  1162. // Edit_IsCharNumeric AorW
  1163. //
  1164. // Tests whether the character entered is a numeral.
  1165. // For multiline and singleline edit controls with the ES_NUMBER style.
  1166. //
  1167. BOOL Edit_IsCharNumeric(PED ped, DWORD keyPress)
  1168. {
  1169. WORD wCharType;
  1170. if (ped->fAnsi)
  1171. {
  1172. char ch = (char)keyPress;
  1173. LCID lcid = (LCID)((ULONG_PTR)GetKeyboardLayout(0) & 0xFFFF);
  1174. GetStringTypeA(lcid, CT_CTYPE1, &ch, 1, &wCharType);
  1175. }
  1176. else
  1177. {
  1178. WCHAR wch = (WCHAR)keyPress;
  1179. GetStringTypeW(CT_CTYPE1, &wch, 1, &wCharType);
  1180. }
  1181. return (wCharType & C1_DIGIT ? TRUE : FALSE);
  1182. }
  1183. //---------------------------------------------------------------------------//
  1184. VOID Edit_EnableDisableIME(PED ped)
  1185. {
  1186. if ( ped->fReadOnly || ped->charPasswordChar )
  1187. {
  1188. //
  1189. // IME should be disabled
  1190. //
  1191. HIMC hImc;
  1192. hImc = ImmGetContext( ped->hwnd );
  1193. if ( hImc != NULL_HIMC )
  1194. {
  1195. ImmReleaseContext( ped->hwnd, hImc );
  1196. ped->hImcPrev = ImmAssociateContext( ped->hwnd, NULL_HIMC );
  1197. }
  1198. }
  1199. else
  1200. {
  1201. //
  1202. // IME should be enabled
  1203. //
  1204. if ( ped->hImcPrev != NULL_HIMC )
  1205. {
  1206. ped->hImcPrev = ImmAssociateContext( ped->hwnd, ped->hImcPrev );
  1207. //
  1208. // Font and the caret position might be changed while
  1209. // IME was being disabled. Set those now if the window
  1210. // has the focus.
  1211. //
  1212. if ( ped->fFocus )
  1213. {
  1214. POINT pt;
  1215. Edit_SetCompositionFont( ped );
  1216. GetCaretPos( &pt );
  1217. Edit_ImmSetCompositionWindow( ped, pt.x, pt.y );
  1218. }
  1219. }
  1220. }
  1221. Edit_InitInsert(ped, GetKeyboardLayout(0));
  1222. }
  1223. //---------------------------------------------------------------------------//
  1224. VOID Edit_ImmSetCompositionWindow(PED ped, LONG x, LONG y)
  1225. {
  1226. COMPOSITIONFORM cf = {0};
  1227. COMPOSITIONFORM cft = {0};
  1228. RECT rcScreenWindow;
  1229. HIMC hImc;
  1230. hImc = ImmGetContext(ped->hwnd);
  1231. if ( hImc != NULL_HIMC )
  1232. {
  1233. if ( ped->fFocus )
  1234. {
  1235. GetWindowRect( ped->hwnd, &rcScreenWindow);
  1236. //
  1237. // assuming RECT.left is the first and and RECT.top is the second field
  1238. //
  1239. MapWindowPoints( ped->hwnd, HWND_DESKTOP, (LPPOINT)&rcScreenWindow, 2);
  1240. if (ped->fInReconversion)
  1241. {
  1242. DWORD dwPoint = (DWORD)(ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_POSFROMCHAR, ped->ichMinSel, 0);
  1243. x = GET_X_LPARAM(dwPoint);
  1244. y = GET_Y_LPARAM(dwPoint);
  1245. TraceMsg(TF_STANDARD, "UxEdit: Edit_ImmSetCompositionWindow: fInReconversion (%d,%d)", x, y);
  1246. }
  1247. //
  1248. // The window currently has the focus.
  1249. //
  1250. if (ped->fSingle)
  1251. {
  1252. //
  1253. // Single line edit control.
  1254. //
  1255. cf.dwStyle = CFS_POINT;
  1256. cf.ptCurrentPos.x = x;
  1257. cf.ptCurrentPos.y = y;
  1258. SetRectEmpty(&cf.rcArea);
  1259. }
  1260. else
  1261. {
  1262. //
  1263. // Multi line edit control.
  1264. //
  1265. cf.dwStyle = CFS_RECT;
  1266. cf.ptCurrentPos.x = x;
  1267. cf.ptCurrentPos.y = y;
  1268. cf.rcArea = ped->rcFmt;
  1269. }
  1270. ImmGetCompositionWindow( hImc, &cft );
  1271. if ( (!RtlEqualMemory(&cf,&cft,sizeof(COMPOSITIONFORM))) ||
  1272. (ped->ptScreenBounding.x != rcScreenWindow.left) ||
  1273. (ped->ptScreenBounding.y != rcScreenWindow.top) )
  1274. {
  1275. ped->ptScreenBounding.x = rcScreenWindow.left;
  1276. ped->ptScreenBounding.y = rcScreenWindow.top;
  1277. ImmSetCompositionWindow( hImc, &cf );
  1278. }
  1279. }
  1280. ImmReleaseContext( ped->hwnd, hImc );
  1281. }
  1282. }
  1283. //---------------------------------------------------------------------------//
  1284. VOID Edit_SetCompositionFont(PED ped)
  1285. {
  1286. HIMC hImc;
  1287. LOGFONTW lf;
  1288. hImc = ImmGetContext( ped->hwnd );
  1289. if (hImc != NULL_HIMC)
  1290. {
  1291. if (ped->hFont)
  1292. {
  1293. GetObjectW(ped->hFont, sizeof(LOGFONTW), (LPLOGFONTW)&lf);
  1294. }
  1295. else
  1296. {
  1297. GetObjectW(GetStockObject(SYSTEM_FONT), sizeof(LOGFONTW), (LPLOGFONTW)&lf);
  1298. }
  1299. ImmSetCompositionFontW( hImc, &lf );
  1300. ImmReleaseContext( ped->hwnd, hImc );
  1301. }
  1302. }
  1303. //---------------------------------------------------------------------------//
  1304. //
  1305. // Edit_InitInsert
  1306. //
  1307. // this function is called when:
  1308. // 1) a edit control window is initialized
  1309. // 2) active keyboard layout of current thread is changed
  1310. // 3) read only attribute of this edit control is changed
  1311. //
  1312. VOID Edit_InitInsert( PED ped, HKL hkl )
  1313. {
  1314. ped->fKorea = FALSE;
  1315. ped->fInsertCompChr = FALSE;
  1316. ped->fNoMoveCaret = FALSE;
  1317. ped->fResultProcess = FALSE;
  1318. if (g_fIMMEnabled && ImmIsIME(hkl) )
  1319. {
  1320. if (PRIMARYLANGID(LOWORD(HandleToUlong(hkl))) == LANG_KOREAN )
  1321. {
  1322. ped->fKorea = TRUE;
  1323. }
  1324. //
  1325. // LATER:this flag should be set based on the IME caps
  1326. // retrieved from IME. (Such IME caps should be defined)
  1327. // For now, we can safely assume that only Korean IMEs
  1328. // set CS_INSERTCHAR.
  1329. //
  1330. if ( ped->fKorea )
  1331. {
  1332. ped->fInsertCompChr = TRUE;
  1333. }
  1334. }
  1335. //
  1336. // if we had a composition character, the shape of caret
  1337. // is changed. We need to reset the caret shape.
  1338. //
  1339. if ( ped->fReplaceCompChr )
  1340. {
  1341. ped->fReplaceCompChr = FALSE;
  1342. Edit_SetCaretHandler( ped );
  1343. }
  1344. }
  1345. //---------------------------------------------------------------------------//
  1346. VOID Edit_SetCaretHandler(PED ped)
  1347. {
  1348. HDC hdc;
  1349. PSTR pText;
  1350. SIZE size = {0};
  1351. //
  1352. // In any case destroy caret beforehand otherwise SetCaretPos()
  1353. // will get crazy.. win95d-B#992,B#2370
  1354. //
  1355. if (ped->fFocus)
  1356. {
  1357. HideCaret(ped->hwnd);
  1358. DestroyCaret();
  1359. if ( ped->fReplaceCompChr )
  1360. {
  1361. hdc = Edit_GetDC(ped, TRUE );
  1362. pText = Edit_Lock(ped);
  1363. if ( ped->fAnsi)
  1364. {
  1365. GetTextExtentPointA(hdc, pText + ped->ichCaret, 2, &size);
  1366. }
  1367. else
  1368. {
  1369. GetTextExtentPointW(hdc, (LPWSTR)pText + ped->ichCaret, 1, &size);
  1370. }
  1371. Edit_Unlock(ped);
  1372. Edit_ReleaseDC(ped, hdc, TRUE);
  1373. CreateCaret(ped->hwnd, (HBITMAP)NULL, size.cx, ped->lineHeight);
  1374. }
  1375. else
  1376. {
  1377. CreateCaret(ped->hwnd,
  1378. (HBITMAP)NULL,
  1379. (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
  1380. ped->lineHeight);
  1381. }
  1382. hdc = Edit_GetDC(ped, TRUE );
  1383. if ( ped->fSingle )
  1384. {
  1385. EditSL_SetCaretPosition( ped, hdc );
  1386. }
  1387. else
  1388. {
  1389. EditML_SetCaretPosition( ped, hdc );
  1390. }
  1391. Edit_ReleaseDC(ped, hdc, TRUE);
  1392. ShowCaret(ped->hwnd);
  1393. }
  1394. }
  1395. //---------------------------------------------------------------------------//
  1396. #define GET_COMPOSITION_STRING (ped->fAnsi ? ImmGetCompositionStringA : ImmGetCompositionStringW)
  1397. BOOL Edit_ResultStrHandler(PED ped)
  1398. {
  1399. HIMC himc;
  1400. LPSTR lpStr;
  1401. LONG dwLen;
  1402. ped->fInsertCompChr = FALSE; // clear the state
  1403. ped->fNoMoveCaret = FALSE;
  1404. himc = ImmGetContext(ped->hwnd);
  1405. if ( himc == NULL_HIMC )
  1406. {
  1407. return FALSE;
  1408. }
  1409. dwLen = GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, NULL, 0);
  1410. if (dwLen == 0)
  1411. {
  1412. ImmReleaseContext(ped->hwnd, himc);
  1413. return FALSE;
  1414. }
  1415. dwLen *= ped->cbChar;
  1416. dwLen += ped->cbChar;
  1417. lpStr = (LPSTR)GlobalAlloc(GPTR, dwLen);
  1418. if (lpStr == NULL)
  1419. {
  1420. ImmReleaseContext(ped->hwnd, himc);
  1421. return FALSE;
  1422. }
  1423. GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, lpStr, dwLen);
  1424. if (ped->fSingle)
  1425. {
  1426. EditSL_ReplaceSel(ped, lpStr);
  1427. }
  1428. else
  1429. {
  1430. EditML_ReplaceSel(ped, lpStr);
  1431. }
  1432. GlobalFree((HGLOBAL)lpStr);
  1433. ImmReleaseContext(ped->hwnd, himc);
  1434. ped->fReplaceCompChr = FALSE;
  1435. ped->fNoMoveCaret = FALSE;
  1436. ped->fResultProcess = FALSE;
  1437. Edit_SetCaretHandler(ped);
  1438. return TRUE;
  1439. }
  1440. //---------------------------------------------------------------------------//
  1441. LRESULT Edit_ImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
  1442. {
  1443. INT ich;
  1444. LRESULT lReturn = 1;
  1445. HDC hdc;
  1446. BOOL fSLTextUpdated = FALSE;
  1447. ICH iResult;
  1448. HIMC hImc;
  1449. BYTE TextBuf[4];
  1450. if (!ped->fInsertCompChr)
  1451. {
  1452. if (lParam & GCS_RESULTSTR)
  1453. {
  1454. Edit_InOutReconversionMode(ped, FALSE);
  1455. if (!ped->fKorea && ped->wImeStatus & EIMES_GETCOMPSTRATONCE)
  1456. {
  1457. ResultAtOnce:
  1458. Edit_ResultStrHandler(ped);
  1459. lParam &= ~GCS_RESULTSTR;
  1460. }
  1461. }
  1462. return DefWindowProc(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1463. }
  1464. //
  1465. // In case of Ansi edit control, the length of minimum composition string
  1466. // is 2. Check here maximum byte of edit control.
  1467. //
  1468. if( ped->fAnsi && ped->cchTextMax == 1 )
  1469. {
  1470. HIMC hImc;
  1471. hImc = ImmGetContext( ped->hwnd );
  1472. ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
  1473. ImmReleaseContext( ped->hwnd, hImc );
  1474. MessageBeep(MB_ICONEXCLAMATION);
  1475. return lReturn;
  1476. }
  1477. //
  1478. // Don't move this after CS_NOMOVECARET check.
  1479. // In case if skip the message, fNoMoveCaret should not be set.
  1480. //
  1481. if ((lParam & CS_INSERTCHAR) && ped->fResultProcess)
  1482. {
  1483. //
  1484. // Now we're in result processing. GCS_RESULTSTR ends up
  1485. // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
  1486. // the message(s) will come later than this CS_INSERTCHAR
  1487. // message. This composition character should be handled
  1488. // after the WM_CHAR message(s).
  1489. //
  1490. if(ped->fAnsi)
  1491. {
  1492. PostMessageA(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1493. }
  1494. else
  1495. {
  1496. PostMessageW(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1497. }
  1498. ped->fResultProcess = FALSE;
  1499. return lReturn;
  1500. }
  1501. if (lParam & GCS_RESULTSTR)
  1502. {
  1503. if (!ped->fKorea && ped->wImeStatus & EIMES_GETCOMPSTRATONCE)
  1504. {
  1505. goto ResultAtOnce;
  1506. }
  1507. ped->fResultProcess = TRUE;
  1508. if ( ped->fReplaceCompChr )
  1509. {
  1510. //
  1511. // we have a DBCS character to be replaced.
  1512. // let's delete it before inserting the new one.
  1513. //
  1514. ich = (ped->fAnsi) ? 2 : 1;
  1515. ped->fReplaceCompChr = FALSE;
  1516. ped->ichMaxSel = min(ped->ichCaret + ich, ped->cch);
  1517. ped->ichMinSel = ped->ichCaret;
  1518. if ( Edit_DeleteText( ped ) > 0 )
  1519. {
  1520. if ( ped->fSingle )
  1521. {
  1522. //
  1523. // Update the display
  1524. //
  1525. Edit_NotifyParent(ped, EN_UPDATE);
  1526. hdc = Edit_GetDC(ped,FALSE);
  1527. EditSL_DrawText(ped, hdc, 0);
  1528. Edit_ReleaseDC(ped,hdc,FALSE);
  1529. //
  1530. // Tell parent our text contents changed.
  1531. //
  1532. Edit_NotifyParent(ped, EN_CHANGE);
  1533. }
  1534. }
  1535. Edit_SetCaretHandler( ped );
  1536. }
  1537. }
  1538. else if (lParam & CS_INSERTCHAR)
  1539. {
  1540. //
  1541. // If we are in the middle of a mousedown command, don't do anything.
  1542. //
  1543. if (ped->fMouseDown)
  1544. {
  1545. return lReturn;
  1546. }
  1547. //
  1548. // We can safely assume that interimm character is always DBCS.
  1549. //
  1550. ich = ( ped->fAnsi ) ? 2 : 1;
  1551. if ( ped->fReplaceCompChr )
  1552. {
  1553. //
  1554. // we have a character to be replaced.
  1555. // let's delete it before inserting the new one.
  1556. // when we have a composition characters, the
  1557. // caret is placed before the composition character.
  1558. //
  1559. ped->ichMaxSel = min(ped->ichCaret+ich, ped->cch);
  1560. ped->ichMinSel = ped->ichCaret;
  1561. }
  1562. //
  1563. // let's delete current selected text or composition character
  1564. //
  1565. if ( ped->fSingle )
  1566. {
  1567. if ( Edit_DeleteText( ped ) > 0 )
  1568. {
  1569. fSLTextUpdated = TRUE;
  1570. }
  1571. }
  1572. else
  1573. {
  1574. EditML_DeleteText( ped );
  1575. }
  1576. //
  1577. // When the composition charcter is canceled, IME may give us NULL wParam,
  1578. // with CS_INSERTCHAR flag on. We shouldn't insert a NULL character.
  1579. //
  1580. if ( wParam != 0 )
  1581. {
  1582. if ( ped->fAnsi )
  1583. {
  1584. TextBuf[0] = HIBYTE(LOWORD(wParam)); // leading byte
  1585. TextBuf[1] = LOBYTE(LOWORD(wParam)); // trailing byte
  1586. TextBuf[2] = '\0';
  1587. }
  1588. else
  1589. {
  1590. TextBuf[0] = LOBYTE(LOWORD(wParam));
  1591. TextBuf[1] = HIBYTE(LOWORD(wParam));
  1592. TextBuf[2] = '\0';
  1593. TextBuf[3] = '\0';
  1594. }
  1595. if ( ped->fSingle )
  1596. {
  1597. iResult = EditSL_InsertText( ped, (LPSTR)TextBuf, ich );
  1598. if (iResult == 0)
  1599. {
  1600. //
  1601. // Couldn't insert the text, for e.g. the text exceeded the limit.
  1602. //
  1603. MessageBeep(0);
  1604. }
  1605. else if (iResult > 0)
  1606. {
  1607. //
  1608. // Remember we need to update the text.
  1609. //
  1610. fSLTextUpdated = TRUE;
  1611. }
  1612. }
  1613. else
  1614. {
  1615. iResult = EditML_InsertText( ped, (LPSTR)TextBuf, ich, TRUE);
  1616. }
  1617. if ( iResult > 0 )
  1618. {
  1619. //
  1620. // ped->fReplaceCompChr will be reset:
  1621. //
  1622. // 1) when the character is finalized.
  1623. // we will receive GCS_RESULTSTR
  1624. //
  1625. // 2) when the character is canceled.
  1626. //
  1627. // we will receive WM_IME_COMPOSITION|CS_INSERTCHAR
  1628. // with wParam == 0 (in case of user types backspace
  1629. // at the first element of composition character).
  1630. //
  1631. // or
  1632. //
  1633. // we will receive WM_IME_ENDCOMPOSITION message
  1634. //
  1635. ped->fReplaceCompChr = TRUE;
  1636. //
  1637. // Caret should be placed BEFORE the composition
  1638. // character.
  1639. //
  1640. ped->ichCaret = max( 0, (INT)ped->ichCaret - ich);
  1641. Edit_SetCaretHandler( ped );
  1642. }
  1643. else
  1644. {
  1645. //
  1646. // We failed to insert a character. We might run out
  1647. // of memory, or reached to the text size limit. let's
  1648. // cancel the composition character.
  1649. //
  1650. hImc = ImmGetContext(ped->hwnd);
  1651. ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
  1652. ImmReleaseContext(ped->hwnd, hImc);
  1653. ped->fReplaceCompChr = FALSE;
  1654. Edit_SetCaretHandler( ped );
  1655. }
  1656. }
  1657. else
  1658. {
  1659. //
  1660. // the composition character is canceled.
  1661. //
  1662. ped->fReplaceCompChr = FALSE;
  1663. Edit_SetCaretHandler( ped );
  1664. }
  1665. //
  1666. // We won't notify parent the text change
  1667. // because the composition character has
  1668. // not been finalized.
  1669. //
  1670. if ( fSLTextUpdated )
  1671. {
  1672. //
  1673. // Update the display
  1674. //
  1675. Edit_NotifyParent(ped, EN_UPDATE);
  1676. hdc = Edit_GetDC(ped,FALSE);
  1677. if ( ped->fReplaceCompChr )
  1678. {
  1679. //
  1680. // move back the caret to the original position
  1681. // temporarily so that our new block cursor can
  1682. // be located within the visible area of window.
  1683. //
  1684. ped->ichCaret = min( ped->cch, ped->ichCaret + ich);
  1685. EditSL_ScrollText(ped, hdc);
  1686. ped->ichCaret = max( 0, (INT)ped->ichCaret - ich);
  1687. }
  1688. else
  1689. {
  1690. EditSL_ScrollText(ped, hdc);
  1691. }
  1692. EditSL_DrawText(ped, hdc, 0);
  1693. Edit_ReleaseDC(ped,hdc,FALSE);
  1694. //
  1695. // Tell parent our text contents changed.
  1696. //
  1697. Edit_NotifyParent(ped, EN_CHANGE);
  1698. }
  1699. return lReturn;
  1700. }
  1701. return DefWindowProc(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1702. }
  1703. //---------------------------------------------------------------------------//
  1704. //
  1705. // HanjaKeyHandler
  1706. //
  1707. // VK_HANJA handler - Korean only
  1708. //
  1709. BOOL HanjaKeyHandler(PED ped)
  1710. {
  1711. BOOL changeSelection = FALSE;
  1712. if (ped->fKorea && !ped->fReadOnly)
  1713. {
  1714. ICH oldCaret = ped->ichCaret;
  1715. if (ped->fReplaceCompChr)
  1716. {
  1717. return FALSE;
  1718. }
  1719. if (ped->ichMinSel < ped->ichMaxSel)
  1720. {
  1721. ped->ichCaret = ped->ichMinSel;
  1722. }
  1723. if (!ped->cch || ped->cch == ped->ichCaret)
  1724. {
  1725. ped->ichCaret = oldCaret;
  1726. MessageBeep(MB_ICONEXCLAMATION);
  1727. return FALSE;
  1728. }
  1729. if (ped->fAnsi)
  1730. {
  1731. if (ImmEscapeA(GetKeyboardLayout(0), ImmGetContext(ped->hwnd),
  1732. IME_ESC_HANJA_MODE, (Edit_Lock(ped) + ped->ichCaret * ped->cbChar)))
  1733. {
  1734. changeSelection = TRUE;
  1735. }
  1736. else
  1737. {
  1738. ped->ichCaret = oldCaret;
  1739. }
  1740. Edit_Unlock(ped);
  1741. }
  1742. else
  1743. {
  1744. if (ImmEscapeW(GetKeyboardLayout(0), ImmGetContext(ped->hwnd),
  1745. IME_ESC_HANJA_MODE, (Edit_Lock(ped) + ped->ichCaret * ped->cbChar)))
  1746. {
  1747. changeSelection = TRUE;
  1748. }
  1749. else
  1750. {
  1751. ped->ichCaret = oldCaret;
  1752. }
  1753. Edit_Unlock(ped);
  1754. }
  1755. }
  1756. return changeSelection;
  1757. }
  1758. //---------------------------------------------------------------------------//
  1759. // Edit_RequestHandler()
  1760. //
  1761. // Handles WM_IME_REQUEST message originated by IME
  1762. //
  1763. #define MAX_ECDOCFEED 20
  1764. ICH Edit_ImeGetDocFeedMin(PED ped, LPSTR lpstr)
  1765. {
  1766. ICH ich;
  1767. if (ped->ichMinSel > MAX_ECDOCFEED)
  1768. {
  1769. ich = ped->ichMinSel - MAX_ECDOCFEED;
  1770. ich = Edit_AdjustIch(ped, lpstr, ich);
  1771. }
  1772. else
  1773. {
  1774. ich = 0;
  1775. }
  1776. return ich;
  1777. }
  1778. ICH Edit_ImeGetDocFeedMax(PED ped, LPSTR lpstr)
  1779. {
  1780. ICH ich;
  1781. if ((ped->cch - ped->ichMaxSel) > MAX_ECDOCFEED)
  1782. {
  1783. ich = ped->ichMaxSel + MAX_ECDOCFEED;
  1784. ich = Edit_AdjustIch(ped, lpstr, ich);
  1785. }
  1786. else
  1787. {
  1788. ich = ped->cch;
  1789. }
  1790. return ich;
  1791. }
  1792. LRESULT Edit_RequestHandler(PED ped, WPARAM dwSubMsg, LPARAM lParam)
  1793. {
  1794. LRESULT lreturn = 0L;
  1795. switch (dwSubMsg)
  1796. {
  1797. case IMR_CONFIRMRECONVERTSTRING:
  1798. //
  1799. // CHECK VERSION of the structure
  1800. //
  1801. if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0)
  1802. {
  1803. TraceMsg(TF_STANDARD, "Edit_RequestHandler: RECONVERTSTRING dwVersion is not expected.",
  1804. ((LPRECONVERTSTRING)lParam)->dwVersion);
  1805. return 0L;
  1806. }
  1807. if (lParam && ped && ped->fFocus && ped->hText && ImmIsIME(GetKeyboardLayout(0)))
  1808. {
  1809. LPVOID lpSrc;
  1810. lpSrc = Edit_Lock(ped);
  1811. if (lpSrc == NULL)
  1812. {
  1813. TraceMsg(TF_STANDARD, "Edit_RequestHandler: LOCALLOCK(ped) failed.");
  1814. }
  1815. else
  1816. {
  1817. LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
  1818. ICH ichStart;
  1819. ICH ichEnd;
  1820. UINT cchLen;
  1821. ichStart = Edit_ImeGetDocFeedMin(ped, lpSrc);
  1822. ichEnd = Edit_ImeGetDocFeedMax(ped, lpSrc);
  1823. UserAssert(ichEnd >= ichStart);
  1824. cchLen = ichEnd - ichStart; // holds character count.
  1825. Edit_Unlock(ped);
  1826. if (lpRCS->dwStrLen != cchLen)
  1827. {
  1828. TraceMsg(TF_STANDARD, "Edit_RequestHandler: the given string length is not expected.");
  1829. }
  1830. else
  1831. {
  1832. ICH ichSelStart;
  1833. ICH ichSelEnd;
  1834. ichSelStart = ichStart + (lpRCS->dwCompStrOffset / ped->cbChar);
  1835. ichSelEnd = ichSelStart + lpRCS->dwCompStrLen;
  1836. (ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_SETSEL, ichSelStart, ichSelEnd);
  1837. lreturn = 1L;
  1838. }
  1839. }
  1840. }
  1841. break;
  1842. case IMR_RECONVERTSTRING:
  1843. //
  1844. // CHECK VERSION of the structure
  1845. //
  1846. if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0)
  1847. {
  1848. TraceMsg(TF_STANDARD, "UxEdit: Edit_RequestHandler: RECONVERTSTRING dwVersion is not expected.");
  1849. return 0L;
  1850. }
  1851. if (ped && ped->fFocus && ped->hText && ImmIsIME(GetKeyboardLayout(0)))
  1852. {
  1853. ICH ichStart;
  1854. ICH ichEnd;
  1855. UINT cchLen;
  1856. UINT cchSelLen;
  1857. LPVOID lpSrc;
  1858. lpSrc = Edit_Lock(ped);
  1859. if (lpSrc == NULL)
  1860. {
  1861. TraceMsg(TF_STANDARD, "Edit_RequestHandler: LOCALLOCK(ped) failed.");
  1862. return 0L;
  1863. }
  1864. ichStart = Edit_ImeGetDocFeedMin(ped, lpSrc);
  1865. ichEnd = Edit_ImeGetDocFeedMax(ped, lpSrc);
  1866. UserAssert(ichEnd >= ichStart);
  1867. cchLen = ichEnd - ichStart; // holds character count.
  1868. cchSelLen = ped->ichMaxSel - ped->ichMinSel; // holds character count.
  1869. if (cchLen == 0)
  1870. {
  1871. // if we have no selection,
  1872. // just return 0.
  1873. break;
  1874. }
  1875. UserAssert(ped->cbChar == sizeof(BYTE) || ped->cbChar == sizeof(WCHAR));
  1876. // This Edit Control has selection.
  1877. if (lParam == 0)
  1878. {
  1879. //
  1880. // IME just want to get required size for buffer.
  1881. // cchLen + 1 is needed to reserve room for trailing L'\0'.
  1882. // ~~~~
  1883. lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
  1884. }
  1885. else
  1886. {
  1887. LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
  1888. LPVOID lpDest = (LPBYTE)lpRCS + sizeof(RECONVERTSTRING);
  1889. // check buffer size
  1890. // if the given buffer is smaller than actual needed size,
  1891. // shrink our size to fit the buffer
  1892. if ((INT)lpRCS->dwSize <= sizeof(RECONVERTSTRING) + cchLen * ped->cbChar)
  1893. {
  1894. TraceMsg(TF_STANDARD, "UxEdit: Edit_Request: ERR09");
  1895. cchLen = (lpRCS->dwSize - sizeof(RECONVERTSTRING)) / ped->cbChar - ped->cbChar;
  1896. }
  1897. lpRCS->dwStrOffset = sizeof(RECONVERTSTRING); // buffer begins just after RECONVERTSTRING
  1898. lpRCS->dwCompStrOffset =
  1899. lpRCS->dwTargetStrOffset = (ped->ichMinSel - ichStart) * ped->cbChar; // BYTE count offset
  1900. lpRCS->dwStrLen = cchLen; // TCHAR count
  1901. lpRCS->dwCompStrLen =
  1902. lpRCS->dwTargetStrLen = cchSelLen; // TCHAR count
  1903. RtlCopyMemory(lpDest,
  1904. (LPBYTE)lpSrc + ichStart * ped->cbChar,
  1905. cchLen * ped->cbChar);
  1906. // Null-Terminate the string
  1907. if (ped->fAnsi)
  1908. {
  1909. LPBYTE psz = (LPBYTE)lpDest;
  1910. psz[cchLen] = '\0';
  1911. }
  1912. else
  1913. {
  1914. LPWSTR pwsz = (LPWSTR)lpDest;
  1915. pwsz[cchLen] = L'\0';
  1916. }
  1917. Edit_Unlock(ped);
  1918. // final buffer size
  1919. lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
  1920. Edit_InOutReconversionMode(ped, TRUE);
  1921. Edit_ImmSetCompositionWindow(ped, 0, 0);
  1922. }
  1923. }
  1924. break;
  1925. }
  1926. return lreturn;
  1927. }