Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1968 lines
62 KiB

/****************************************************************************\
* edECRare.c - EC Edit controls Routines Called rarely are to be
* put in a seperate segment _EDECRare. This file contains
* these routines.
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Support Routines common to Single-line and Multi-Line edit controls
* called Rarely.
*
* Created: 02-08-89 sankar
\****************************************************************************/
#include "precomp.h"
#pragma hdrstop
extern LOOKASIDE EditLookaside;
#define WS_EX_EDGEMASK (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)
/*
* Those two macros assume PED can be referred as "ped."
*/
#define GetCharABCWidthsAorW ((ped)->fAnsi ? GetCharABCWidthsA : GetCharABCWidthsW)
#define GetCharWidthAorW ((ped)->fAnsi ? GetCharWidthA : GetCharWidthW)
#define umin(a, b) ((unsigned)(a) < (unsigned)(b) ? (unsigned)(a) : (unsigned)(b))
typedef BOOL (*PFNABCWIDTHS)(HDC, UINT, UINT, LPABC);
typedef BOOL (*PFNCHARWIDTH)(HDC, UINT, UINT, LPINT);
/***************************************************************************\
*
* GetMaxOverlapChars - Gives maximum number of overlapping characters due to
* negative A or C widths.
*
\***************************************************************************/
DWORD GetMaxOverlapChars( void )
{
return (DWORD) MAKELONG( gpsi->wMaxLeftOverlapChars, gpsi->wMaxRightOverlapChars ) ;
}
/***************************************************************************\
*
* ECSetMargin()
*
\***************************************************************************/
void ECSetMargin(PED ped, UINT wFlags, long lMarginValues, BOOL fRedraw)
{
BOOL fUseFontInfo = FALSE;
UINT wValue, wOldLeftMargin, wOldRightMargin;
if (wFlags & EC_LEFTMARGIN) /* Set the left margin */ {
if ((int) (wValue = (int)(short)LOWORD(lMarginValues)) < 0) {
fUseFontInfo = TRUE;
wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegA);
}
ped->rcFmt.left += wValue - ped->wLeftMargin;
wOldLeftMargin = ped->wLeftMargin;
ped->wLeftMargin = wValue;
}
if (wFlags & EC_RIGHTMARGIN) /* Set the Right margin */ {
if ((int) (wValue = (int)(short)HIWORD(lMarginValues)) < 0) {
fUseFontInfo = TRUE;
wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegC);
}
ped->rcFmt.right -= wValue - ped->wRightMargin;
wOldRightMargin = ped->wRightMargin;
ped->wRightMargin = wValue;
}
if (fUseFontInfo) {
if (ped->rcFmt.right - ped->rcFmt.left < 2 * ped->aveCharWidth) {
RIPMSG0(RIP_WARNING, "ECSetMargin: rcFmt is too narrow for EC_USEFONTINFO");
if (wFlags & EC_LEFTMARGIN) /* Reset the left margin */ {
ped->rcFmt.left += wOldLeftMargin - ped->wLeftMargin;
ped->wLeftMargin = wOldLeftMargin;
}
if (wFlags & EC_RIGHTMARGIN) /* Reset the Right margin */ {
ped->rcFmt.right -= wOldRightMargin - ped->wRightMargin;
ped->wRightMargin = wOldRightMargin;
}
return;
}
}
// NtUserInvalidateRect(ped->hwnd, NULL, TRUE);
if (fRedraw) {
ECInvalidateClient(ped, TRUE);
}
}
// --------------------------------------------------------------------------
//
// ECCalcMarginfForDBCSFont()
//
// Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (edecrare.c)
// --------------------------------------------------------------------------
void ECCalcMarginForDBCSFont(PED ped, BOOL fRedraw)
{
if (!ped->fTrueType)
return;
if (!ped->fSingle) {
// wMaxNegA came from ABC CharWidth.
if (ped->wMaxNegA != 0) {
ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO),fRedraw);
}
} else {
int iMaxNegA = 0, iMaxNegC = 0;
int i;
PVOID lpBuffer;
LPABC lpABCBuff;
ABC ABCInfo;
HFONT hOldFont;
HDC hdc = NtUserGetDC(ped->hwnd);
if (!ped->hFont || !(hOldFont = SelectFont(hdc, ped->hFont))) {
ReleaseDC(ped->hwnd, hdc);
return;
}
if (lpBuffer = UserLocalAlloc(0,sizeof(ABC) * 256)) {
lpABCBuff = lpBuffer;
GetCharABCWidthsAorW(hdc, 0, 255, lpABCBuff);
} else {
lpABCBuff = &ABCInfo;
GetCharABCWidthsAorW(hdc, 0, 0, lpABCBuff);
}
i = 0;
while (TRUE) {
iMaxNegA = min(iMaxNegA, lpABCBuff->abcA);
iMaxNegC = min(iMaxNegC, lpABCBuff->abcC);
if (++i == 256)
break;
if (lpBuffer) {
lpABCBuff++;
} else {
GetCharABCWidthsAorW(hdc, i, i, lpABCBuff);
}
}
SelectFont(hdc, hOldFont);
if (lpBuffer) UserLocalFree(lpBuffer);
ReleaseDC(ped->hwnd, hdc);
if ((iMaxNegA != 0) || (iMaxNegC != 0))
ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
MAKELONG((UINT)(-iMaxNegC), (UINT)(-iMaxNegA)),fRedraw);
}
return;
}
// --------------------------------------------------------------------------
//
// GetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
//
// Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (wmclient.c)
// --------------------------------------------------------------------------
CONST WCHAR AveCharWidthData[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
//
// if an app set a font for vertical writing, even though we don't
// handle it with EC, the escapement of tm can be NON 0. Then cxWidth from
// GetCharDimenstions() could be 0 in GetCharDimensions().
// This will break our caller who don't expect 0 at return. So I created
// this entry for the case the caller set vertical font.
//
//
int UserGetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
{
int cxWidth;
TEXTMETRIC tm;
LOGFONTW lf;
WCHAR wchFaceName[LF_FACESIZE];
//
// Is this font vertical font ??
//
wchFaceName[0] = 0;
GetTextFaceW(hDC, LF_FACESIZE, wchFaceName);
if (wchFaceName[0] != L'@') {
//
// if not call GDI...
//
return(GdiGetCharDimensions(hDC, lptm, lpcy));
}
if (!lptm)
lptm = &tm;
GetTextMetrics(hDC, lptm);
// TMPF_FIXED_PITCH
//
// If this bit is set the font is a variable pitch font.
// If this bit is clear the font is a fixed pitch font.
// Note very carefully that those meanings are the opposite of what the constant name implies.
//
if (!(lptm->tmPitchAndFamily & TMPF_FIXED_PITCH)) { // If !variable_width font
// This is fixed pitch font....
cxWidth = lptm->tmAveCharWidth;
} else {
// This is variable pitch font...
if (hfont && GetObjectW(hfont, sizeof(LOGFONTW), &lf) && (lf.lfEscapement != 0)) {
cxWidth = lptm->tmAveCharWidth;
} else {
SIZE size;
GetTextExtentPointW(hDC, AveCharWidthData, 52, &size);
cxWidth = ((size.cx / 26) + 1) / 2;
}
}
if (lpcy)
*lpcy = lptm->tmHeight;
return(cxWidth);
}
/***************************************************************************\
* ECGetText AorW
*
* Copies at most maxCchToCopy chars to the buffer lpBuffer. Returns
* how many chars were actually copied. Null terminates the string based
* on the fNullTerminate flag:
* fNullTerminate --> at most (maxCchToCopy - 1) characters will be copied
* !fNullTerminate --> at most (maxCchToCopy) characters will be copied
*
* History:
\***************************************************************************/
ICH ECGetText(
PED ped,
ICH maxCchToCopy,
LPSTR lpBuffer,
BOOL fNullTerminate)
{
PSTR pText;
if (maxCchToCopy) {
/*
* Zero terminator takes the extra byte
*/
if (fNullTerminate)
maxCchToCopy--;
maxCchToCopy = min(maxCchToCopy, ped->cch);
/*
* Zero terminate the string
*/
if (ped->fAnsi)
*(LPSTR)(lpBuffer + maxCchToCopy) = 0;
else
*(((LPWSTR)lpBuffer) + maxCchToCopy) = 0;
pText = ECLock(ped);
RtlCopyMemory(lpBuffer, pText, maxCchToCopy*ped->cbChar);
ECUnlock(ped);
}
return maxCchToCopy;
}
/***************************************************************************\
* ECNcCreate AorW
*
* History:
\***************************************************************************/
BOOL ECNcCreate(
PED ped,
PWND pwnd,
LPCREATESTRUCT lpCreateStruct)
{
HWND hwnd = HWq(pwnd);
BOOL fAnsi;
fAnsi = TestWF(pwnd, WFANSICREATOR);
/*
* Initialize the ped
*/
ped->fEncoded = FALSE;
ped->iLockLevel = 0;
ped->chLines = NULL;
ped->pTabStops = NULL;
ped->charWidthBuffer = NULL;
ped->fAnsi = fAnsi ? 1 : 0; // Force TRUE to be 1 because its a 1 bit field
ped->cbChar = (WORD)(fAnsi ? sizeof(CHAR) : sizeof(WCHAR));
ped->hInstance = KHANDLE_TO_HANDLE(pwnd->hModule);
// IME
ped->hImcPrev = NULL_HIMC;
{
DWORD dwVer = GETEXPWINVER(lpCreateStruct->hInstance);
ped->fWin31Compat = (dwVer >= 0x030a);
ped->f40Compat = (dwVer >= 0x0400);
}
//
// NOTE:
// The order of the following two checks is important. People can
// create edit fields with a 3D and a normal border, and we don't
// want to disallow that. But we need to detect the "no 3D border"
// border case too.
//
if (TestWF(pwnd, WEFEDGEMASK))
{
ped->fBorder = TRUE;
}
else if (TestWF(pwnd, WFBORDER))
{
ClearWindowState(pwnd, WFBORDER);
ped->fFlatBorder = TRUE;
ped->fBorder = TRUE;
}
if (!TestWF(pwnd, EFMULTILINE))
ped->fSingle = TRUE;
if (TestWF(pwnd, WFDISABLED))
ped->fDisabled = TRUE;
if (TestWF(pwnd, EFREADONLY)) {
if (!ped->fWin31Compat) {
/*
* BACKWARD COMPATIBILITY HACK
*
* "MileStone" unknowingly sets the ES_READONLY style. So, we strip this
* style here for all Win3.0 apps (this style is new for Win3.1).
* Fix for Bug #12982 -- SANKAR -- 01/24/92 --
*/
ClearWindowState(pwnd, EFREADONLY);
} else
ped->fReadOnly = TRUE;
}
/*
* Allocate storage for the text for the edit controls. Storage for single
* line edit controls will always get allocated in the local data segment.
* Multiline will allocate in the local ds but the app may free this and
* allocate storage elsewhere...
*/
ped->hText = LOCALALLOC(LHND, CCHALLOCEXTRA*ped->cbChar, ped->hInstance);
if (!ped->hText) {
FreeLookasideEntry(&EditLookaside, ped);
NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT); /* No ped for this window */
return FALSE;
}
ped->cchAlloc = CCHALLOCEXTRA;
ped->lineHeight = 1;
ped->hwnd = hwnd;
ped->hwndParent = lpCreateStruct->hwndParent;
ped->wImeStatus = 0;
return (BOOL)DefWindowProcWorker(pwnd,
WM_NCCREATE,
0,
(LPARAM)lpCreateStruct,
fAnsi);
}
/***************************************************************************\
* ECCreate AorW
*
* History:
\***************************************************************************/
BOOL ECCreate(
PED ped,
LONG windowStyle)
{
HDC hdc;
/*
* Get values from the window instance data structure and put them in the
* ped so that we can access them easier.
*/
if (windowStyle & ES_AUTOHSCROLL)
ped->fAutoHScroll = 1;
if (windowStyle & ES_NOHIDESEL)
ped->fNoHideSel = 1;
ped->format = (LOWORD(windowStyle) & LOWORD(ES_FMTMASK));
if (TestWF(ped->pwnd, WEFRIGHT) && !ped->format)
ped->format = ES_RIGHT;
ped->cchTextMax = MAXTEXT; /* Max # chars we will initially allow */
/*
* Set up undo initial conditions... (ie. nothing to undo)
*/
ped->ichDeleted = (ICH)-1;
ped->ichInsStart = (ICH)-1;
ped->ichInsEnd = (ICH)-1;
// initial charset value - need to do this BEFORE MLCreate is called
// so that we know not to fool with scrollbars if nessacary
hdc = ECGetEditDC(ped, TRUE);
ped->charSet = (BYTE)GetTextCharset(hdc);
ECReleaseEditDC(ped, hdc, TRUE);
// FE_IME
// EC_INSERT_COMPOSITION_CHARACTER: ECCreate() - call ECInitInsert()
ECInitInsert(ped, THREAD_HKL());
if(ped->pLpkEditCallout = fpLpkEditControl) {
return ped->pLpkEditCallout->EditCreate(ped, HW(ped->pwnd));
} else
return TRUE;
}
/***************************************************************************\
* ECNcDestroyHandler AorW
*
* Destroys the edit control ped by freeing up all memory used by it.
*
* History:
\***************************************************************************/
VOID ECNcDestroyHandler(
PWND pwnd,
PED ped)
{
PWND pwndParent;
/*
* Ped could be NULL if WM_NCCREATE failed to create it.
*/
if (ped) {
/*
* Free the text buffer.
*/
LOCALFREE(ped->hText, ped->hInstance);
/*
* Free up undo buffer and line start array (if present).
*/
if (ped->hDeletedText != NULL) {
UserGlobalFree(ped->hDeletedText);
}
/*
* Free tab stop buffer (if present)
*/
if (ped->pTabStops) {
UserLocalFree(ped->pTabStops);
}
/*
* Free line start array (if present)
*/
if (ped->chLines) {
UserLocalFree(ped->chLines);
}
/*
* Free the character width buffer (if present).
*/
if (ped->charWidthBuffer) {
UserLocalFree(ped->charWidthBuffer);
}
/*
* Free the cursor bitmap.
*/
if (ped->pLpkEditCallout && ped->hCaretBitmap) {
DeleteObject(ped->hCaretBitmap);
}
/*
* Last but not least, free the ped.
*/
FreeLookasideEntry(&EditLookaside, ped);
}
/*
* Set the window's fnid status so that we can ignore rogue messages.
*/
NtUserSetWindowFNID(HWq(pwnd), FNID_CLEANEDUP_BIT);
/*
* If we're part of a combo box, let it know we're gone.
*/
pwndParent = REBASEPWND(pwnd, spwndParent);
if (pwndParent && GETFNID(pwndParent) == FNID_COMBOBOX) {
ComboBoxWndProcWorker(pwndParent,
WM_PARENTNOTIFY,
MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)),
(LPARAM)HWq(pwnd),
FALSE);
}
}
/***************************************************************************\
* ECSetPasswordChar AorW
*
* Sets the password char to display.
*
* History:
\***************************************************************************/
void ECSetPasswordChar(
PED ped,
UINT pwchar)
{
HDC hdc;
SIZE size;
ped->charPasswordChar = pwchar;
if (pwchar) {
hdc = ECGetEditDC(ped, TRUE);
if (ped->fAnsi)
GetTextExtentPointA(hdc, (LPSTR)&pwchar, 1, &size);
else
GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
ped->cPasswordCharWidth = max(size.cx, 1);
ECReleaseEditDC(ped, hdc, TRUE);
}
if (pwchar)
SetWindowState(ped->pwnd, EFPASSWORD);
else
ClearWindowState(ped->pwnd, EFPASSWORD);
ECEnableDisableIME(ped);
}
/***************************************************************************\
* GetNegABCwidthInfo()
* This function fills up the ped->charWidthBuffer buffer with the
* negative A,B and C widths for all the characters below 0x7f in the
* currently selected font.
* Returns:
* TRUE, if the function succeeded.
* FALSE, if GDI calls to get the char widths have failed.
*
* Note: not used if LPK installed
\***************************************************************************/
BOOL GetNegABCwidthInfo(
PED ped,
HDC hdc)
{
LPABC lpABCbuff;
int i;
int CharWidthBuff[CHAR_WIDTH_BUFFER_LENGTH]; // Local char width buffer.
int iOverhang;
if (!GetCharABCWidthsA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPABC)ped->charWidthBuffer)) {
RIPMSG0(RIP_WARNING, "GetNegABCwidthInfo: GetCharABCWidthsA Failed");
return FALSE;
}
// The (A+B+C) returned for some fonts (eg: Lucida Caligraphy) does not
// equal the actual advanced width returned by GetCharWidths() minus overhang.
// This is due to font bugs. So, we adjust the 'B' width so that this
// discrepancy is removed.
// Fix for Bug #2932 --sankar-- 02/17/93
iOverhang = ped->charOverhang;
GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPINT)CharWidthBuff);
lpABCbuff = (LPABC)ped->charWidthBuffer;
for(i = 0; i < CHAR_WIDTH_BUFFER_LENGTH; i++) {
lpABCbuff->abcB = CharWidthBuff[i] - iOverhang
- lpABCbuff->abcA
- lpABCbuff->abcC;
lpABCbuff++;
}
return(TRUE);
}
/***************************************************************************\
*
* ECSize() -
*
* Handle sizing for an edit control's client rectangle.
* Use lprc as the bounding rectangle if specified; otherwise use the current
* client rectangle.
*
\***************************************************************************/
void ECSize(
PED ped,
LPRECT lprc,
BOOL fRedraw)
{
RECT rc;
/*
* BiDi VB32 Creates an Edit Control and immediately sends a WM_SIZE
* message which causes EXSize to be called before ECSetFont, which
* in turn causes a divide by zero exception below. This check for
* ped->lineHeight will pick it up safely. [samera] 3/5/97
*/
if(ped->lineHeight == 0)
return;
// assume that we won't be able to display the caret
ped->fCaretHidden = TRUE;
if ( lprc )
CopyRect(&rc, lprc);
else
_GetClientRect(ped->pwnd, &rc);
if (!(rc.right - rc.left) || !(rc.bottom - rc.top)) {
if (ped->rcFmt.right - ped->rcFmt.left)
return;
rc.left = 0;
rc.top = 0;
rc.right = ped->aveCharWidth * 10;
rc.bottom = ped->lineHeight;
}
if (!lprc) {
// subtract the margins from the given rectangle --
// make sure that this rectangle is big enough to have these margins.
if ((rc.right - rc.left) > (int)(ped->wLeftMargin + ped->wRightMargin)) {
rc.left += ped->wLeftMargin;
rc.right -= ped->wRightMargin;
}
}
//
// Leave space so text doesn't touch borders.
// For 3.1 compatibility, don't subtract out vertical borders unless
// there is room.
//
if (ped->fBorder) {
int cxBorder = SYSMET(CXBORDER);
int cyBorder = SYSMET(CYBORDER);
if (ped->fFlatBorder)
{
cxBorder *= 2;
cyBorder *= 2;
}
if (rc.bottom < rc.top + ped->lineHeight + 2*cyBorder)
cyBorder = 0;
InflateRect(&rc, -cxBorder, -cyBorder);
}
// Is the resulting rectangle too small? Don't change it then.
if ((!ped->fSingle) && ((rc.right - rc.left < (int) ped->aveCharWidth) ||
((rc.bottom - rc.top) / ped->lineHeight == 0)))
return;
// now, we know we're safe to display the caret
ped->fCaretHidden = FALSE;
CopyRect(&ped->rcFmt, &rc);
if (ped->fSingle)
ped->rcFmt.bottom = min(rc.bottom, rc.top + ped->lineHeight);
else
MLSize(ped, fRedraw);
if (fRedraw) {
NtUserInvalidateRect(ped->hwnd, NULL, TRUE);
// UpdateWindow31(ped->hwnd); Evaluates to NOP in Chicago - Johnl
}
// FE_IME
// ECSize() - call ECImmSetCompositionWindow()
//
// normally this isn't needed because WM_SIZE will cause
// WM_PAINT and the paint handler will take care of IME
// composition window. However when the edit window is
// restored from maximized window and client area is out
// of screen, the window will not be redrawn.
//
if (ped->fFocus && fpImmIsIME(THREAD_HKL())) {
POINT pt;
NtUserGetCaretPos(&pt);
ECImmSetCompositionWindow(ped, pt.x, pt.y);
}
}
/***************************************************************************\
*
* ECSetFont AorW () -
*
* Sets the font used in the edit control. Warning: Memory compaction may
* occur if the font wasn't previously loaded. If the font handle passed
* in is NULL, assume the system font.
*
\***************************************************************************/
void ECSetFont(
PED ped,
HFONT hfont,
BOOL fRedraw)
{
short i;
TEXTMETRIC TextMetrics;
HDC hdc;
HFONT hOldFont=NULL;
UINT wBuffSize;
LPINT lpCharWidthBuff;
DWORD dwMaxOverlapChars;
CHWIDTHINFO cwi;
UINT uExtracharPos;
hdc = NtUserGetDC(ped->hwnd);
if (ped->hFont = hfont) {
//
// Since the default font is the system font, no need to select it in
// if that's what the user wants.
//
if (!(hOldFont = SelectObject(hdc, hfont))) {
hfont = ped->hFont = NULL;
}
//
// Get the metrics and ave char width for the currently selected font
//
//
// Call Vertical font-aware AveWidth compute function...
//
// FE_SB
ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight);
/*
* This might fail when people uses network fonts (or bad fonts).
*/
if (ped->aveCharWidth == 0) {
RIPMSG0(RIP_WARNING, "ECSetFont: GdiGetCharDimensions failed");
if (hOldFont != NULL) {
SelectObject(hdc, hOldFont);
}
/*
* We've messed up the ped so let's reset the font.
* Note that we won't recurse more than once because we'll
* pass hfont == NULL.
* Too bad WM_SETFONT doesn't return a value.
*/
ECSetFont(ped, NULL, fRedraw);
return;
}
} else {
ped->aveCharWidth = gpsi->cxSysFontChar;
ped->lineHeight = gpsi->cySysFontChar;
TextMetrics = gpsi->tmSysFont;
}
ped->charOverhang = TextMetrics.tmOverhang;
//assume that they don't have any negative widths at all.
ped->wMaxNegA = ped->wMaxNegC = ped->wMaxNegAcharPos = ped->wMaxNegCcharPos = 0;
// Check if Proportional Width Font
//
// NOTE: as SDK doc says about TEXTMETRIC:
// TMPF_FIXED_PITCH
// If this bit is set the font is a variable pitch font. If this bit is clear
// the font is a fixed pitch font. Note very carefully that those meanings are
// the opposite of what the constant name implies.
//
// Thus we have to reverse the value using logical not (fNonPropFont has 1 bit width)
//
ped->fNonPropFont = !(TextMetrics.tmPitchAndFamily & FIXED_PITCH);
// Check for a TrueType font
// Older app OZWIN chokes if we allocate a bigger buffer for TrueType fonts
// So, for apps older than 4.0, no special treatment for TrueType fonts.
if (ped->f40Compat && (TextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
ped->fTrueType = GetCharWidthInfo(hdc, &cwi);
#if DBG
if (!ped->fTrueType) {
RIPMSG0(RIP_WARNING, "ECSetFont: GetCharWidthInfo Failed");
}
#endif
} else {
ped->fTrueType = FALSE;
}
// FE_SB
//
// In DBCS Windows, Edit Control must handle Double Byte Character
// if tmCharSet field of textmetrics is double byte character set
// such as SHIFTJIS_CHARSET(128:Japan), HANGEUL_CHARSET(129:Korea).
//
// We call ECGetDBCSVector even when fAnsi is false so that we could
// treat ped->fAnsi and ped->fDBCS indivisually. I changed ECGetDBCSVector
// function so that it returns 0 or 1, because I would like to set ped->fDBCS
// bit field here.
//
ped->fDBCS = ECGetDBCSVector(ped,hdc,TextMetrics.tmCharSet);
ped->charSet = TextMetrics.tmCharSet;
if (ped->fDBCS) {
//
// Free the character width buffer if ped->fDBCS.
//
// I expect single GetTextExtentPoint call is faster than multiple
// GetTextExtentPoint call (because the graphic engine has a cache buffer).
// See editec.c/ECTabTheTextOut().
//
if (ped->charWidthBuffer) {
UserLocalFree(ped->charWidthBuffer);
ped->charWidthBuffer = NULL;
}
//
// if FullWidthChar : HalfWidthChar == 2 : 1....
//
// TextMetrics.tmMaxCharWidth = FullWidthChar width
// ped->aveCharWidth = HalfWidthChar width
//
if (ped->fNonPropFont &&
((ped->aveCharWidth * 2) == TextMetrics.tmMaxCharWidth)) {
ped->fNonPropDBCS = TRUE;
} else {
ped->fNonPropDBCS = FALSE;
}
} else {
//
// Since the font has changed, let us obtain and save the character width
// info for this font.
//
// First left us find out if the maximum chars that can overlap due to
// negative widths. Since we can't access USER globals, we make a call here.
//
if (!(ped->fSingle || ped->pLpkEditCallout)) { // Is this a multiline edit control with no LPK present?
//
// For multiline edit controls, we maintain a buffer that contains
// the character width information.
//
wBuffSize = (ped->fTrueType) ? (CHAR_WIDTH_BUFFER_LENGTH * sizeof(ABC)) :
(CHAR_WIDTH_BUFFER_LENGTH * sizeof(int));
if (ped->charWidthBuffer) { /* If buffer already present */
lpCharWidthBuff = ped->charWidthBuffer;
ped->charWidthBuffer = UserLocalReAlloc(lpCharWidthBuff, wBuffSize, HEAP_ZERO_MEMORY);
if (ped->charWidthBuffer == NULL) {
UserLocalFree((HANDLE)lpCharWidthBuff);
}
} else {
ped->charWidthBuffer = UserLocalAlloc(HEAP_ZERO_MEMORY, wBuffSize);
}
if (ped->charWidthBuffer != NULL) {
if (ped->fTrueType) {
ped->fTrueType = GetNegABCwidthInfo(ped, hdc);
}
/*
* It is possible that the above attempts could have failed and reset
* the value of fTrueType. So, let us check that value again.
*/
if (!ped->fTrueType) {
if (!GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, ped->charWidthBuffer)) {
UserLocalFree((HANDLE)ped->charWidthBuffer);
ped->charWidthBuffer=NULL;
} else {
/*
* We need to subtract out the overhang associated with
* each character since GetCharWidth includes it...
*/
for (i=0;i < CHAR_WIDTH_BUFFER_LENGTH;i++)
ped->charWidthBuffer[i] -= ped->charOverhang;
}
}
} /* if (ped->charWidthBuffer != NULL) */
} /* if (!ped->fSingle) */
} /* if (ped->fDBCS) */
{
/*
* Calculate MaxNeg A C metrics
*/
dwMaxOverlapChars = GetMaxOverlapChars();
if (ped->fTrueType) {
if (cwi.lMaxNegA < 0)
ped->wMaxNegA = -cwi.lMaxNegA;
else
ped->wMaxNegA = 0;
if (cwi.lMaxNegC < 0)
ped->wMaxNegC = -cwi.lMaxNegC;
else
ped->wMaxNegC = 0;
if (cwi.lMinWidthD != 0) {
ped->wMaxNegAcharPos = (ped->wMaxNegA + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
ped->wMaxNegCcharPos = (ped->wMaxNegC + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
if (ped->wMaxNegA + ped->wMaxNegC > (UINT)cwi.lMinWidthD) {
uExtracharPos = (ped->wMaxNegA + ped->wMaxNegC - 1) / cwi.lMinWidthD;
ped->wMaxNegAcharPos += uExtracharPos;
ped->wMaxNegCcharPos += uExtracharPos;
}
} else {
ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
}
} else if (ped->charOverhang != 0) {
/*
* Some bitmaps fonts (i.e., italic) have under/overhangs;
* this is pretty much like having negative A and C widths.
*/
ped->wMaxNegA = ped->wMaxNegC = ped->charOverhang;
ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
}
} /* if (ped->fDBCS) */
if (!hfont) {
//
// We are getting the stats for the system font so update the system
// font fields in the ed structure since we use these when calculating
// some spacing.
//
ped->cxSysCharWidth = ped->aveCharWidth;
ped->cySysCharHeight= ped->lineHeight;
} else if (hOldFont)
SelectObject(hdc, hOldFont);
if (ped->fFocus) {
//
// Update the caret.
//
NtUserHideCaret(ped->hwnd);
NtUserDestroyCaret();
if (ped->pLpkEditCallout) {
ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(), ped->lineHeight, 0);
} else {
NtUserCreateCaret(ped->hwnd, (HBITMAP)NULL, ECGetCaretWidth(), ped->lineHeight);
}
NtUserShowCaret(ped->hwnd);
}
ReleaseDC(ped->hwnd, hdc);
//
// Update password character.
//
if (ped->charPasswordChar)
ECSetPasswordChar(ped, ped->charPasswordChar);
//
// If it is a TrueType font and it's a new app, set both the margins at the
// max negative width values for all types of the edit controls.
// (NOTE: Can't use ped->f40Compat here because edit-controls inside dialog
// boxes without DS_LOCALEDIT style are always marked as 4.0 compat.
// This is the fix for NETBENCH 3.0)
//
if (ped->fTrueType && (GETAPPVER() >= VER40))
if (ped->fDBCS) {
// For DBCS TrueType Font, we calc margin from ABC width.
ECCalcMarginForDBCSFont(ped, fRedraw);
} else {
ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO), fRedraw);
}
//
// We need to calc maxPixelWidth when font changes.
// If the word-wrap is ON, then this is done in MLSize() called later.
//
if((!ped->fSingle) && (!ped->fWrap))
MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL);
//
// Recalc the layout.
//
ECSize(ped, NULL, fRedraw);
if ( ped->fFocus && fpImmIsIME(THREAD_HKL()) ) {
ECImmSetCompositionFont( ped );
}
}
/***************************************************************************\
*
* ECIsCharNumeric AorW () -
*
* Tests whether the character entered is a numeral.
* For multiline and singleline edit controls with the ES_NUMBER style.
*
\***************************************************************************/
BOOL ECIsCharNumeric(
PED ped,
DWORD keyPress)
{
WORD wCharType;
if (ped->fAnsi) {
char ch = (char)keyPress;
LCID lcid = (LCID)((ULONG_PTR)THREAD_HKL() & 0xFFFF);
GetStringTypeA(lcid, CT_CTYPE1, &ch, 1, &wCharType);
} else {
WCHAR wch = (WCHAR)keyPress;
GetStringTypeW(CT_CTYPE1, &wch, 1, &wCharType);
}
return (wCharType & C1_DIGIT ? TRUE : FALSE);
}
/***************************************************************************\
*
* ECEnableDisableIME( PED ped )
*
*
* xx/xx/9x by somebody Created for Win95
* xx/xx/95 by kazum Ported to NT-J 3.51
* 04/15/96 by takaok Ported to NT 4.0
*
\***************************************************************************/
VOID ECEnableDisableIME( PED ped )
{
if ( ped->fReadOnly || ped->charPasswordChar ) {
//
// IME should be disabled
//
HIMC hImc;
hImc = fpImmGetContext( ped->hwnd );
if ( hImc != NULL_HIMC ) {
fpImmReleaseContext( ped->hwnd, hImc );
ped->hImcPrev = fpImmAssociateContext( ped->hwnd, NULL_HIMC );
}
} else {
//
// IME should be enabled
//
if ( ped->hImcPrev != NULL_HIMC ) {
ped->hImcPrev = fpImmAssociateContext( ped->hwnd, ped->hImcPrev );
//
// Font and the caret position might be changed while
// IME was being disabled. Set those now if the window
// has the focus.
//
if ( ped->fFocus ) {
POINT pt;
ECImmSetCompositionFont( ped );
NtUserGetCaretPos( &pt );
ECImmSetCompositionWindow( ped, pt.x, pt.y );
}
}
}
ECInitInsert(ped, THREAD_HKL());
}
/***************************************************************************\
*
* ECImmSetCompositionWindow( PED ped, LONG x, LONG y )
*
* xx/xx/9x by somebody Created for Win95
* xx/xx/95 by kazum Ported to NT-J 3.51
* 04/15/96 by takaok Ported to NT 4.0
\***************************************************************************/
VOID ECImmSetCompositionWindow( PED ped, LONG x, LONG y )
{
COMPOSITIONFORM cf;
COMPOSITIONFORM cft;
RECT rcScreenWindow;
HIMC hImc;
hImc = fpImmGetContext( ped->hwnd );
if ( hImc != NULL_HIMC ) {
if ( ped->fFocus ) {
GetWindowRect( ped->hwnd, &rcScreenWindow);
// assuming RECT.left is the first and and RECT.top is the second field
MapWindowPoints( ped->hwnd, HWND_DESKTOP, (LPPOINT)&rcScreenWindow, 2);
if (ped->fInReconversion) {
DWORD dwPoint = (DWORD)(ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_POSFROMCHAR, ped->ichMinSel, 0);
x = GET_X_LPARAM(dwPoint);
y = GET_Y_LPARAM(dwPoint);
RIPMSG2(RIP_WARNING, "ECImmSetCompositionWindow: fInReconversion (%d,%d)", x, y);
}
//
// The window currently has the focus.
//
if (ped->fSingle) {
//
// Single line edit control.
//
cf.dwStyle = CFS_POINT;
cf.ptCurrentPos.x = x;
cf.ptCurrentPos.y = y;
SetRectEmpty(&cf.rcArea);
} else {
//
// Multi line edit control.
//
cf.dwStyle = CFS_RECT;
cf.ptCurrentPos.x = x;
cf.ptCurrentPos.y = y;
cf.rcArea = ped->rcFmt;
}
fpImmGetCompositionWindow( hImc, &cft );
if ( (!RtlEqualMemory(&cf,&cft,sizeof(COMPOSITIONFORM))) ||
(ped->ptScreenBounding.x != rcScreenWindow.left) ||
(ped->ptScreenBounding.y != rcScreenWindow.top) ) {
ped->ptScreenBounding.x = rcScreenWindow.left;
ped->ptScreenBounding.y = rcScreenWindow.top;
fpImmSetCompositionWindow( hImc, &cf );
}
}
fpImmReleaseContext( ped->hwnd, hImc );
}
}
/***************************************************************************\
*
* ECImmSetCompositionFont( PED ped )
*
* xx/xx/9x by somebody Created for Win95
* xx/xx/95 by kazum Ported to NT-J 3.51
* 04/15/96 by takaok Ported to NT 4.0
\***************************************************************************/
VOID ECImmSetCompositionFont( PED ped )
{
HIMC hImc;
LOGFONTW lf;
if ( (hImc = fpImmGetContext( ped->hwnd )) != NULL_HIMC ) {
if (ped->hFont) {
GetObjectW( ped->hFont,
sizeof(LOGFONTW),
(LPLOGFONTW)&lf);
} else {
GetObjectW( GetStockObject(SYSTEM_FONT),
sizeof(LOGFONTW),
(LPLOGFONTW)&lf);
}
fpImmSetCompositionFontW( hImc, &lf );
fpImmReleaseContext( ped->hwnd, hImc );
}
}
/***************************************************************************\
*
* ECInitInsert( PED ped, HKL hkl )
*
* this function is called when:
* 1) a edit control window is initialized
* 2) active keyboard layout of current thread is changed
* 3) read only attribute of this edit control is changed
*
* 04/15/96 by takaok Created
\***************************************************************************/
VOID ECInitInsert( PED ped, HKL hkl )
{
ped->fKorea = FALSE;
ped->fInsertCompChr = FALSE;
ped->fNoMoveCaret = FALSE;
ped->fResultProcess = FALSE;
if ( fpImmIsIME(hkl) ) {
if ( PRIMARYLANGID(LOWORD(HandleToUlong(hkl))) == LANG_KOREAN ) {
ped->fKorea = TRUE;
}
//
// LATER:this flag should be set based on the IME caps
// retrieved from IME. (Such IME caps should be defined)
// For now, we can safely assume that only Korean IMEs
// set CS_INSERTCHAR.
//
if ( ped->fKorea ) {
ped->fInsertCompChr = TRUE;
}
}
//
// if we had a composition character, the shape of caret
// is changed. We need to reset the caret shape.
//
if ( ped->fReplaceCompChr ) {
ped->fReplaceCompChr = FALSE;
ECSetCaretHandler( ped );
}
}
/***************************************************************************\
*
* ECSetCaretHandler( PED ped )
*
* History:
* 07/16/96 by takaok ported from NT 3.51
*
\***************************************************************************/
void ECSetCaretHandler(PED ped)
{
HDC hdc;
SIZE size;
PSTR pText;
// if (!ped->fInsertCompChr || ped->fReadOnly)
// return;
// In any case destroy caret beforehand otherwise SetCaretPos()
// will get crazy.. win95d-B#992,B#2370
//
if (ped->fFocus) {
NtUserHideCaret(ped->hwnd);
DestroyCaret();
if ( ped->fReplaceCompChr ) {
hdc = ECGetEditDC(ped, TRUE );
pText = ECLock(ped);
if ( ped->fAnsi)
GetTextExtentPointA(hdc, pText + ped->ichCaret, 2, &size);
else
GetTextExtentPointW(hdc, (LPWSTR)pText + ped->ichCaret, 1, &size);
ECUnlock(ped);
ECReleaseEditDC(ped, hdc, TRUE);
CreateCaret(ped->hwnd, (HBITMAP)NULL, size.cx, ped->lineHeight);
}
else {
CreateCaret(ped->hwnd,
(HBITMAP)NULL,
(ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
ped->lineHeight);
}
hdc = ECGetEditDC(ped, TRUE );
if ( ped->fSingle )
SLSetCaretPosition( ped, hdc );
else
MLSetCaretPosition( ped, hdc );
ECReleaseEditDC(ped, hdc, TRUE);
NtUserShowCaret(ped->hwnd);
}
}
/***************************************************************************\
*
* LONG ECImeCompoistion( PED ped, WPARAM wParam, LPARAM lParam )
*
* WM_IME_COMPOSITION handler for Korean IME
*
* History:
\***************************************************************************/
extern void MLReplaceSel(PED, LPSTR);
#define GET_COMPOSITION_STRING (ped->fAnsi ? fpImmGetCompositionStringA : fpImmGetCompositionStringW)
BOOL FAR PASCAL ECResultStrHandler(PED ped)
{
HIMC himc;
LPSTR lpStr;
LONG dwLen;
ped->fInsertCompChr = FALSE; // clear the state
ped->fNoMoveCaret = FALSE;
if ((himc = fpImmGetContext(ped->hwnd)) == 0) {
return FALSE;
}
dwLen = GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, NULL, 0);
if (dwLen == 0) {
fpImmReleaseContext(ped->hwnd, himc);
return FALSE;
}
dwLen *= ped->cbChar;
dwLen += ped->cbChar;
lpStr = (LPSTR)UserGlobalAlloc(GPTR, dwLen);
if (lpStr == NULL) {
fpImmReleaseContext(ped->hwnd, himc);
return FALSE;
}
GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, lpStr, dwLen);
if (ped->fSingle) {
SLReplaceSel(ped, lpStr);
} else {
MLReplaceSel(ped, lpStr);
}
UserGlobalFree((HGLOBAL)lpStr);
fpImmReleaseContext(ped->hwnd, himc);
ped->fReplaceCompChr = FALSE;
ped->fNoMoveCaret = FALSE;
ped->fResultProcess = FALSE;
ECSetCaretHandler(ped);
return TRUE;
}
LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
{
INT ich;
LRESULT lReturn = 1;
HDC hdc;
BOOL fSLTextUpdated = FALSE;
ICH iResult;
HIMC hImc;
BYTE TextBuf[4];
if (!ped->fInsertCompChr) {
if (lParam & GCS_RESULTSTR) {
ECInOutReconversionMode(ped, FALSE);
if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) {
ResultAtOnce:
ECResultStrHandler(ped);
lParam &= ~GCS_RESULTSTR;
}
}
return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
}
// In case of Ansi edit control, the length of minimum composition string
// is 2. Check here maximum byte of edit control.
if( ped->fAnsi && ped->cchTextMax == 1 ) {
HIMC hImc;
hImc = fpImmGetContext( ped->hwnd );
fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
fpImmReleaseContext( ped->hwnd, hImc );
NtUserMessageBeep(MB_ICONEXCLAMATION);
return lReturn;
}
// Don't move this after CS_NOMOVECARET check.
// In case if skip the message, fNoMoveCaret should not be set.
if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) {
// Now we're in result processing. GCS_RESULTSTR ends up
// to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
// the message(s) will come later than this CS_INSERTCHAR
// message. This composition character should be handled
// after the WM_CHAR message(s).
//
if(ped->fAnsi)
PostMessageA(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
else
PostMessageW(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
ped->fResultProcess = FALSE;
return lReturn;
}
//
// If fReplaceCompChr is TRUE, we change the shape of caret. A block
// caret is displayed on the composition character. From the user's
// point of view, there is no difference if the caret is before the
// composition character or after the composition character. When
// the composition character is finalized, the insertion point should
// be moved to after the character, any way. Therefore checking
// CS_NOMOVECARET bit doesn't make sense in our current implementation.
// [takaok]
//
#if 0
if (lParam & CS_NOMOVECARET)
ped->fNoMoveCaret=TRUE; // stick to current caret pos.
else
ped->fNoMoveCaret=FALSE;
#endif
if (lParam & GCS_RESULTSTR) {
if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) {
goto ResultAtOnce;
}
ped->fResultProcess=TRUE;
if ( ped->fReplaceCompChr ) {
//
// we have a DBCS character to be replaced.
// let's delete it before inserting the new one.
//
ich = (ped->fAnsi) ? 2 : 1;
ped->fReplaceCompChr = FALSE;
ped->ichMaxSel = min(ped->ichCaret + ich, ped->cch);
ped->ichMinSel = ped->ichCaret;
if ( ECDeleteText( ped ) > 0 ) {
if ( ped->fSingle ) {
//
// Update the display
//
ECNotifyParent(ped, EN_UPDATE);
hdc = ECGetEditDC(ped,FALSE);
SLDrawText(ped, hdc, 0);
ECReleaseEditDC(ped,hdc,FALSE);
//
// Tell parent our text contents changed.
//
ECNotifyParent(ped, EN_CHANGE);
}
}
ECSetCaretHandler( ped );
}
} else if(lParam & CS_INSERTCHAR) {
//
// If we are in the middle of a mousedown command, don't do anything.
//
if (ped->fMouseDown) {
return lReturn;
}
//
// We can safely assume that interimm character is always DBCS.
//
ich = ( ped->fAnsi ) ? 2 : 1;
if ( ped->fReplaceCompChr ) {
//
// we have a character to be replaced.
// let's delete it before inserting the new one.
// when we have a composition characters, the
// caret is placed before the composition character.
//
ped->ichMaxSel = min(ped->ichCaret+ich, ped->cch);
ped->ichMinSel = ped->ichCaret;
}
//
// let's delete current selected text or composition character
//
if ( ped->fSingle ) {
if ( ECDeleteText( ped ) > 0 ) {
fSLTextUpdated = TRUE;
}
} else {
MLDeleteText( ped );
}
//
// When the composition charcter is canceled, IME may give us NULL wParam,
// with CS_INSERTCHAR flag on. We shouldn't insert a NULL character.
//
if ( wParam != 0 ) {
if ( ped->fAnsi ) {
TextBuf[0] = HIBYTE(LOWORD(wParam)); // leading byte
TextBuf[1] = LOBYTE(LOWORD(wParam)); // trailing byte
TextBuf[2] = '\0';
} else {
TextBuf[0] = LOBYTE(LOWORD(wParam));
TextBuf[1] = HIBYTE(LOWORD(wParam));
TextBuf[2] = '\0';
TextBuf[3] = '\0';
}
if ( ped->fSingle ) {
iResult = SLInsertText( ped, (LPSTR)TextBuf, ich );
if (iResult == 0) {
/*
* Couldn't insert the text, for e.g. the text exceeded the limit.
*/
NtUserMessageBeep(0);
} else if (iResult > 0) {
/*
* Remember we need to update the text.
*/
fSLTextUpdated = TRUE;
}
} else {
iResult = MLInsertText( ped, (LPSTR)TextBuf, ich, TRUE);
}
if ( iResult > 0 ) {
//
// ped->fReplaceCompChr will be reset:
//
// 1) when the character is finalized.
// we will receive GCS_RESULTSTR
//
// 2) when the character is canceled.
//
// we will receive WM_IME_COMPOSITION|CS_INSERTCHAR
// with wParam == 0 (in case of user types backspace
// at the first element of composition character).
//
// or
//
// we will receive WM_IME_ENDCOMPOSITION message
//
ped->fReplaceCompChr = TRUE;
//
// Caret should be placed BEFORE the composition
// character.
//
ped->ichCaret = max( 0, (INT)(ped->ichCaret - ich));
ECSetCaretHandler( ped );
} else {
//
// We failed to insert a character. We might run out
// of memory, or reached to the text size limit. let's
// cancel the composition character.
//
hImc = fpImmGetContext(ped->hwnd);
fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
fpImmReleaseContext(ped->hwnd, hImc);
ped->fReplaceCompChr = FALSE;
ECSetCaretHandler( ped );
}
} else {
//
// the composition character is canceled.
//
ped->fReplaceCompChr = FALSE;
ECSetCaretHandler( ped );
}
//
// We won't notify parent the text change
// because the composition character has
// not been finalized.
//
if ( fSLTextUpdated ) {
//
// Update the display
//
ECNotifyParent(ped, EN_UPDATE);
hdc = ECGetEditDC(ped,FALSE);
if ( ped->fReplaceCompChr ) {
//
// move back the caret to the original position
// temporarily so that our new block cursor can
// be located within the visible area of window.
//
ped->ichCaret = min( ped->cch, ped->ichCaret + ich);
SLScrollText(ped, hdc);
ped->ichCaret = max( 0, (INT)(ped->ichCaret - ich));
} else {
SLScrollText(ped, hdc);
}
SLDrawText(ped, hdc, 0);
ECReleaseEditDC(ped,hdc,FALSE);
//
// Tell parent our text contents changed.
//
ECNotifyParent(ped, EN_CHANGE);
}
return lReturn;
}
return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
}
#ifdef LATER // fyi: window 98 equiv.
LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
{
INT ich;
LRESULT lReturn = 1;
HDC hdc;
BOOL fSLTextUpdated = FALSE;
ICH iResult;
HIMC hImc;
BYTE TextBuf[4];
// In case of Ansi edit control, the length of minimum composition string
// is 2. Check here maximum byte of edit control.
if( ped->fAnsi && ped->cchTextMax == 1 ) {
HIMC hImc;
hImc = fpImmGetContext( ped->hwnd );
fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
fpImmReleaseContext( ped->hwnd, hImc );
MessageBeep(MB_ICONEXCLAMATION);
return lReturn;
}
// Don't move this after CS_NOMOVECARET check.
// In case if skip the message, fNoMoveCaret should not be set.
if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) {
// Now we're in result processing. GCS_RESULTSTR ends up
// to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
// the message(s) will come later than this CS_INSERTCHAR
// message. This composition character should be handled
// after the WM_CHAR message(s).
//
(ped->fAnsi ? PostMessageA : PostMessageW)(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
ped->fResultProcess = FALSE;
return lReturn;
}
ped->fNoMoveCaret = (lParam & CS_NOMOVECARET) != 0;
if (lParam & GCS_RESULTSTR) {
ECInOutReconversionMode(ped, FALSE);
if (ped->wImeStatus & EIMS_GETCOMPSTRATONCE) {
ECGetCompStrAtOnce(ped);
goto PassToDefaultWindowProc;
}
// Getting into result processing
ped->fResultProcess = TRUE;
}
else if (lParam & CS_INSERTCHAR) {
ped->fInsertCompChr = TRUE; // Process this composition character.
(ped->fSingleLine ? SLChar : MLChar)(ped, wParam, 0);
if (ped->fInsretCompChr) {
ped->fReplaceCompChr = TRUE; // The next character will replace this.
ped->fInsertCompChr = FALSE; // Clear the state for the next character.
}
ECSetCaretHandler(ped);
return 0;
}
PassToDefaultWindowProc:
return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
}
#endif
/***************************************************************************\
*
* BOOL HanjaKeyHandler( PED ped )
*
* VK_HANJA handler - Korean only
*
* History: July 15,1996 takaok ported from NT 3.51
\***************************************************************************/
BOOL HanjaKeyHandler( PED ped )
{
BOOL changeSelection = FALSE;
if (ped->fKorea && !ped->fReadOnly) {
ICH oldCaret = ped->ichCaret;
if (ped->fReplaceCompChr)
return FALSE;
if (ped->ichMinSel < ped->ichMaxSel)
ped->ichCaret = ped->ichMinSel;
if (!ped->cch || ped->cch == ped->ichCaret) {
ped->ichCaret = oldCaret;
NtUserMessageBeep(MB_ICONEXCLAMATION);
return FALSE;
}
if (ped->fAnsi) {
if (fpImmEscapeA(THREAD_HKL(), fpImmGetContext(ped->hwnd),
IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) {
changeSelection = TRUE;
}
else
ped->ichCaret = oldCaret;
ECUnlock(ped);
}
else {
if (fpImmEscapeW(THREAD_HKL(), fpImmGetContext(ped->hwnd),
IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) {
changeSelection = TRUE;
}
else
ped->ichCaret = oldCaret;
ECUnlock(ped);
}
}
return changeSelection;
}
//////////////////////////////////////////////////////////////////////////////
// EcImeRequestHandler()
//
// Handles WM_IME_REQUEST message originated by IME
//
// Histroy:
// 27-Mar-97 Hiroyama Created
//////////////////////////////////////////////////////////////////////////////
#ifdef CUAS_ENABLE
#define MAX_ECDOCFEED 20
ICH EcImeGetDocFeedMin(PED ped, LPSTR lpstr)
{
ICH ich;
if (!IS_CICERO_ENABLED())
return ped->ichMinSel;
if (ped->ichMinSel > MAX_ECDOCFEED) {
ich = ped->ichMinSel - MAX_ECDOCFEED;
ich = ECAdjustIch(ped, lpstr, ich);
} else {
ich = 0;
}
return ich;
}
ICH EcImeGetDocFeedMax(PED ped, LPSTR lpstr)
{
ICH ich;
if (!IS_CICERO_ENABLED())
return ped->ichMinSel;
if ((ped->cch - ped->ichMaxSel) > MAX_ECDOCFEED) {
ich = ped->ichMaxSel + MAX_ECDOCFEED;
ich = ECAdjustIch(ped, lpstr, ich);
} else {
ich = ped->cch;
}
return ich;
}
#endif // CUAS_ENABLE
LRESULT EcImeRequestHandler(PED ped, WPARAM dwSubMsg, LPARAM lParam)
{
LRESULT lreturn = 0L;
switch (dwSubMsg) {
case IMR_CONFIRMRECONVERTSTRING:
#if !defined(CUAS_ENABLE)
// Edit control does not allow IME to change it.
break;
#else
// Edit control does not allow IME to change it if it is not CUAS.
if (!IS_CICERO_ENABLED())
return 0L;
//
// CHECK VERSION of the structure
//
if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0) {
RIPMSG1(RIP_WARNING, "EcImeRequestHandler: RECONVERTSTRING dwVersion is not expected.",
((LPRECONVERTSTRING)lParam)->dwVersion);
return 0L;
}
if (lParam && ped && ped->fFocus && ped->hText && fpImmIsIME(THREAD_HKL())) {
LPVOID lpSrc;
lpSrc = ECLock(ped);
if (lpSrc == NULL) {
RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed.");
} else {
LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
ICH ichStart;
ICH ichEnd;
UINT cchLen;
ichStart = EcImeGetDocFeedMin(ped, lpSrc);
ichEnd = EcImeGetDocFeedMax(ped, lpSrc);
UserAssert(ichEnd >= ichStart);
cchLen = ichEnd - ichStart; // holds character count.
ECUnlock(ped);
if (lpRCS->dwStrLen != cchLen) {
RIPMSG0(RIP_WARNING, "EcImeRequestHandler: the given string length is not expected.");
} else {
ICH ichSelStart;
ICH ichSelEnd;
ichSelStart = ichStart + (lpRCS->dwCompStrOffset / ped->cbChar);
ichSelEnd = ichSelStart + lpRCS->dwCompStrLen;
(ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_SETSEL, ichSelStart, ichSelEnd);
lreturn = 1L;
}
}
}
break;
#endif // CUAS_ENABLE
case IMR_RECONVERTSTRING:
//
// CHECK VERSION of the structure
//
if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0) {
RIPMSG1(RIP_WARNING, "EcImeRequestHandler: RECONVERTSTRING dwVersion is not expected.",
((LPRECONVERTSTRING)lParam)->dwVersion);
return 0L;
}
if (ped && ped->fFocus && ped->hText && fpImmIsIME(THREAD_HKL())) {
#if !defined(CUAS_ENABLE)
UINT cchLen = ped->ichMaxSel - ped->ichMinSel; // holds character count.
#else
ICH ichStart;
ICH ichEnd;
UINT cchLen;
UINT cchSelLen;
LPVOID lpSrc;
lpSrc = ECLock(ped);
if (lpSrc == NULL) {
RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed.");
return 0L;
}
ichStart = EcImeGetDocFeedMin(ped, lpSrc);
ichEnd = EcImeGetDocFeedMax(ped, lpSrc);
UserAssert(ichEnd >= ichStart);
cchLen = ichEnd - ichStart; // holds character count.
cchSelLen = ped->ichMaxSel - ped->ichMinSel; // holds character count.
#endif
if (cchLen == 0) {
#if defined(CUAS_ENABLE)
ECUnlock(ped);
#endif
// if we have no selection,
// just return 0.
break;
}
UserAssert(ped->cbChar == sizeof(BYTE) || ped->cbChar == sizeof(WCHAR));
// This Edit Control has selection.
if (lParam == 0) {
//
// IME just want to get required size for buffer.
// cchLen + 1 is needed to reserve room for trailing L'\0'.
// ~~~~
lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
#if defined(CUAS_ENABLE)
ECUnlock(ped);
#endif
} else {
LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
#if !defined(CUAS_ENABLE)
LPVOID lpSrc;
#endif
LPVOID lpDest = (LPBYTE)lpRCS + sizeof(RECONVERTSTRING);
// check buffer size
// if the given buffer is smaller than actual needed size,
// shrink our size to fit the buffer
if ((INT)lpRCS->dwSize <= sizeof(RECONVERTSTRING) + cchLen * ped->cbChar) {
RIPMSG0(RIP_WARNING, "EcImeRequest: ERR09");
cchLen = (lpRCS->dwSize - sizeof(RECONVERTSTRING)) / ped->cbChar - ped->cbChar;
}
lpRCS->dwStrOffset = sizeof(RECONVERTSTRING); // buffer begins just after RECONVERTSTRING
#if !defined(CUAS_ENABLE)
lpRCS->dwCompStrOffset =
lpRCS->dwTargetStrOffset = 0;
lpRCS->dwStrLen =
lpRCS->dwCompStrLen =
lpRCS->dwTargetStrLen = cchLen; // StrLen means TCHAR count
lpSrc = ECLock(ped);
if (lpSrc == NULL) {
RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed.");
} else
#else
lpRCS->dwCompStrOffset =
lpRCS->dwTargetStrOffset = (ped->ichMinSel - ichStart) * ped->cbChar; // BYTE count offset
lpRCS->dwStrLen = cchLen; // TCHAR count
lpRCS->dwCompStrLen =
lpRCS->dwTargetStrLen = cchSelLen; // TCHAR count
#endif
{
#if !defined(CUAS_ENABLE)
RtlCopyMemory(lpDest,
(LPBYTE)lpSrc + ped->ichMinSel * ped->cbChar,
cchLen * ped->cbChar);
#else
RtlCopyMemory(lpDest,
(LPBYTE)lpSrc + ichStart * ped->cbChar,
cchLen * ped->cbChar);
#endif
// Null-Terminate the string
if (ped->fAnsi) {
LPBYTE psz = (LPBYTE)lpDest;
psz[cchLen] = '\0';
} else {
LPWSTR pwsz = (LPWSTR)lpDest;
pwsz[cchLen] = L'\0';
}
ECUnlock(ped);
// final buffer size
lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
ECInOutReconversionMode(ped, TRUE);
ECImmSetCompositionWindow(ped, 0, 0);
}
}
}
break;
}
return lreturn;
}