Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

edecrare.c

Go to the documentation of this file.
00001 /****************************************************************************\ 00002 * edECRare.c - EC Edit controls Routines Called rarely are to be 00003 * put in a seperate segment _EDECRare. This file contains 00004 * these routines. 00005 * 00006 * Copyright (c) 1985 - 1999, Microsoft Corporation 00007 * 00008 * Support Routines common to Single-line and Multi-Line edit controls 00009 * called Rarely. 00010 * 00011 * Created: 02-08-89 sankar 00012 \****************************************************************************/ 00013 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 00017 00018 extern LOOKASIDE EditLookaside; 00019 00020 #define WS_EX_EDGEMASK (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) 00021 00022 /* 00023 * Those two macros assume PED can be referred as "ped." 00024 */ 00025 #define GetCharABCWidthsAorW ((ped)->fAnsi ? GetCharABCWidthsA : GetCharABCWidthsW) 00026 #define GetCharWidthAorW ((ped)->fAnsi ? GetCharWidthA : GetCharWidthW) 00027 00028 #define umin(a, b) ((unsigned)(a) < (unsigned)(b) ? (unsigned)(a) : (unsigned)(b)) 00029 00030 typedef BOOL (*PFNABCWIDTHS)(HDC, UINT, UINT, LPABC); 00031 typedef BOOL (*PFNCHARWIDTH)(HDC, UINT, UINT, LPINT); 00032 00033 /***************************************************************************\ 00034 * 00035 * GetMaxOverlapChars - Gives maximum number of overlapping characters due to 00036 * negative A or C widths. 00037 * 00038 \***************************************************************************/ 00039 DWORD GetMaxOverlapChars( void ) 00040 { 00041 return (DWORD) MAKELONG( gpsi->wMaxLeftOverlapChars, gpsi->wMaxRightOverlapChars ) ; 00042 } 00043 00044 /***************************************************************************\ 00045 * 00046 * ECSetMargin() 00047 * 00048 \***************************************************************************/ 00049 void ECSetMargin(PED ped, UINT wFlags, long lMarginValues, BOOL fRedraw) 00050 { 00051 BOOL fUseFontInfo = FALSE; 00052 UINT wValue, wOldLeftMargin, wOldRightMargin; 00053 00054 00055 if (wFlags & EC_LEFTMARGIN) /* Set the left margin */ { 00056 00057 if ((int) (wValue = (int)(short)LOWORD(lMarginValues)) < 0) { 00058 fUseFontInfo = TRUE; 00059 wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegA); 00060 } 00061 00062 ped->rcFmt.left += wValue - ped->wLeftMargin; 00063 wOldLeftMargin = ped->wLeftMargin; 00064 ped->wLeftMargin = wValue; 00065 } 00066 00067 if (wFlags & EC_RIGHTMARGIN) /* Set the Right margin */ { 00068 00069 if ((int) (wValue = (int)(short)HIWORD(lMarginValues)) < 0) { 00070 fUseFontInfo = TRUE; 00071 wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegC); 00072 } 00073 00074 ped->rcFmt.right -= wValue - ped->wRightMargin; 00075 wOldRightMargin = ped->wRightMargin; 00076 ped->wRightMargin = wValue; 00077 } 00078 00079 if (fUseFontInfo) { 00080 if (ped->rcFmt.right - ped->rcFmt.left < 2 * ped->aveCharWidth) { 00081 RIPMSG0(RIP_WARNING, "ECSetMargin: rcFmt is too narrow for EC_USEFONTINFO"); 00082 00083 if (wFlags & EC_LEFTMARGIN) /* Reset the left margin */ { 00084 ped->rcFmt.left += wOldLeftMargin - ped->wLeftMargin; 00085 ped->wLeftMargin = wOldLeftMargin; 00086 } 00087 00088 if (wFlags & EC_RIGHTMARGIN) /* Reset the Right margin */ { 00089 ped->rcFmt.right -= wOldRightMargin - ped->wRightMargin; 00090 ped->wRightMargin = wOldRightMargin; 00091 } 00092 00093 return; 00094 } 00095 } 00096 00097 // NtUserInvalidateRect(ped->hwnd, NULL, TRUE); 00098 if (fRedraw) { 00099 ECInvalidateClient(ped, TRUE); 00100 } 00101 } 00102 00103 // -------------------------------------------------------------------------- 00104 // 00105 // ECCalcMarginfForDBCSFont() 00106 // 00107 // Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (edecrare.c) 00108 // -------------------------------------------------------------------------- 00109 void ECCalcMarginForDBCSFont(PED ped, BOOL fRedraw) 00110 { 00111 if (!ped->fTrueType) 00112 return; 00113 00114 if (!ped->fSingle) { 00115 // wMaxNegA came from ABC CharWidth. 00116 if (ped->wMaxNegA != 0) { 00117 ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN, 00118 MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO),fRedraw); 00119 } 00120 } else { 00121 int iMaxNegA = 0, iMaxNegC = 0; 00122 int i; 00123 PVOID lpBuffer; 00124 LPABC lpABCBuff; 00125 ABC ABCInfo; 00126 HFONT hOldFont; 00127 HDC hdc = NtUserGetDC(ped->hwnd); 00128 00129 if (!ped->hFont || !(hOldFont = SelectFont(hdc, ped->hFont))) { 00130 ReleaseDC(ped->hwnd, hdc); 00131 return; 00132 } 00133 00134 if (lpBuffer = UserLocalAlloc(0,sizeof(ABC) * 256)) { 00135 lpABCBuff = lpBuffer; 00136 GetCharABCWidthsAorW(hdc, 0, 255, lpABCBuff); 00137 } else { 00138 lpABCBuff = &ABCInfo; 00139 GetCharABCWidthsAorW(hdc, 0, 0, lpABCBuff); 00140 } 00141 00142 i = 0; 00143 while (TRUE) { 00144 iMaxNegA = min(iMaxNegA, lpABCBuff->abcA); 00145 iMaxNegC = min(iMaxNegC, lpABCBuff->abcC); 00146 if (++i == 256) 00147 break; 00148 if (lpBuffer) { 00149 lpABCBuff++; 00150 } else { 00151 GetCharABCWidthsAorW(hdc, i, i, lpABCBuff); 00152 } 00153 } 00154 00155 SelectFont(hdc, hOldFont); 00156 00157 if (lpBuffer) UserLocalFree(lpBuffer); 00158 00159 ReleaseDC(ped->hwnd, hdc); 00160 00161 if ((iMaxNegA != 0) || (iMaxNegC != 0)) 00162 ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN, 00163 MAKELONG((UINT)(-iMaxNegC), (UINT)(-iMaxNegA)),fRedraw); 00164 } 00165 00166 return; 00167 } 00168 00169 // -------------------------------------------------------------------------- 00170 // 00171 // GetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy) 00172 // 00173 // Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (wmclient.c) 00174 // -------------------------------------------------------------------------- 00175 00176 WCHAR AveCharWidthData[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 00177 // 00178 // if an app set a font for vertical writing, even though we don't 00179 // handle it with EC, the escapement of tm can be NON 0. Then cxWidth from 00180 // GetCharDimenstions() could be 0 in GetCharDimensions(). 00181 // This will break our caller who don't expect 0 at return. So I created 00182 // this entry for the case the caller set vertical font. 00183 // 00184 // 00185 int UserGetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy) 00186 { 00187 int cxWidth; 00188 TEXTMETRIC tm; 00189 LOGFONTW lf; 00190 WCHAR wchFaceName[LF_FACESIZE]; 00191 00192 // 00193 // Is this font vertical font ?? 00194 // 00195 GetTextFaceW(hDC, LF_FACESIZE, wchFaceName); 00196 if (wchFaceName[0] != L'@') { 00197 // 00198 // if not call GDI... 00199 // 00200 return(GdiGetCharDimensions(hDC, lptm, lpcy)); 00201 } 00202 00203 if (!lptm) 00204 lptm = &tm; 00205 00206 GetTextMetrics(hDC, lptm); 00207 00208 // TMPF_FIXED_PITCH 00209 // 00210 // If this bit is set the font is a variable pitch font. 00211 // If this bit is clear the font is a fixed pitch font. 00212 // Note very carefully that those meanings are the opposite of what the constant name implies. 00213 // 00214 if (!(lptm->tmPitchAndFamily & TMPF_FIXED_PITCH)) { // If !variable_width font 00215 // This is fixed pitch font.... 00216 cxWidth = lptm->tmAveCharWidth; 00217 } else { 00218 // This is variable pitch font... 00219 if (hfont && GetObjectW(hfont, sizeof(LOGFONTW), &lf) && (lf.lfEscapement != 0)) { 00220 cxWidth = lptm->tmAveCharWidth; 00221 } else { 00222 SIZE size; 00223 GetTextExtentPointW(hDC, AveCharWidthData, 52, &size); 00224 cxWidth = ((size.cx / 26) + 1) / 2; 00225 } 00226 } 00227 00228 if (lpcy) 00229 *lpcy = lptm->tmHeight; 00230 00231 return(cxWidth); 00232 } 00233 00234 /***************************************************************************\ 00235 * ECGetText AorW 00236 * 00237 * Copies at most maxCchToCopy chars to the buffer lpBuffer. Returns 00238 * how many chars were actually copied. Null terminates the string based 00239 * on the fNullTerminate flag: 00240 * fNullTerminate --> at most (maxCchToCopy - 1) characters will be copied 00241 * !fNullTerminate --> at most (maxCchToCopy) characters will be copied 00242 * 00243 * History: 00244 \***************************************************************************/ 00245 00246 ICH ECGetText( 00247 PED ped, 00248 ICH maxCchToCopy, 00249 LPSTR lpBuffer, 00250 BOOL fNullTerminate) 00251 { 00252 PSTR pText; 00253 00254 if (maxCchToCopy) { 00255 00256 /* 00257 * Zero terminator takes the extra byte 00258 */ 00259 if (fNullTerminate) 00260 maxCchToCopy--; 00261 maxCchToCopy = min(maxCchToCopy, ped->cch); 00262 00263 /* 00264 * Zero terminate the string 00265 */ 00266 if (ped->fAnsi) 00267 *(LPSTR)(lpBuffer + maxCchToCopy) = 0; 00268 else 00269 *(((LPWSTR)lpBuffer) + maxCchToCopy) = 0; 00270 00271 pText = ECLock(ped); 00272 RtlCopyMemory(lpBuffer, pText, maxCchToCopy*ped->cbChar); 00273 ECUnlock(ped); 00274 } 00275 00276 return maxCchToCopy; 00277 } 00278 00279 /***************************************************************************\ 00280 * ECNcCreate AorW 00281 * 00282 * History: 00283 \***************************************************************************/ 00284 00285 BOOL ECNcCreate( 00286 PED ped, 00287 PWND pwnd, 00288 LPCREATESTRUCT lpCreateStruct) 00289 { 00290 HWND hwnd = HWq(pwnd); 00291 BOOL fAnsi; 00292 00293 fAnsi = TestWF(pwnd, WFANSICREATOR); 00294 00295 /* 00296 * Initialize the ped 00297 */ 00298 ped->fEncoded = FALSE; 00299 ped->iLockLevel = 0; 00300 00301 ped->chLines = NULL; 00302 ped->pTabStops = NULL; 00303 ped->charWidthBuffer = NULL; 00304 ped->fAnsi = fAnsi ? 1 : 0; // Force TRUE to be 1 because its a 1 bit field 00305 ped->cbChar = (WORD)(fAnsi ? sizeof(CHAR) : sizeof(WCHAR)); 00306 ped->hInstance = pwnd->hModule; 00307 // IME 00308 ped->hImcPrev = NULL_HIMC; 00309 00310 { 00311 DWORD dwVer = GETEXPWINVER(lpCreateStruct->hInstance); 00312 00313 ped->fWin31Compat = (dwVer >= 0x030a); 00314 ped->f40Compat = (dwVer >= 0x0400); 00315 } 00316 00317 // 00318 // NOTE: 00319 // The order of the following two checks is important. People can 00320 // create edit fields with a 3D and a normal border, and we don't 00321 // want to disallow that. But we need to detect the "no 3D border" 00322 // border case too. 00323 // 00324 if (TestWF(pwnd, WEFEDGEMASK)) 00325 { 00326 ped->fBorder = TRUE; 00327 } 00328 else if (TestWF(pwnd, WFBORDER)) 00329 { 00330 ClearWindowState(pwnd, WFBORDER); 00331 ped->fFlatBorder = TRUE; 00332 ped->fBorder = TRUE; 00333 } 00334 00335 if (!TestWF(pwnd, EFMULTILINE)) 00336 ped->fSingle = TRUE; 00337 00338 if (TestWF(pwnd, WFDISABLED)) 00339 ped->fDisabled = TRUE; 00340 00341 if (TestWF(pwnd, EFREADONLY)) { 00342 if (!ped->fWin31Compat) { 00343 /* 00344 * BACKWARD COMPATIBILITY HACK 00345 * 00346 * "MileStone" unknowingly sets the ES_READONLY style. So, we strip this 00347 * style here for all Win3.0 apps (this style is new for Win3.1). 00348 * Fix for Bug #12982 -- SANKAR -- 01/24/92 -- 00349 */ 00350 ClearWindowState(pwnd, EFREADONLY); 00351 } else 00352 ped->fReadOnly = TRUE; 00353 } 00354 00355 00356 /* 00357 * Allocate storage for the text for the edit controls. Storage for single 00358 * line edit controls will always get allocated in the local data segment. 00359 * Multiline will allocate in the local ds but the app may free this and 00360 * allocate storage elsewhere... 00361 */ 00362 ped->hText = LOCALALLOC(LHND, CCHALLOCEXTRA*ped->cbChar, ped->hInstance); 00363 if (!ped->hText) { 00364 FreeLookasideEntry(&EditLookaside, ped); 00365 NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT); /* No ped for this window */ 00366 return FALSE; /* If no_memory error */ 00367 } 00368 00369 ped->cchAlloc = CCHALLOCEXTRA; 00370 ped->lineHeight = 1; 00371 00372 ped->hwnd = hwnd; 00373 ped->hwndParent = lpCreateStruct->hwndParent; 00374 00375 ped->wImeStatus = 0; 00376 00377 return (BOOL)DefWindowProcWorker(pwnd, WM_NCCREATE, 0, 00378 (LPARAM)lpCreateStruct, fAnsi); 00379 } 00380 00381 /***************************************************************************\ 00382 * ECCreate AorW 00383 * 00384 * History: 00385 \***************************************************************************/ 00386 00387 BOOL ECCreate( 00388 PED ped, 00389 LONG windowStyle) 00390 { 00391 HDC hdc; 00392 00393 /* 00394 * Get values from the window instance data structure and put them in the 00395 * ped so that we can access them easier. 00396 */ 00397 if (windowStyle & ES_AUTOHSCROLL) 00398 ped->fAutoHScroll = 1; 00399 if (windowStyle & ES_NOHIDESEL) 00400 ped->fNoHideSel = 1; 00401 00402 ped->format = (LOWORD(windowStyle) & LOWORD(ES_FMTMASK)); 00403 if (TestWF(ped->pwnd, WEFRIGHT) && !ped->format) 00404 ped->format = ES_RIGHT; 00405 00406 ped->cchTextMax = MAXTEXT; /* Max # chars we will initially allow */ 00407 00408 /* 00409 * Set up undo initial conditions... (ie. nothing to undo) 00410 */ 00411 ped->ichDeleted = (ICH)-1; 00412 ped->ichInsStart = (ICH)-1; 00413 ped->ichInsEnd = (ICH)-1; 00414 00415 // initial charset value - need to do this BEFORE MLCreate is called 00416 // so that we know not to fool with scrollbars if nessacary 00417 hdc = ECGetEditDC(ped, TRUE); 00418 ped->charSet = (BYTE)GetTextCharset(hdc); 00419 ECReleaseEditDC(ped, hdc, TRUE); 00420 00421 // FE_IME 00422 // EC_INSERT_COMPOSITION_CHARACTER: ECCreate() - call ECInitInsert() 00423 ECInitInsert(ped, THREAD_HKL()); 00424 00425 if(ped->pLpkEditCallout = fpLpkEditControl) { 00426 return ped->pLpkEditCallout->EditCreate(ped, HW(ped->pwnd)); 00427 } else 00428 return TRUE; 00429 } 00430 00431 /***************************************************************************\ 00432 * ECNcDestroyHandler AorW 00433 * 00434 * Destroys the edit control ped by freeing up all memory used by it. 00435 * 00436 * History: 00437 \***************************************************************************/ 00438 00439 void ECNcDestroyHandler( 00440 PWND pwnd, 00441 PED ped) 00442 { 00443 PWND pwndParent; 00444 00445 /* 00446 * ped could be NULL if WM_NCCREATE failed to create it... 00447 */ 00448 if (ped) { 00449 00450 /* 00451 * Free the text buffer (always present?) 00452 */ 00453 LOCALFREE(ped->hText, ped->hInstance); 00454 00455 /* 00456 * Free up undo buffer and line start array (if present) 00457 */ 00458 if (ped->hDeletedText != NULL) 00459 UserGlobalFree(ped->hDeletedText); 00460 00461 /* 00462 * Free tab stop buffer (if present) 00463 */ 00464 if (ped->pTabStops) 00465 UserLocalFree(ped->pTabStops); 00466 00467 /* 00468 * Free line start array (if present) 00469 */ 00470 if (ped->chLines) { 00471 UserLocalFree(ped->chLines); 00472 } 00473 00474 /* 00475 * Free the character width buffer (if present) 00476 */ 00477 if (ped->charWidthBuffer) 00478 UserLocalFree(ped->charWidthBuffer); 00479 00480 /* 00481 * Free the cursor bitmap 00482 */ 00483 if (ped->pLpkEditCallout && ped->hCaretBitmap) { 00484 DeleteObject(ped->hCaretBitmap); 00485 } 00486 00487 /* 00488 * Last but not least, free the ped 00489 */ 00490 FreeLookasideEntry(&EditLookaside, ped); 00491 } 00492 00493 /* 00494 * Set the window's fnid status so that we can ignore rogue messages 00495 */ 00496 NtUserSetWindowFNID(HWq(pwnd), FNID_CLEANEDUP_BIT); 00497 00498 /* 00499 * If we're part of a combo box, let it know we're gone 00500 */ 00501 pwndParent = REBASEPWND(pwnd, spwndParent); 00502 if (pwndParent && GETFNID(pwndParent) == FNID_COMBOBOX) { 00503 ComboBoxWndProcWorker(pwndParent, WM_PARENTNOTIFY, 00504 MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd), FALSE); 00505 } 00506 } 00507 00508 /***************************************************************************\ 00509 * ECSetPasswordChar AorW 00510 * 00511 * Sets the password char to display. 00512 * 00513 * History: 00514 \***************************************************************************/ 00515 00516 void ECSetPasswordChar( 00517 PED ped, 00518 UINT pwchar) 00519 { 00520 HDC hdc; 00521 SIZE size; 00522 00523 ped->charPasswordChar = pwchar; 00524 00525 if (pwchar) { 00526 hdc = ECGetEditDC(ped, TRUE); 00527 if (ped->fAnsi) 00528 GetTextExtentPointA(hdc, (LPSTR)&pwchar, 1, &size); 00529 else 00530 GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size); 00531 00532 GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size); 00533 ped->cPasswordCharWidth = max(size.cx, 1); 00534 ECReleaseEditDC(ped, hdc, TRUE); 00535 } 00536 if (pwchar) 00537 SetWindowState(ped->pwnd, EFPASSWORD); 00538 else 00539 ClearWindowState(ped->pwnd, EFPASSWORD); 00540 00541 ECEnableDisableIME(ped); 00542 } 00543 00544 /***************************************************************************\ 00545 * GetNegABCwidthInfo() 00546 * This function fills up the ped->charWidthBuffer buffer with the 00547 * negative A,B and C widths for all the characters below 0x7f in the 00548 * currently selected font. 00549 * Returns: 00550 * TRUE, if the function succeeded. 00551 * FALSE, if GDI calls to get the char widths have failed. 00552 * 00553 * Note: not used if LPK installed 00554 \***************************************************************************/ 00555 BOOL GetNegABCwidthInfo( 00556 PED ped, 00557 HDC hdc) 00558 { 00559 LPABC lpABCbuff; 00560 int i; 00561 int CharWidthBuff[CHAR_WIDTH_BUFFER_LENGTH]; // Local char width buffer. 00562 int iOverhang; 00563 00564 if (!GetCharABCWidthsA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPABC)ped->charWidthBuffer)) { 00565 RIPMSG0(RIP_WARNING, "GetNegABCwidthInfo: GetCharABCWidthsA Failed"); 00566 return FALSE; 00567 } 00568 00569 // The (A+B+C) returned for some fonts (eg: Lucida Caligraphy) does not 00570 // equal the actual advanced width returned by GetCharWidths() minus overhang. 00571 // This is due to font bugs. So, we adjust the 'B' width so that this 00572 // discrepancy is removed. 00573 // Fix for Bug #2932 --sankar-- 02/17/93 00574 iOverhang = ped->charOverhang; 00575 GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPINT)CharWidthBuff); 00576 lpABCbuff = (LPABC)ped->charWidthBuffer; 00577 for(i = 0; i < CHAR_WIDTH_BUFFER_LENGTH; i++) { 00578 lpABCbuff->abcB = CharWidthBuff[i] - iOverhang 00579 - lpABCbuff->abcA 00580 - lpABCbuff->abcC; 00581 lpABCbuff++; 00582 } 00583 00584 return(TRUE); 00585 } 00586 00587 /***************************************************************************\ 00588 * 00589 * ECSize() - 00590 * 00591 * Handle sizing for an edit control's client rectangle. 00592 * Use lprc as the bounding rectangle if specified; otherwise use the current 00593 * client rectangle. 00594 * 00595 \***************************************************************************/ 00596 00597 void ECSize( 00598 PED ped, 00599 LPRECT lprc, 00600 BOOL fRedraw) 00601 { 00602 RECT rc; 00603 00604 /* 00605 * BiDi VB32 Creates an Edit Control and immediately sends a WM_SIZE 00606 * message which causes EXSize to be called before ECSetFont, which 00607 * in turn causes a divide by zero exception below. This check for 00608 * ped->lineHeight will pick it up safely. [samera] 3/5/97 00609 */ 00610 if(ped->lineHeight == 0) 00611 return; 00612 00613 // assume that we won't be able to display the caret 00614 ped->fCaretHidden = TRUE; 00615 00616 00617 if ( lprc ) 00618 CopyRect(&rc, lprc); 00619 else 00620 _GetClientRect(ped->pwnd, &rc); 00621 00622 if (!(rc.right - rc.left) || !(rc.bottom - rc.top)) { 00623 if (ped->rcFmt.right - ped->rcFmt.left) 00624 return; 00625 00626 rc.left = 0; 00627 rc.top = 0; 00628 rc.right = ped->aveCharWidth * 10; 00629 rc.bottom = ped->lineHeight; 00630 } 00631 00632 if (!lprc) { 00633 // subtract the margins from the given rectangle -- 00634 // make sure that this rectangle is big enough to have these margins. 00635 if ((rc.right - rc.left) > (int)(ped->wLeftMargin + ped->wRightMargin)) { 00636 rc.left += ped->wLeftMargin; 00637 rc.right -= ped->wRightMargin; 00638 } 00639 } 00640 00641 // 00642 // Leave space so text doesn't touch borders. 00643 // For 3.1 compatibility, don't subtract out vertical borders unless 00644 // there is room. 00645 // 00646 if (ped->fBorder) { 00647 int cxBorder = SYSMET(CXBORDER); 00648 int cyBorder = SYSMET(CYBORDER); 00649 00650 if (ped->fFlatBorder) 00651 { 00652 cxBorder *= 2; 00653 cyBorder *= 2; 00654 } 00655 00656 if (rc.bottom < rc.top + ped->lineHeight + 2*cyBorder) 00657 cyBorder = 0; 00658 00659 InflateRect(&rc, -cxBorder, -cyBorder); 00660 } 00661 00662 // Is the resulting rectangle too small? Don't change it then. 00663 if ((!ped->fSingle) && ((rc.right - rc.left < (int) ped->aveCharWidth) || 00664 ((rc.bottom - rc.top) / ped->lineHeight == 0))) 00665 return; 00666 00667 // now, we know we're safe to display the caret 00668 ped->fCaretHidden = FALSE; 00669 00670 CopyRect(&ped->rcFmt, &rc); 00671 00672 if (ped->fSingle) 00673 ped->rcFmt.bottom = min(rc.bottom, rc.top + ped->lineHeight); 00674 else 00675 MLSize(ped, fRedraw); 00676 00677 if (fRedraw) { 00678 NtUserInvalidateRect(ped->hwnd, NULL, TRUE); 00679 // UpdateWindow31(ped->hwnd); Evaluates to NOP in Chicago - Johnl 00680 } 00681 00682 // FE_IME 00683 // ECSize() - call ECImmSetCompositionWindow() 00684 // 00685 // normally this isn't needed because WM_SIZE will cause 00686 // WM_PAINT and the paint handler will take care of IME 00687 // composition window. However when the edit window is 00688 // restored from maximized window and client area is out 00689 // of screen, the window will not be redrawn. 00690 // 00691 if (ped->fFocus && fpImmIsIME(THREAD_HKL())) { 00692 POINT pt; 00693 00694 NtUserGetCaretPos(&pt); 00695 ECImmSetCompositionWindow(ped, pt.x, pt.y); 00696 } 00697 } 00698 00699 /***************************************************************************\ 00700 * 00701 * ECSetFont AorW () - 00702 * 00703 * Sets the font used in the edit control. Warning: Memory compaction may 00704 * occur if the font wasn't previously loaded. If the font handle passed 00705 * in is NULL, assume the system font. 00706 * 00707 \***************************************************************************/ 00708 void ECSetFont( 00709 PED ped, 00710 HFONT hfont, 00711 BOOL fRedraw) 00712 { 00713 short i; 00714 TEXTMETRIC TextMetrics; 00715 HDC hdc; 00716 HFONT hOldFont=NULL; 00717 UINT wBuffSize; 00718 LPINT lpCharWidthBuff; 00719 DWORD dwMaxOverlapChars; 00720 CHWIDTHINFO cwi; 00721 UINT uExtracharPos; 00722 00723 hdc = NtUserGetDC(ped->hwnd); 00724 00725 if (ped->hFont = hfont) { 00726 // 00727 // Since the default font is the system font, no need to select it in 00728 // if that's what the user wants. 00729 // 00730 if (!(hOldFont = SelectObject(hdc, hfont))) { 00731 hfont = ped->hFont = NULL; 00732 } 00733 00734 // 00735 // Get the metrics and ave char width for the currently selected font 00736 // 00737 00738 // 00739 // Call Vertical font-aware AveWidth compute function... 00740 // 00741 // FE_SB 00742 ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight); 00743 00744 /* 00745 * This might fail when people uses network fonts (or bad fonts). 00746 */ 00747 if (ped->aveCharWidth == 0) { 00748 RIPMSG0(RIP_WARNING, "ECSetFont: GdiGetCharDimensions failed"); 00749 if (hOldFont != NULL) { 00750 SelectObject(hdc, hOldFont); 00751 } 00752 00753 /* 00754 * We've messed up the ped so let's reset the font. 00755 * Note that we won't recurse more than once because we'll 00756 * pass hfont == NULL. 00757 * Too bad WM_SETFONT doesn't return a value. 00758 */ 00759 ECSetFont(ped, NULL, fRedraw); 00760 return; 00761 } 00762 } else { 00763 ped->aveCharWidth = gpsi->cxSysFontChar; 00764 ped->lineHeight = gpsi->cySysFontChar; 00765 TextMetrics = gpsi->tmSysFont; 00766 } 00767 00768 ped->charOverhang = TextMetrics.tmOverhang; 00769 00770 //assume that they don't have any negative widths at all. 00771 ped->wMaxNegA = ped->wMaxNegC = ped->wMaxNegAcharPos = ped->wMaxNegCcharPos = 0; 00772 00773 00774 // Check if Proportional Width Font 00775 // 00776 // NOTE: as SDK doc says about TEXTMETRIC: 00777 // TMPF_FIXED_PITCH 00778 // If this bit is set the font is a variable pitch font. If this bit is clear 00779 // the font is a fixed pitch font. Note very carefully that those meanings are 00780 // the opposite of what the constant name implies. 00781 // 00782 // Thus we have to reverse the value using logical not (fNonPropFont has 1 bit width) 00783 // 00784 ped->fNonPropFont = !(TextMetrics.tmPitchAndFamily & FIXED_PITCH); 00785 00786 // Check for a TrueType font 00787 // Older app OZWIN chokes if we allocate a bigger buffer for TrueType fonts 00788 // So, for apps older than 4.0, no special treatment for TrueType fonts. 00789 if (ped->f40Compat && (TextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) { 00790 ped->fTrueType = GetCharWidthInfo(hdc, &cwi); 00791 #if DBG 00792 if (!ped->fTrueType) { 00793 RIPMSG0(RIP_WARNING, "ECSetFont: GetCharWidthInfo Failed"); 00794 } 00795 #endif 00796 } else { 00797 ped->fTrueType = FALSE; 00798 } 00799 00800 // FE_SB 00801 // 00802 // In DBCS Windows, Edit Control must handle Double Byte Character 00803 // if tmCharSet field of textmetrics is double byte character set 00804 // such as SHIFTJIS_CHARSET(128:Japan), HANGEUL_CHARSET(129:Korea). 00805 // 00806 // We call ECGetDBCSVector even when fAnsi is false so that we could 00807 // treat ped->fAnsi and ped->fDBCS indivisually. I changed ECGetDBCSVector 00808 // function so that it returns 0 or 1, because I would like to set ped->fDBCS 00809 // bit field here. 00810 // 00811 ped->fDBCS = ECGetDBCSVector(ped,hdc,TextMetrics.tmCharSet); 00812 ped->charSet = TextMetrics.tmCharSet; 00813 00814 if (ped->fDBCS) { 00815 // 00816 // Free the character width buffer if ped->fDBCS. 00817 // 00818 // I expect single GetTextExtentPoint call is faster than multiple 00819 // GetTextExtentPoint call (because the graphic engine has a cache buffer). 00820 // See editec.c/ECTabTheTextOut(). 00821 // 00822 if (ped->charWidthBuffer) { 00823 LocalFree(ped->charWidthBuffer); 00824 ped->charWidthBuffer = NULL; 00825 } 00826 00827 // 00828 // if FullWidthChar : HalfWidthChar == 2 : 1.... 00829 // 00830 // TextMetrics.tmMaxCharWidth = FullWidthChar width 00831 // ped->aveCharWidth = HalfWidthChar width 00832 // 00833 if (ped->fNonPropFont && 00834 ((ped->aveCharWidth * 2) == TextMetrics.tmMaxCharWidth)) { 00835 ped->fNonPropDBCS = TRUE; 00836 } else { 00837 ped->fNonPropDBCS = FALSE; 00838 } 00839 00840 } else { 00841 00842 // 00843 // Since the font has changed, let us obtain and save the character width 00844 // info for this font. 00845 // 00846 // First left us find out if the maximum chars that can overlap due to 00847 // negative widths. Since we can't access USER globals, we make a call here. 00848 // 00849 if (!(ped->fSingle || ped->pLpkEditCallout)) { // Is this a multiline edit control with no LPK present? 00850 // 00851 // For multiline edit controls, we maintain a buffer that contains 00852 // the character width information. 00853 // 00854 wBuffSize = (ped->fTrueType) ? (CHAR_WIDTH_BUFFER_LENGTH * sizeof(ABC)) : 00855 (CHAR_WIDTH_BUFFER_LENGTH * sizeof(int)); 00856 00857 if (ped->charWidthBuffer) { /* If buffer already present */ 00858 lpCharWidthBuff = ped->charWidthBuffer; 00859 ped->charWidthBuffer = UserLocalReAlloc(lpCharWidthBuff, wBuffSize, HEAP_ZERO_MEMORY); 00860 if (ped->charWidthBuffer == NULL) { 00861 UserLocalFree((HANDLE)lpCharWidthBuff); 00862 } 00863 } else { 00864 ped->charWidthBuffer = UserLocalAlloc(HEAP_ZERO_MEMORY, wBuffSize); 00865 } 00866 00867 if (ped->charWidthBuffer != NULL) { 00868 if (ped->fTrueType) { 00869 ped->fTrueType = GetNegABCwidthInfo(ped, hdc); 00870 } 00871 00872 /* 00873 * It is possible that the above attempts could have failed and reset 00874 * the value of fTrueType. So, let us check that value again. 00875 */ 00876 if (!ped->fTrueType) { 00877 if (!GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, ped->charWidthBuffer)) { 00878 UserLocalFree((HANDLE)ped->charWidthBuffer); 00879 ped->charWidthBuffer=NULL; 00880 } else { 00881 /* 00882 * We need to subtract out the overhang associated with 00883 * each character since GetCharWidth includes it... 00884 */ 00885 for (i=0;i < CHAR_WIDTH_BUFFER_LENGTH;i++) 00886 ped->charWidthBuffer[i] -= ped->charOverhang; 00887 } 00888 } 00889 } /* if (ped->charWidthBuffer != NULL) */ 00890 } /* if (!ped->fSingle) */ 00891 } /* if (ped->fDBCS) */ 00892 00893 { 00894 /* 00895 * Calculate MaxNeg A C metrics 00896 */ 00897 dwMaxOverlapChars = GetMaxOverlapChars(); 00898 if (ped->fTrueType) { 00899 if (cwi.lMaxNegA < 0) 00900 ped->wMaxNegA = -cwi.lMaxNegA; 00901 else 00902 ped->wMaxNegA = 0; 00903 if (cwi.lMaxNegC < 0) 00904 ped->wMaxNegC = -cwi.lMaxNegC; 00905 else 00906 ped->wMaxNegC = 0; 00907 if (cwi.lMinWidthD != 0) { 00908 ped->wMaxNegAcharPos = (ped->wMaxNegA + cwi.lMinWidthD - 1) / cwi.lMinWidthD; 00909 ped->wMaxNegCcharPos = (ped->wMaxNegC + cwi.lMinWidthD - 1) / cwi.lMinWidthD; 00910 if (ped->wMaxNegA + ped->wMaxNegC > (UINT)cwi.lMinWidthD) { 00911 uExtracharPos = (ped->wMaxNegA + ped->wMaxNegC - 1) / cwi.lMinWidthD; 00912 ped->wMaxNegAcharPos += uExtracharPos; 00913 ped->wMaxNegCcharPos += uExtracharPos; 00914 } 00915 } else { 00916 ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left 00917 ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right 00918 } 00919 00920 } else if (ped->charOverhang != 0) { 00921 /* 00922 * Some bitmaps fonts (i.e., italic) have under/overhangs; 00923 * this is pretty much like having negative A and C widths. 00924 */ 00925 ped->wMaxNegA = ped->wMaxNegC = ped->charOverhang; 00926 ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left 00927 ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right 00928 } 00929 } /* if (ped->fDBCS) */ 00930 00931 if (!hfont) { 00932 // 00933 // We are getting the stats for the system font so update the system 00934 // font fields in the ed structure since we use these when calculating 00935 // some spacing. 00936 // 00937 ped->cxSysCharWidth = ped->aveCharWidth; 00938 ped->cySysCharHeight= ped->lineHeight; 00939 } else if (hOldFont) 00940 SelectObject(hdc, hOldFont); 00941 00942 if (ped->fFocus) { 00943 // 00944 // Update the caret. 00945 // 00946 NtUserHideCaret(ped->hwnd); 00947 NtUserDestroyCaret(); 00948 00949 if (ped->pLpkEditCallout) { 00950 ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(), ped->lineHeight, 0); 00951 } 00952 else { 00953 NtUserCreateCaret(ped->hwnd, (HBITMAP)NULL, ECGetCaretWidth(), ped->lineHeight); 00954 } 00955 NtUserShowCaret(ped->hwnd); 00956 } 00957 00958 ReleaseDC(ped->hwnd, hdc); 00959 00960 // 00961 // Update password character. 00962 // 00963 if (ped->charPasswordChar) 00964 ECSetPasswordChar(ped, ped->charPasswordChar); 00965 00966 // 00967 // If it is a TrueType font and it's a new app, set both the margins at the 00968 // max negative width values for all types of the edit controls. 00969 // (NOTE: Can't use ped->f40Compat here because edit-controls inside dialog 00970 // boxes without DS_LOCALEDIT style are always marked as 4.0 compat. 00971 // This is the fix for NETBENCH 3.0) 00972 // 00973 00974 if (ped->fTrueType && (GETAPPVER() >= VER40)) 00975 if (ped->fDBCS) { 00976 // For DBCS TrueType Font, we calc margin from ABC width. 00977 ECCalcMarginForDBCSFont(ped, fRedraw); 00978 } else { 00979 ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN, 00980 MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO), fRedraw); 00981 } 00982 00983 // 00984 // We need to calc maxPixelWidth when font changes. 00985 // If the word-wrap is ON, then this is done in MLSize() called later. 00986 // 00987 if((!ped->fSingle) && (!ped->fWrap)) 00988 MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL); 00989 00990 // 00991 // Recalc the layout. 00992 // 00993 ECSize(ped, NULL, fRedraw); 00994 00995 if ( ped->fFocus && fpImmIsIME(THREAD_HKL()) ) { 00996 ECImmSetCompositionFont( ped ); 00997 } 00998 } 00999 01000 01001 01002 /***************************************************************************\ 01003 * 01004 * ECIsCharNumeric AorW () - 01005 * 01006 * Tests whether the character entered is a numeral. 01007 * For multiline and singleline edit controls with the ES_NUMBER style. 01008 * 01009 \***************************************************************************/ 01010 BOOL ECIsCharNumeric( 01011 PED ped, 01012 DWORD keyPress) 01013 { 01014 WORD wCharType; 01015 01016 if (ped->fAnsi) { 01017 char ch = (char)keyPress; 01018 LCID lcid = (LCID)((ULONG_PTR)THREAD_HKL() & 0xFFFF); 01019 GetStringTypeA(lcid, CT_CTYPE1, &ch, 1, &wCharType); 01020 } else { 01021 WCHAR wch = (WCHAR)keyPress; 01022 GetStringTypeW(CT_CTYPE1, &wch, 1, &wCharType); 01023 } 01024 return (wCharType & C1_DIGIT ? TRUE : FALSE); 01025 } 01026 01027 /***************************************************************************\ 01028 * 01029 * ECEnableDisableIME( PED ped ) 01030 * 01031 * 01032 * xx/xx/9x by somebody Created for Win95 01033 * xx/xx/95 by kazum Ported to NT-J 3.51 01034 * 04/15/96 by takaok Ported to NT 4.0 01035 * 01036 \***************************************************************************/ 01037 VOID ECEnableDisableIME( PED ped ) 01038 { 01039 if ( ped->fReadOnly || ped->charPasswordChar ) { 01040 // 01041 // IME should be disabled 01042 // 01043 HIMC hImc; 01044 hImc = fpImmGetContext( ped->hwnd ); 01045 01046 if ( hImc != NULL_HIMC ) { 01047 fpImmReleaseContext( ped->hwnd, hImc ); 01048 ped->hImcPrev = fpImmAssociateContext( ped->hwnd, NULL_HIMC ); 01049 } 01050 01051 } else { 01052 // 01053 // IME should be enabled 01054 // 01055 if ( ped->hImcPrev != NULL_HIMC ) { 01056 ped->hImcPrev = fpImmAssociateContext( ped->hwnd, ped->hImcPrev ); 01057 01058 // 01059 // Font and the caret position might be changed while 01060 // IME was being disabled. Set those now if the window 01061 // has the focus. 01062 // 01063 if ( ped->fFocus ) { 01064 POINT pt; 01065 01066 ECImmSetCompositionFont( ped ); 01067 01068 NtUserGetCaretPos( &pt ); 01069 ECImmSetCompositionWindow( ped, pt.x, pt.y ); 01070 } 01071 } 01072 } 01073 ECInitInsert(ped, THREAD_HKL()); 01074 } 01075 01076 01077 /***************************************************************************\ 01078 * 01079 * ECImmSetCompositionWindow( PED ped, LONG x, LONG y ) 01080 * 01081 * xx/xx/9x by somebody Created for Win95 01082 * xx/xx/95 by kazum Ported to NT-J 3.51 01083 * 04/15/96 by takaok Ported to NT 4.0 01084 \***************************************************************************/ 01085 VOID ECImmSetCompositionWindow( PED ped, LONG x, LONG y ) 01086 { 01087 COMPOSITIONFORM cf; 01088 COMPOSITIONFORM cft; 01089 RECT rcScreenWindow; 01090 HIMC hImc; 01091 01092 hImc = fpImmGetContext( ped->hwnd ); 01093 if ( hImc != NULL_HIMC ) { 01094 01095 if ( ped->fFocus ) { 01096 GetWindowRect( ped->hwnd, &rcScreenWindow); 01097 // assuming RECT.left is the first and and RECT.top is the second field 01098 MapWindowPoints( ped->hwnd, HWND_DESKTOP, (LPPOINT)&rcScreenWindow, 2); 01099 if (ped->fInReconversion) { 01100 DWORD dwPoint = (DWORD)(ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_POSFROMCHAR, ped->ichMinSel, 0); 01101 01102 x = GET_X_LPARAM(dwPoint); 01103 y = GET_Y_LPARAM(dwPoint); 01104 01105 RIPMSG2(RIP_WARNING, "ECImmSetCompositionWindow: fInReconversion (%d,%d)", x, y); 01106 } 01107 // 01108 // The window currently has the focus. 01109 // 01110 if (ped->fSingle) { 01111 // 01112 // Single line edit control. 01113 // 01114 cf.dwStyle = CFS_POINT; 01115 cf.ptCurrentPos.x = x; 01116 cf.ptCurrentPos.y = y; 01117 SetRectEmpty(&cf.rcArea); 01118 01119 } else { 01120 // 01121 // Multi line edit control. 01122 // 01123 cf.dwStyle = CFS_RECT; 01124 cf.ptCurrentPos.x = x; 01125 cf.ptCurrentPos.y = y; 01126 cf.rcArea = ped->rcFmt; 01127 } 01128 fpImmGetCompositionWindow( hImc, &cft ); 01129 if ( (!RtlEqualMemory(&cf,&cft,sizeof(COMPOSITIONFORM))) || 01130 (ped->ptScreenBounding.x != rcScreenWindow.left) || 01131 (ped->ptScreenBounding.y != rcScreenWindow.top) ) { 01132 01133 ped->ptScreenBounding.x = rcScreenWindow.left; 01134 ped->ptScreenBounding.y = rcScreenWindow.top; 01135 fpImmSetCompositionWindow( hImc, &cf ); 01136 } 01137 } 01138 fpImmReleaseContext( ped->hwnd, hImc ); 01139 } 01140 } 01141 01142 /***************************************************************************\ 01143 * 01144 * ECImmSetCompositionFont( PED ped ) 01145 * 01146 * xx/xx/9x by somebody Created for Win95 01147 * xx/xx/95 by kazum Ported to NT-J 3.51 01148 * 04/15/96 by takaok Ported to NT 4.0 01149 \***************************************************************************/ 01150 VOID ECImmSetCompositionFont( PED ped ) 01151 { 01152 HIMC hImc; 01153 LOGFONTW lf; 01154 01155 if ( (hImc = fpImmGetContext( ped->hwnd )) != NULL_HIMC ) { 01156 01157 if (ped->hFont) { 01158 GetObjectW( ped->hFont, 01159 sizeof(LOGFONTW), 01160 (LPLOGFONTW)&lf); 01161 } else { 01162 GetObjectW( GetStockObject(SYSTEM_FONT), 01163 sizeof(LOGFONTW), 01164 (LPLOGFONTW)&lf); 01165 } 01166 fpImmSetCompositionFontW( hImc, &lf ); 01167 fpImmReleaseContext( ped->hwnd, hImc ); 01168 } 01169 } 01170 01171 01172 /***************************************************************************\ 01173 * 01174 * ECInitInsert( PED ped, HKL hkl ) 01175 * 01176 * this function is called when: 01177 * 1) a edit control window is initialized 01178 * 2) active keyboard layout of current thread is changed 01179 * 3) read only attribute of this edit control is changed 01180 * 01181 * 04/15/96 by takaok Created 01182 \***************************************************************************/ 01183 VOID ECInitInsert( PED ped, HKL hkl ) 01184 { 01185 ped->fKorea = FALSE; 01186 ped->fInsertCompChr = FALSE; 01187 ped->fNoMoveCaret = FALSE; 01188 ped->fResultProcess = FALSE; 01189 01190 if ( fpImmIsIME(hkl) ) { 01191 if ( PRIMARYLANGID(LOWORD(HandleToUlong(hkl))) == LANG_KOREAN ) { 01192 01193 ped->fKorea = TRUE; 01194 } 01195 // 01196 // LATER:this flag should be set based on the IME caps 01197 // retrieved from IME. (Such IME caps should be defined) 01198 // For now, we can safely assume that only Korean IMEs 01199 // set CS_INSERTCHAR. 01200 // 01201 if ( ped->fKorea ) { 01202 ped->fInsertCompChr = TRUE; 01203 } 01204 } 01205 01206 // 01207 // if we had a composition character, the shape of caret 01208 // is changed. We need to reset the caret shape. 01209 // 01210 if ( ped->fReplaceCompChr ) { 01211 ped->fReplaceCompChr = FALSE; 01212 ECSetCaretHandler( ped ); 01213 } 01214 } 01215 01216 /***************************************************************************\ 01217 * 01218 * ECSetCaretHandler( PED ped ) 01219 * 01220 * History: 01221 * 07/16/96 by takaok ported from NT 3.51 01222 * 01223 \***************************************************************************/ 01224 01225 void ECSetCaretHandler(PED ped) 01226 { 01227 HDC hdc; 01228 SIZE size; 01229 PSTR pText; 01230 01231 // if (!ped->fInsertCompChr || ped->fReadOnly) 01232 // return; 01233 01234 // In any case destroy caret beforehand otherwise SetCaretPos() 01235 // will get crazy.. win95d-B#992,B#2370 01236 // 01237 if (ped->fFocus) { 01238 01239 NtUserHideCaret(ped->hwnd); 01240 DestroyCaret(); 01241 if ( ped->fReplaceCompChr ) { 01242 01243 hdc = ECGetEditDC(ped, TRUE ); 01244 pText = ECLock(ped); 01245 01246 if ( ped->fAnsi) 01247 GetTextExtentPointA(hdc, pText + ped->ichCaret, 2, &size); 01248 else 01249 GetTextExtentPointW(hdc, (LPWSTR)pText + ped->ichCaret, 1, &size); 01250 01251 ECUnlock(ped); 01252 ECReleaseEditDC(ped, hdc, TRUE); 01253 01254 CreateCaret(ped->hwnd, (HBITMAP)NULL, size.cx, ped->lineHeight); 01255 } 01256 else { 01257 CreateCaret(ped->hwnd, 01258 (HBITMAP)NULL, 01259 (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2), 01260 ped->lineHeight); 01261 } 01262 01263 hdc = ECGetEditDC(ped, TRUE ); 01264 if ( ped->fSingle ) 01265 SLSetCaretPosition( ped, hdc ); 01266 else 01267 MLSetCaretPosition( ped, hdc ); 01268 ECReleaseEditDC(ped, hdc, TRUE); 01269 NtUserShowCaret(ped->hwnd); 01270 } 01271 } 01272 01273 01274 /***************************************************************************\ 01275 * 01276 * LONG ECImeCompoistion( PED ped, WPARAM wParam, LPARAM lParam ) 01277 * 01278 * WM_IME_COMPOSITION handler for Korean IME 01279 * 01280 * History: 01281 \***************************************************************************/ 01282 01283 extern void MLReplaceSel(PED, LPSTR); 01284 01285 #define GET_COMPOSITION_STRING (ped->fAnsi ? fpImmGetCompositionStringA : fpImmGetCompositionStringW) 01286 01287 BOOL FAR PASCAL ECResultStrHandler(PED ped) 01288 { 01289 HIMC himc; 01290 LPSTR lpStr; 01291 LONG dwLen; 01292 01293 ped->fInsertCompChr = FALSE; // clear the state 01294 ped->fNoMoveCaret = FALSE; 01295 01296 if ((himc = fpImmGetContext(ped->hwnd)) == 0) { 01297 return FALSE; 01298 } 01299 01300 dwLen = GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, NULL, 0); 01301 01302 if (dwLen == 0) { 01303 fpImmReleaseContext(ped->hwnd, himc); 01304 return FALSE; 01305 } 01306 01307 dwLen *= ped->cbChar; 01308 dwLen += ped->cbChar; 01309 01310 lpStr = (LPSTR)UserGlobalAlloc(GPTR, dwLen); 01311 if (lpStr == NULL) { 01312 fpImmReleaseContext(ped->hwnd, himc); 01313 return FALSE; 01314 } 01315 01316 GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, lpStr, dwLen); 01317 01318 if (ped->fSingle) { 01319 SLReplaceSel(ped, lpStr); 01320 } else { 01321 MLReplaceSel(ped, lpStr); 01322 } 01323 01324 UserGlobalFree((HGLOBAL)lpStr); 01325 01326 fpImmReleaseContext(ped->hwnd, himc); 01327 01328 ped->fReplaceCompChr = FALSE; 01329 ped->fNoMoveCaret = FALSE; 01330 ped->fResultProcess = FALSE; 01331 01332 ECSetCaretHandler(ped); 01333 01334 return TRUE; 01335 } 01336 01337 LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam) 01338 { 01339 INT ich; 01340 LRESULT lReturn = 1; 01341 HDC hdc; 01342 BOOL fSLTextUpdated = FALSE; 01343 ICH iResult; 01344 HIMC hImc; 01345 BYTE TextBuf[4]; 01346 01347 if (!ped->fInsertCompChr) { 01348 if (lParam & GCS_RESULTSTR) { 01349 ECInOutReconversionMode(ped, FALSE); 01350 01351 if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) { 01352 ResultAtOnce: 01353 ECResultStrHandler(ped); 01354 lParam &= ~GCS_RESULTSTR; 01355 } 01356 } 01357 return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi); 01358 } 01359 01360 // In case of Ansi edit control, the length of minimum composition string 01361 // is 2. Check here maximum byte of edit control. 01362 if( ped->fAnsi && ped->cchTextMax == 1 ) { 01363 HIMC hImc; 01364 01365 hImc = fpImmGetContext( ped->hwnd ); 01366 fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L); 01367 fpImmReleaseContext( ped->hwnd, hImc ); 01368 NtUserMessageBeep(MB_ICONEXCLAMATION); 01369 return lReturn; 01370 } 01371 01372 // Don't move this after CS_NOMOVECARET check. 01373 // In case if skip the message, fNoMoveCaret should not be set. 01374 if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) { 01375 01376 // Now we're in result processing. GCS_RESULTSTR ends up 01377 // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted, 01378 // the message(s) will come later than this CS_INSERTCHAR 01379 // message. This composition character should be handled 01380 // after the WM_CHAR message(s). 01381 // 01382 if(ped->fAnsi) 01383 PostMessageA(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam); 01384 else 01385 PostMessageW(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam); 01386 ped->fResultProcess = FALSE; 01387 return lReturn; 01388 } 01389 01390 // 01391 // If fReplaceCompChr is TRUE, we change the shape of caret. A block 01392 // caret is displayed on the composition character. From the user's 01393 // point of view, there is no difference if the caret is before the 01394 // composition character or after the composition character. When 01395 // the composition character is finalized, the insertion point should 01396 // be moved to after the character, any way. Therefore checking 01397 // CS_NOMOVECARET bit doesn't make sense in our current implementation. 01398 // [takaok] 01399 // 01400 #if 0 01401 if (lParam & CS_NOMOVECARET) 01402 ped->fNoMoveCaret=TRUE; // stick to current caret pos. 01403 else 01404 ped->fNoMoveCaret=FALSE; 01405 #endif 01406 01407 if (lParam & GCS_RESULTSTR) { 01408 01409 if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) { 01410 goto ResultAtOnce; 01411 } 01412 01413 ped->fResultProcess=TRUE; 01414 if ( ped->fReplaceCompChr ) { 01415 // 01416 // we have a DBCS character to be replaced. 01417 // let's delete it before inserting the new one. 01418 // 01419 ich = (ped->fAnsi) ? 2 : 1; 01420 ped->fReplaceCompChr = FALSE; 01421 ped->ichMaxSel = min(ped->ichCaret + ich, ped->cch); 01422 ped->ichMinSel = ped->ichCaret; 01423 if ( ECDeleteText( ped ) > 0 ) { 01424 if ( ped->fSingle ) { 01425 // 01426 // Update the display 01427 // 01428 ECNotifyParent(ped, EN_UPDATE); 01429 hdc = ECGetEditDC(ped,FALSE); 01430 SLDrawText(ped, hdc, 0); 01431 ECReleaseEditDC(ped,hdc,FALSE); 01432 // 01433 // Tell parent our text contents changed. 01434 // 01435 ECNotifyParent(ped, EN_CHANGE); 01436 } 01437 } 01438 ECSetCaretHandler( ped ); 01439 } 01440 01441 } else if(lParam & CS_INSERTCHAR) { 01442 01443 // 01444 // If we are in the middle of a mousedown command, don't do anything. 01445 // 01446 if (ped->fMouseDown) { 01447 return lReturn; 01448 } 01449 01450 // 01451 // We can safely assume that interimm character is always DBCS. 01452 // 01453 ich = ( ped->fAnsi ) ? 2 : 1; 01454 01455 if ( ped->fReplaceCompChr ) { 01456 // 01457 // we have a character to be replaced. 01458 // let's delete it before inserting the new one. 01459 // when we have a composition characters, the 01460 // caret is placed before the composition character. 01461 // 01462 ped->ichMaxSel = min(ped->ichCaret+ich, ped->cch); 01463 ped->ichMinSel = ped->ichCaret; 01464 } 01465 01466 // 01467 // let's delete current selected text or composition character 01468 // 01469 if ( ped->fSingle ) { 01470 if ( ECDeleteText( ped ) > 0 ) { 01471 fSLTextUpdated = TRUE; 01472 } 01473 } else { 01474 MLDeleteText( ped ); 01475 } 01476 01477 // 01478 // When the composition charcter is canceled, IME may give us NULL wParam, 01479 // with CS_INSERTCHAR flag on. We shouldn't insert a NULL character. 01480 // 01481 if ( wParam != 0 ) { 01482 01483 if ( ped->fAnsi ) { 01484 TextBuf[0] = HIBYTE(LOWORD(wParam)); // leading byte 01485 TextBuf[1] = LOBYTE(LOWORD(wParam)); // trailing byte 01486 TextBuf[2] = '\0'; 01487 } else { 01488 TextBuf[0] = LOBYTE(LOWORD(wParam)); 01489 TextBuf[1] = HIBYTE(LOWORD(wParam)); 01490 TextBuf[2] = '\0'; 01491 TextBuf[3] = '\0'; 01492 } 01493 01494 if ( ped->fSingle ) { 01495 01496 iResult = SLInsertText( ped, (LPSTR)TextBuf, ich ); 01497 if (iResult == 0) { 01498 /* 01499 * Couldn't insert the text, for e.g. the text exceeded the limit. 01500 */ 01501 NtUserMessageBeep(0); 01502 } else if (iResult > 0) { 01503 /* 01504 * Remember we need to update the text. 01505 */ 01506 fSLTextUpdated = TRUE; 01507 } 01508 01509 } else { 01510 01511 iResult = MLInsertText( ped, (LPSTR)TextBuf, ich, TRUE); 01512 } 01513 01514 if ( iResult > 0 ) { 01515 // 01516 // ped->fReplaceCompChr will be reset: 01517 // 01518 // 1) when the character is finalized. 01519 // we will receive GCS_RESULTSTR 01520 // 01521 // 2) when the character is canceled. 01522 // 01523 // we will receive WM_IME_COMPOSITION|CS_INSERTCHAR 01524 // with wParam == 0 (in case of user types backspace 01525 // at the first element of composition character). 01526 // 01527 // or 01528 // 01529 // we will receive WM_IME_ENDCOMPOSITION message 01530 // 01531 ped->fReplaceCompChr = TRUE; 01532 01533 // 01534 // Caret should be placed BEFORE the composition 01535 // character. 01536 // 01537 ped->ichCaret = max( 0, ped->ichCaret - ich); 01538 ECSetCaretHandler( ped ); 01539 } else { 01540 01541 // 01542 // We failed to insert a character. We might run out 01543 // of memory, or reached to the text size limit. let's 01544 // cancel the composition character. 01545 // 01546 hImc = fpImmGetContext(ped->hwnd); 01547 fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 01548 fpImmReleaseContext(ped->hwnd, hImc); 01549 01550 ped->fReplaceCompChr = FALSE; 01551 ECSetCaretHandler( ped ); 01552 } 01553 } else { 01554 // 01555 // the composition character is canceled. 01556 // 01557 ped->fReplaceCompChr = FALSE; 01558 ECSetCaretHandler( ped ); 01559 } 01560 01561 // 01562 // We won't notify parent the text change 01563 // because the composition character has 01564 // not been finalized. 01565 // 01566 if ( fSLTextUpdated ) { 01567 01568 // 01569 // Update the display 01570 // 01571 ECNotifyParent(ped, EN_UPDATE); 01572 01573 hdc = ECGetEditDC(ped,FALSE); 01574 01575 if ( ped->fReplaceCompChr ) { 01576 // 01577 // move back the caret to the original position 01578 // temporarily so that our new block cursor can 01579 // be located within the visible area of window. 01580 // 01581 ped->ichCaret = min( ped->cch, ped->ichCaret + ich); 01582 SLScrollText(ped, hdc); 01583 ped->ichCaret = max( 0, ped->ichCaret - ich); 01584 } else { 01585 SLScrollText(ped, hdc); 01586 } 01587 SLDrawText(ped, hdc, 0); 01588 01589 ECReleaseEditDC(ped,hdc,FALSE); 01590 01591 // 01592 // Tell parent our text contents changed. 01593 // 01594 ECNotifyParent(ped, EN_CHANGE); 01595 } 01596 return lReturn; 01597 } 01598 01599 return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi); 01600 } 01601 01602 01603 #ifdef LATER // fyi: window 98 equiv. 01604 LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam) 01605 { 01606 INT ich; 01607 LRESULT lReturn = 1; 01608 HDC hdc; 01609 BOOL fSLTextUpdated = FALSE; 01610 ICH iResult; 01611 HIMC hImc; 01612 BYTE TextBuf[4]; 01613 01614 // In case of Ansi edit control, the length of minimum composition string 01615 // is 2. Check here maximum byte of edit control. 01616 if( ped->fAnsi && ped->cchTextMax == 1 ) { 01617 HIMC hImc; 01618 01619 hImc = fpImmGetContext( ped->hwnd ); 01620 fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L); 01621 fpImmReleaseContext( ped->hwnd, hImc ); 01622 MessageBeep(MB_ICONEXCLAMATION); 01623 return lReturn; 01624 } 01625 01626 // Don't move this after CS_NOMOVECARET check. 01627 // In case if skip the message, fNoMoveCaret should not be set. 01628 if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) { 01629 01630 // Now we're in result processing. GCS_RESULTSTR ends up 01631 // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted, 01632 // the message(s) will come later than this CS_INSERTCHAR 01633 // message. This composition character should be handled 01634 // after the WM_CHAR message(s). 01635 // 01636 (ped->fAnsi ? PostMessageA : PostMessageW)(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam); 01637 ped->fResultProcess = FALSE; 01638 return lReturn; 01639 } 01640 01641 ped->fNoMoveCaret = (lParam & CS_NOMOVECARET) != 0; 01642 01643 if (lParam & GCS_RESULTSTR) { 01644 ECInOutReconversionMode(ped, FALSE); 01645 01646 if (ped->wImeStatus & EIMS_GETCOMPSTRATONCE) { 01647 ECGetCompStrAtOnce(ped); 01648 01649 goto PassToDefaultWindowProc; 01650 } 01651 01652 // Getting into result processing 01653 ped->fResultProcess = TRUE; 01654 } 01655 else if (lParam & CS_INSERTCHAR) { 01656 ped->fInsertCompChr = TRUE; // Process this composition character. 01657 01658 (ped->fSingleLine ? SLChar : MLChar)(ped, wParam, 0); 01659 01660 if (ped->fInsretCompChr) { 01661 ped->fReplaceCompChr = TRUE; // The next character will replace this. 01662 ped->fInsertCompChr = FALSE; // Clear the state for the next character. 01663 } 01664 01665 ECSetCaretHandler(ped); 01666 return 0; 01667 } 01668 01669 PassToDefaultWindowProc: 01670 return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi); 01671 } 01672 #endif 01673 01674 01675 /***************************************************************************\ 01676 * 01677 * BOOL HanjaKeyHandler( PED ped ) 01678 * 01679 * VK_HANJA handler - Korean only 01680 * 01681 * History: July 15,1996 takaok ported from NT 3.51 01682 \***************************************************************************/ 01683 BOOL HanjaKeyHandler( PED ped ) 01684 { 01685 BOOL changeSelection = FALSE; 01686 01687 if (ped->fKorea && !ped->fReadOnly) { 01688 ICH oldCaret = ped->ichCaret; 01689 01690 if (ped->fReplaceCompChr) 01691 return FALSE; 01692 01693 if (ped->ichMinSel < ped->ichMaxSel) 01694 ped->ichCaret = ped->ichMinSel; 01695 01696 if (!ped->cch || ped->cch == ped->ichCaret) { 01697 ped->ichCaret = oldCaret; 01698 NtUserMessageBeep(MB_ICONEXCLAMATION); 01699 return FALSE; 01700 } 01701 01702 if (ped->fAnsi) { 01703 if (fpImmEscapeA(THREAD_HKL(), fpImmGetContext(ped->hwnd), 01704 IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) { 01705 changeSelection = TRUE; 01706 } 01707 else 01708 ped->ichCaret = oldCaret; 01709 ECUnlock(ped); 01710 } 01711 else { 01712 if (fpImmEscapeW(THREAD_HKL(), fpImmGetContext(ped->hwnd), 01713 IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) { 01714 changeSelection = TRUE; 01715 } 01716 else 01717 ped->ichCaret = oldCaret; 01718 ECUnlock(ped); 01719 } 01720 } 01721 return changeSelection; 01722 } 01723 01724 01726 // EcImeRequestHandler() 01727 // 01728 // Handles WM_IME_REQUEST message originated by IME 01729 // 01730 // Histroy: 01731 // 27-Mar-97 Hiroyama Created 01733 01734 01735 LRESULT EcImeRequestHandler(PED ped, WPARAM dwSubMsg, LPARAM lParam) 01736 { 01737 LRESULT lreturn = 0L; 01738 01739 switch (dwSubMsg) { 01740 case IMR_CONFIRMRECONVERTSTRING: 01741 // Edit control does not allow IME to change it. 01742 break; 01743 01744 case IMR_RECONVERTSTRING: 01745 // 01746 // CHECK VERSION of the structure 01747 // 01748 if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0) { 01749 RIPMSG1(RIP_WARNING, "EcImeRequestHandler: RECONVERTSTRING dwVersion is not expected.", 01750 ((LPRECONVERTSTRING)lParam)->dwVersion); 01751 return 0L; 01752 } 01753 01754 if (ped && ped->fFocus && ped->hText && fpImmIsIME(THREAD_HKL())) { 01755 UINT cchLen = ped->ichMaxSel - ped->ichMinSel; // holds character count. 01756 if (cchLen == 0) { 01757 // if we have no selection, 01758 // just return 0. 01759 break; 01760 } 01761 01762 UserAssert(ped->cbChar == sizeof(BYTE) || ped->cbChar == sizeof(WCHAR)); 01763 01764 // This Edit Control has selection. 01765 if (lParam == 0) { 01766 // 01767 // IME just want to get required size for buffer. 01768 // cchLen + 1 is needed to reserve room for trailing L'\0'. 01769 // ~~~~ 01770 lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar; 01771 } else { 01772 LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam; 01773 LPVOID lpSrc; 01774 LPVOID lpDest = (LPBYTE)lpRCS + sizeof(RECONVERTSTRING); 01775 01776 // check buffer size 01777 // if the given buffer is smaller than actual needed size, 01778 // shrink our size to fit the buffer 01779 if ((INT)lpRCS->dwSize <= sizeof(RECONVERTSTRING) + cchLen * ped->cbChar) { 01780 RIPMSG0(RIP_WARNING, "EcImeRequest: ERR09"); 01781 cchLen = (lpRCS->dwSize - sizeof(RECONVERTSTRING)) / ped->cbChar - ped->cbChar; 01782 } 01783 01784 lpRCS->dwStrOffset = sizeof(RECONVERTSTRING); // buffer begins just after RECONVERTSTRING 01785 lpRCS->dwCompStrOffset = 01786 lpRCS->dwTargetStrOffset = 0; 01787 lpRCS->dwStrLen = 01788 lpRCS->dwCompStrLen = 01789 lpRCS->dwTargetStrLen = cchLen; // StrLen means TCHAR count 01790 01791 lpSrc = ECLock(ped); 01792 if (lpSrc == NULL) { 01793 RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed."); 01794 } else { 01795 RtlCopyMemory(lpDest, 01796 (LPBYTE)lpSrc + ped->ichMinSel * ped->cbChar, 01797 cchLen * ped->cbChar); 01798 // Null-Terminate the string 01799 if (ped->fAnsi) { 01800 LPBYTE psz = (LPBYTE)lpDest; 01801 psz[cchLen] = '\0'; 01802 } else { 01803 LPWSTR pwsz = (LPWSTR)lpDest; 01804 pwsz[cchLen] = L'\0'; 01805 } 01806 ECUnlock(ped); 01807 // final buffer size 01808 lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar; 01809 01810 ECInOutReconversionMode(ped, TRUE); 01811 ECImmSetCompositionWindow(ped, 0, 0); 01812 } 01813 } 01814 01815 } 01816 break; 01817 } 01818 01819 return lreturn; 01820 }

Generated on Sat May 15 19:39:48 2004 for test by doxygen 1.3.7