Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1785 lines
52 KiB

/*++
*
* WOW v1.0
*
* Copyright (c) 1991, Microsoft Corporation
*
* EDITSL.C
* Win16 edit control code
*
* History:
*
* Created 28-May-1991 by Jeff Parsons (jeffpar)
* Copied from WIN31 and edited (as little as possible) for WOW16.
--*/
/****************************************************************************/
/* editsl.c - Edit controls rewrite. Version II of edit controls. */
/* */
/* */
/* Created: 24-Jul-88 davidds */
/****************************************************************************/
#define NO_LOCALOBJ_TAGS
#include "user.h"
#include "edit.h"
/****************************************************************************/
/* Single Line Support Routines */
/****************************************************************************/
void FAR PASCAL SLSetCaretPosition(ped,hdc)
register PED ped;
HDC hdc;
/* effects: If the window has the focus, find where the caret belongs and move
* it there.
*/
{
int xPosition;
/* We will only position the caret if we have the focus since we don't want
* to move the caret while another window could own it.
*/
if (ped->fNoRedraw || !ped->fFocus)
return;
xPosition = SLIchToLeftXPos(ped, hdc, ped->ichCaret);
if (!ped->fAutoHScroll)
/* Don't leet caret go out of bounds of edit contol if there is too much
* text in a non scrolling edit control.
*/
xPosition = min(xPosition, ped->rcFmt.right-1);
SetCaretPos(xPosition, ped->rcFmt.top);
}
int NEAR PASCAL SLIchToLeftXPos(ped, hdc, ich)
register PED ped;
HDC hdc;
ICH ich;
/* effects: Given a character index, find its (left side) x coordinate within
* the ped->rcFmt rectangle assuming the character ped->screenStart is at
* coordinates (ped->rcFmt.top, ped->rcFmt.left). A negative value is
* returned if the character ich is to the left of ped->screenStart. WARNING:
* ASSUMES AT MOST 1000 characters will be VISIBLE at one time on the screen.
* There may be 64K total characters in the editcontrol, but we can only
* display 1000 without scrolling. This shouldn't be a problem obviously.
*/
{
int textExtent;
register PSTR pText;
/* Check if we are adding lots and lots of chars. A paste for example could
* cause this and GetTextExtents could overflow on this.
*/
if (ich > ped->screenStart && ich - ped->screenStart > 1000)
return(30000);
if (ped->screenStart > ich && ped->screenStart - ich > 1000)
return(-30000);
if (ped->fNonPropFont)
return((ich-ped->screenStart)*ped->aveCharWidth + ped->rcFmt.left);
/* Check if password hidden chars are being used. */
if (ped->charPasswordChar)
return((ich-ped->screenStart)*ped->cPasswordCharWidth+ped->rcFmt.left);
pText = LocalLock(ped->hText);
if (ped->screenStart <= ich)
{
textExtent = LOWORD(GetTextExtent(hdc,
(LPSTR)(pText + ped->screenStart),
ich-ped->screenStart));
/* In case of signed/unsigned overflow since the text extent may be
* greater than maxint. This happens with long single line edit
* controls. The rect we edit text in will never be greater than 30000
* pixels so we are ok if we just ignore them.
*/
if (textExtent < 0 || textExtent > 31000)
textExtent = 30000;
}
else
textExtent = (-1) *
(int)LOWORD(GetTextExtent(hdc,(LPSTR)(pText + ich),
ped->screenStart-ich));
LocalUnlock(ped->hText);
return(textExtent-ped->charOverhang + ped->rcFmt.left);
}
/* effects: This finds out if the given ichPos falls within the current
* Selection range and if so returns TRUE; Else returns FALSE.
*/
BOOL NEAR PASCAL SLGetHiliteAttr(PED ped, ICH ichPos)
{
return((ichPos >= ped->ichMinSel) && (ichPos < ped->ichMaxSel));
}
/* effects: This takes care of erasing the old selection and drawing the new
* selection
*/
void NEAR PASCAL SLRepaintChangedSelection(
PED ped, HDC hdc,
ICH ichOldMinSel, ICH ichOldMaxSel)
{
BLOCK Blk[2];
int i;
Blk[0].StPos = ichOldMinSel;
Blk[0].EndPos = ichOldMaxSel;
Blk[1].StPos = ped->ichMinSel;
Blk[1].EndPos = ped->ichMaxSel;
if(ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
(LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1]))
{
UpdateWindow(ped->hwnd);
/* Paint the rectangles where selection has changed */
/* Paint both Blk[0] and Blk[1], if they exist */
for(i = 0; i < 2; i++)
{
if (Blk[i].StPos != -1)
SLDrawLine(ped, hdc, Blk[i].StPos, Blk[i].EndPos - Blk[i].StPos,
SLGetHiliteAttr(ped, Blk[i].StPos));
}
}
}
void FAR PASCAL SLChangeSelection(ped, hdc, ichNewMinSel, ichNewMaxSel)
register PED ped;
HDC hdc;
ICH ichNewMinSel;
ICH ichNewMaxSel;
/* effects: Changes the current selection to have the specified starting and
* ending values. Properly highlights the new selection and unhighlights
* anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
* them. Doesn't update the caret position.
*/
{
ICH temp;
ICH ichOldMinSel;
ICH ichOldMaxSel;
if (ichNewMinSel > ichNewMaxSel)
{
temp = ichNewMinSel;
ichNewMinSel = ichNewMaxSel;
ichNewMaxSel = temp;
}
ichNewMinSel = umin(ichNewMinSel, ped->cch);
ichNewMaxSel = umin(ichNewMaxSel, ped->cch);
/* Preserve the Old selection */
ichOldMinSel = ped->ichMinSel;
ichOldMaxSel = ped->ichMaxSel;
/* Set new selection */
ped->ichMinSel = ichNewMinSel;
ped->ichMaxSel = ichNewMaxSel;
/* We will find the intersection of current selection rectangle with the new
* selection rectangle. We will then invert the parts of the two rectangles
* not in the intersection.
*/
if (!ped->fNoRedraw && (ped->fFocus || ped->fNoHideSel))
{
if (ped->fFocus)
HideCaret(ped->hwnd);
SLRepaintChangedSelection(ped, hdc, ichOldMinSel, ichOldMaxSel);
SLSetCaretPosition(ped,hdc);
if (ped->fFocus)
ShowCaret(ped->hwnd);
}
}
void NEAR PASCAL SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus)
register PED ped;
register HDC hdc;
ICH ichStart;
int iCount;
BOOL fSelStatus;
/* This draws the line starting from ichStart, iCount number of characters;
* fSelStatus is TRUE, if it is to be drawn with the "selection" attribute.
*/
{
RECT rc;
HBRUSH hBrush;
PSTR pText;
DWORD rgbSaveBk;
DWORD rgbSaveText;
int iStCount;
DWORD rgbGray=0;
if (ped->fNoRedraw)
return;
if (ichStart < ped->screenStart)
{
if (ichStart+iCount < ped->screenStart)
return;
iCount = iCount - (ped->screenStart-ichStart);
ichStart = ped->screenStart;
}
CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
/* Set the proper clipping rectangle */
ECSetEditClip(ped, hdc);
pText = (PSTR) LocalLock(ped->hText);
/* Calculates the rectangle area to be wiped out */
if (iStCount = ichStart - ped->screenStart)
{
if (ped->charPasswordChar)
rc.left += ped->cPasswordCharWidth * iStCount;
else
rc.left += LOWORD(GetTextExtent(hdc,
(LPSTR)(pText + ped->screenStart),
iStCount)) -
ped->charOverhang;
}
if (ped->charPasswordChar)
rc.right = rc.left + ped->cPasswordCharWidth * iCount;
else
rc.right = rc.left + LOWORD(GetTextExtent(hdc,
(LPSTR)(pText + ichStart),
iCount));
/* Set the background mode before calling GetControlBrush so that the app
* can change it to TRANSPARENT if it wants to.
*/
SetBkMode(hdc, OPAQUE);
if (fSelStatus)
{
hBrush = ped->hbrHiliteBk;
rgbSaveBk = SetBkColor(hdc, ped->rgbHiliteBk);
rgbSaveText = SetTextColor(hdc, ped->rgbHiliteText);
}
else
{
/* We always want to send this so that the app has a chance to muck with
* the DC
*/
hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
}
if (ped->fDisabled &&
(rgbGray = GetSysColor(COLOR_GRAYTEXT)))
{
/* Grey the text in the edit control if disabled.
*/
rgbSaveText = SetTextColor(hdc, rgbGray);
}
/* Erase the rectangular area before text is drawn. Note that we inflate the
* rect by 1 so that the selection color has a one pixel border around the
* text.
*/
InflateRect((LPRECT)&rc, 0, 1);
/* Use paint rect so that the brush gets aligned if dithered.
*/
PaintRect(ped->hwndParent, ped->hwnd, hdc, hBrush, (LPRECT)&rc);
InflateRect((LPRECT)&rc, 0, -1);
if (ped->charPasswordChar)
{
for (iStCount = 0; iStCount < iCount; iStCount++)
TextOut(hdc,
rc.left+iStCount*ped->cPasswordCharWidth,
rc.top,
(LPSTR)&ped->charPasswordChar,
1);
}
else
TextOut(hdc,rc.left,rc.top,(LPSTR)(pText+ichStart),iCount);
if (fSelStatus || rgbGray)
{
SetTextColor(hdc, rgbSaveText);
if (fSelStatus)
SetBkColor(hdc, rgbSaveBk);
}
LocalUnlock(ped->hText);
}
int NEAR PASCAL SLGetBlkEnd(ped, ichStart, ichEnd, lpfStatus)
register PED ped;
register ICH ichStart;
ICH ichEnd;
BOOL FAR *lpfStatus;
/* Given a Starting point and and end point, this function returns whether the
* first few characters fall inside or outside the selection block and if so,
* howmany characters?
*/
{
*lpfStatus = FALSE;
if (ichStart >= ped->ichMinSel)
{
if(ichStart >= ped->ichMaxSel)
return(ichEnd - ichStart);
*lpfStatus = TRUE;
return(min(ichEnd, ped->ichMaxSel) - ichStart);
}
return(min(ichEnd, ped->ichMinSel) - ichStart);
}
void NEAR PASCAL SLDrawText(ped, hdc, ichStart)
register PED ped;
register HDC hdc;
ICH ichStart;
/* effects: Draws text for a single line edit control in the rectangle
* specified by ped->rcFmt. If ichStart == 0, starts drawing text at the left
* side of the window starting at character index ped->screenStart and draws
* as much as will fit. If ichStart > 0, then it appends the characters
* starting at ichStart to the end of the text showing in the window. (ie. We
* are just growing the text length and keeping the left side
* (ped->screenStart to ichStart characters) the same. Assumes the hdc came
* from ECGetEditDC so that the caret and such are properly hidden.
*/
{
ICH cchToDraw;
RECT rc;
PSTR pText;
BOOL fSelStatus;
int iCount;
ICH ichEnd;
BOOL fNoSelection;
if (ped->fNoRedraw)
return;
if (ichStart == 0)
ichStart = ped->screenStart;
CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
/* Find out how many characters will fit on the screen so that we don't do
* any needless drawing.
*/
pText = (PSTR) LocalLock(ped->hText);
cchToDraw = ECCchInWidth(ped, hdc,
(LPSTR)(pText+ped->screenStart),
ped->cch-ped->screenStart,
rc.right - rc.left);
ichEnd = ped->screenStart + cchToDraw;
/*
* There is no selection if,
* 1. MinSel and MaxSel are equal OR
* 2. (This has lost the focus AND Selection is to be hidden)
*/
fNoSelection = ((ped->ichMinSel == ped->ichMaxSel) ||
(!ped->fFocus && !ped->fNoHideSel));
while (ichStart < ichEnd)
{
if (fNoSelection)
{
fSelStatus = FALSE;
iCount = ichEnd - ichStart;
}
else
iCount = SLGetBlkEnd(ped, ichStart, ichEnd,
(BOOL FAR *)&fSelStatus);
SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus);
ichStart += iCount;
}
if (cchToDraw)
{
/* Check if password hidden chars are being used. */
if (ped->charPasswordChar)
rc.left += ped->cPasswordCharWidth * cchToDraw;
else
rc.left += LOWORD(GetTextExtent(hdc,
(LPSTR)(pText + ped->screenStart), cchToDraw));
}
LocalUnlock(ped->hText);
/* Check if anything to be erased on the right hand side */
if (rc.left < rc.right)
{
SetBkMode(hdc, OPAQUE);
/* Erase the rectangular area before text is drawn. Note that we inflate
* the rect by 1 so that the selection color has a one pixel border
* around the text.
*/
InflateRect((LPRECT)&rc, 0, 1);
PaintRect(ped->hwndParent, ped->hwnd, hdc, NULL, (LPRECT)&rc);
}
SLSetCaretPosition(ped, hdc);
}
BOOL FAR PASCAL SLScrollText(ped, hdc)
register PED ped;
HDC hdc;
/* effects: Scrolls the text to bring the caret into view. If the text is
* scrolled, the current selection is unhighlighted. Returns TRUE if the text
* is scrolled else returns false.
*/
{
register PSTR pText;
ICH scrollAmount = (ped->rcFmt.right-ped->rcFmt.left)/4/ped->aveCharWidth+1;
ICH newScreenStartX = ped->screenStart;
if (!ped->fAutoHScroll)
return(FALSE);
/* Calculate the new starting screen position */
if (ped->ichCaret <= ped->screenStart)
{
/* Caret is to the left of the starting text on the screen we must
* scroll the text backwards to bring it into view. Watch out when
* subtracting unsigned numbers when we have the possibility of going
* negative.
*/
if (ped->ichCaret > scrollAmount)
newScreenStartX = ped->ichCaret - scrollAmount;
else
newScreenStartX = 0;
}
else
{
pText = (PSTR) LocalLock(ped->hText);
if ((ped->ichCaret != ped->screenStart) &&
(ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
ped->ichCaret - ped->screenStart,
ped->rcFmt.right-ped->rcFmt.left) <
ped->ichCaret - ped->screenStart))
{
newScreenStartX = ((ped->ichCaret < scrollAmount*2) ? 0 :
ped->ichCaret - scrollAmount*2);
}
LocalUnlock(ped->hText);
}
#ifdef FE_SB
pText = (PSTR) LocalLock(ped->hText);
newScreenStartX = ECAdjustIch( ped,pText,newScreenStartX );
LocalUnlock(ped->hText);
#endif
if (ped->screenStart != newScreenStartX)
{
ped->screenStart = newScreenStartX;
SLDrawText(ped, hdc, 0);
/* Caret pos is set by drawtext */
return(TRUE);
}
return(FALSE);
}
ICH FAR PASCAL SLInsertText(ped, lpText, cchInsert)
register PED ped;
LPSTR lpText;
register ICH cchInsert;
/* effects: Adds up to cchInsert characters from lpText to the ped starting at
* ichCaret. If the ped only allows a maximum number of characters, then we
* will only add that many characters to the ped and send a EN_MAXTEXT
* notification code to the parent of the ec. Also, if !fAutoHScroll, then we
* only allow as many chars as will fit in the client rectangle. The number of
* characters actually added is returned (could be 0). If we can't allocate
* the required space, we notify the parent with EN_ERRSPACE and no characters
* are added.
*/
{
HDC hdc;
PSTR pText;
ICH cchInsertCopy = cchInsert;
int textWidth;
/* First determine exactly how many characters from lpText we can insert
* into the ped.
*/
if (!ped->fAutoHScroll)
{
pText = (PSTR)LocalLock(ped->hText);
hdc = ECGetEditDC(ped, TRUE);
/* If ped->fAutoHScroll bit is not set, then we only insert as many
* characters as will fit in the ped->rcFmt rectangle upto a maximum of
* ped->cchTextMax - ped->cch characters. Note that if password style is
* on, we allow the user to enter as many chars as the number of
* password chars which fit in the rect.
*/
if (ped->cchTextMax <= ped->cch)
cchInsert = 0;
else
{
cchInsert = umin(cchInsert, (unsigned)(ped->cchTextMax - ped->cch));
if (ped->charPasswordChar)
textWidth = ped->cch * ped->cPasswordCharWidth;
else
textWidth = LOWORD(GetTextExtent(hdc, (LPSTR)pText, ped->cch));
cchInsert = umin(cchInsert,
ECCchInWidth(ped, hdc, lpText, cchInsert,
ped->rcFmt.right-ped->rcFmt.left-
textWidth));
}
LocalUnlock(ped->hText);
ECReleaseEditDC(ped, hdc, TRUE);
}
else
{
if (ped->cchTextMax <= ped->cch)
cchInsert = 0;
else
cchInsert = umin((unsigned)(ped->cchTextMax - ped->cch), cchInsert);
}
/* Now try actually adding the text to the ped */
if (cchInsert && !ECInsertText(ped, lpText, cchInsert))
{
ECNotifyParent(ped, EN_ERRSPACE);
return(0);
}
if (cchInsert)
ped->fDirty = TRUE; /* Set modify flag */
if (cchInsert < cchInsertCopy)
/* Notify parent that we couldn't insert all the text requested */
ECNotifyParent(ped, EN_MAXTEXT);
/* Update selection extents and the caret position. Note that ECInsertText
* updates ped->ichCaret, ped->ichMinSel, and ped->ichMaxSel to all be after
* the inserted text.
*/
return(cchInsert);
}
ICH PASCAL NEAR SLPasteText(register PED ped)
/* effects: Pastes a line of text from the clipboard into the edit control
* starting at ped->ichMaxSel. Updates ichMaxSel and ichMinSel to point to
* the end of the inserted text. Notifies the parent if space cannot be
* allocated. Returns how many characters were inserted.
*/
{
HANDLE hData;
LPSTR lpchClip;
LPSTR lpchClip2;
register ICH cchAdded;
ICH clipLength;
if (!OpenClipboard(ped->hwnd))
return(0);
if (!(hData = GetClipboardData(CF_TEXT)))
{
CloseClipboard();
return(0);
}
lpchClip2 = lpchClip = (LPSTR) GlobalLock(hData);
/* Find the first carrage return or line feed. Just add text to that point.
*/
clipLength = (WORD)lstrlen(lpchClip);
for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
if (*lpchClip2++ == 0x0D)
break;
/* Insert the text (SLInsertText checks line length) */
cchAdded = SLInsertText(ped, lpchClip, cchAdded);
GlobalUnlock(hData);
CloseClipboard();
return(cchAdded);
}
void NEAR PASCAL SLReplaceSelHandler(register PED ped,
LPSTR lpText)
/* effects: Replaces the text in the current selection with the given text.
*/
{
BOOL fUpdate;
HDC hdc;
SwapHandle(&lpText);
ECEmptyUndo(ped);
fUpdate = (BOOL)ECDeleteText(ped);
ECEmptyUndo(ped);
SwapHandle(&lpText);
fUpdate = (BOOL)SLInsertText(ped, lpText, lstrlen(lpText)) || fUpdate;
ECEmptyUndo(ped);
if (fUpdate)
{
ECNotifyParent(ped, EN_UPDATE);
hdc = ECGetEditDC(ped,FALSE);
if (!SLScrollText(ped,hdc))
SLDrawText(ped,hdc,0);
ECReleaseEditDC(ped,hdc,FALSE);
ECNotifyParent(ped,EN_CHANGE);
}
}
void FAR PASCAL SLCharHandler(ped, keyValue, keyMods)
register PED ped;
WORD keyValue;
int keyMods;
/* effects: Handles character input (really, no foolin')
*/
{
register HDC hdc;
unsigned char keyPress = LOBYTE(keyValue);
BOOL updateText = FALSE;
#ifdef FE_SB
PSTR pText;
int InsertTextLen = 0;
WORD DBCSkey;
#endif
if (ped->fMouseDown || ped->fReadOnly)
/* Don't do anything if we are in the middle of a mousedown deal or if
* this is a read only edit control.
*/
return;
if ((keyPress == BACKSPACE) || (keyPress >= ' '))
{
/* Delete the selected text if any */
if (ECDeleteText(ped))
updateText=TRUE;
}
switch(keyPress)
{
case BACKSPACE:
/* Delete any selected text or delete character left if no sel */
if (!updateText && ped->ichMinSel)
{
/* There was no selection to delete so we just delete character
left if available */
#ifdef FE_SB
pText = LMHtoP( ped->hText );
if( ECAnsiPrev( ped,pText, pText+ped->ichMinSel) == pText+ped->ichMinSel-2)
ped->ichMinSel--;
#endif
ped->ichMinSel--;
(void) ECDeleteText(ped);
updateText = TRUE;
}
break;
default:
if (keyPress >= ' ')
{
#ifdef FE_SB
InsertTextLen = 1;
if( IsDBCSLeadByte( keyPress ) )
if( ( DBCSkey = DBCSCombine( ped->hwnd, keyPress ) ) != NULL )
if( SLInsertText( ped, (LPSTR)&DBCSkey, 2 ) == 2){
InsertTextLen = 2;
updateText = TRUE;
}else
MessageBeep(0);
else
MessageBeep(0);
else
#endif
if (SLInsertText(ped, (LPSTR) &keyPress, 1))
updateText = TRUE;
else
/* Beep. Since we couldn't add the text */
MessageBeep(0);
}
else
/* User hit an illegal control key */
MessageBeep(0);
break;
}
if (updateText)
{
/* Dirty flag (ped->fDirty) was set when we inserted text */
ECNotifyParent(ped, EN_UPDATE);
hdc = ECGetEditDC(ped,FALSE);
if (!SLScrollText(ped,hdc))
#ifdef FE_SB
SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - InsertTextLen));
#else
SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - 1));
#endif
ECReleaseEditDC(ped,hdc,FALSE);
ECNotifyParent(ped,EN_CHANGE);
}
}
void NEAR PASCAL SLKeyDownHandler(register PED ped,
WORD virtKeyCode,
int keyMods)
/* effects: Handles cursor movement and other VIRT KEY stuff. keyMods allows
* us to make SLKeyDownHandler calls and specify if the modifier keys (shift
* and control) are up or down. This is useful for imnplementing the
* cut/paste/clear messages for single line edit controls. If keyMods == 0,
* we get the keyboard state using GetKeyState(VK_SHIFT) etc. Otherwise, the
* bits in keyMods define the state of the shift and control keys.
*/
{
HDC hdc;
/* Variables we will use for redrawing the updated text */
register ICH newMaxSel = ped->ichMaxSel;
ICH newMinSel = ped->ichMinSel;
/* Flags for drawing the updated text */
BOOL updateText = FALSE;
BOOL changeSelection = FALSE; /* new selection is specified by
newMinSel, newMaxSel */
/* Comparisons we do often */
BOOL MinEqMax = (newMaxSel == newMinSel);
BOOL MinEqCar = (ped->ichCaret == newMinSel);
BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
/* State of shift and control keys. */
int scState = 0;
/* Combo box support */
BOOL fIsListVisible;
BOOL fIsExtendedUI;
#ifdef FE_SB
PSTR pText;
#endif
if (ped->fMouseDown)
{
/* If we are in the middle of a mouse down handler, then don't do
* anything. ie. ignore keyboard input.
*/
return;
}
if (!keyMods)
{
/* Get state of modifier keys for use later. */
scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0);
}
else
scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
switch(virtKeyCode)
{
case VK_UP:
if (ped->listboxHwnd)
{
/* Handle Combobox support */
fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
if (!fIsListVisible && fIsExtendedUI)
{
/* For TandyT
*/
DropExtendedUIListBox:
/* Since an extendedui combo box doesn't do anything on f4, we
* turn off the extended ui, send the f4 to drop, and turn it
* back on again.
*/
SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 0, 0L);
SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L);
SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 1, 0L);
return;
}
else
goto SendKeyToListBox;
}
/* else fall through */
case VK_LEFT:
/* If the caret isn't already at 0, we can move left */
if (ped->ichCaret)
{
switch (scState)
{
case NONEDOWN:
/* Clear selection, move caret left */
#ifdef FE_SB
pText = LMHtoP( ped->hText );
if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
pText + ped->ichCaret - 2 )
ped->ichCaret--;
#endif
ped->ichCaret--;
newMaxSel = newMinSel = ped->ichCaret;
break;
case CTRLDOWN:
/* Clear selection, move caret word left */
ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
newMaxSel = newMinSel = ped->ichCaret;
break;
case SHFTDOWN:
/* Extend selection, move caret left */
#ifdef FE_SB
pText = LMHtoP( ped->hText );
if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
pText + ped->ichCaret - 2 )
ped->ichCaret--;
#endif
ped->ichCaret--;
if (MaxEqCar && !MinEqMax)
/* Reduce selection extent */
newMaxSel = ped->ichCaret;
else
/* Extend selection extent */
newMinSel = ped->ichCaret;
break;
case SHCTDOWN:
/* Extend selection, move caret word left */
ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
if (MaxEqCar && !MinEqMax)
{
/* Reduce selection extent */
/*
* Hint: Suppose WORD. OR is selected. Cursor between R
* and D. Hit select word left, we want to just select the
* W and leave cursor before the W.
*/
newMinSel = ped->ichMinSel;
newMaxSel = ped->ichCaret;
}
else
/* Extend selection extent */
newMinSel = ped->ichCaret;
break;
}
changeSelection = TRUE;
}
else
{
/* If the user tries to move left and we are at the 0th character
and there is a selection, then cancel the selection. */
if (ped->ichMaxSel != ped->ichMinSel &&
(scState == NONEDOWN || scState == CTRLDOWN))
{
changeSelection = TRUE;
newMaxSel = newMinSel = ped->ichCaret;
}
}
break;
case VK_DOWN:
if (ped->listboxHwnd)
{
/* Handle Combobox support */
fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
if (!fIsListVisible && fIsExtendedUI)
{
/* For TandyT
*/
goto DropExtendedUIListBox;
}
else
goto SendKeyToListBox;
}
/* else fall through */
case VK_RIGHT:
/*
* If the caret isn't already at ped->cch, we can move right.
*/
if (ped->ichCaret < ped->cch)
{
switch (scState)
{
case NONEDOWN:
/* Clear selection, move caret right */
#ifdef FE_SB
pText = LMHtoP( ped->hText ) + ped->ichCaret;
if( ECIsDBCSLeadByte( ped, *pText ) )
ped->ichCaret++;
#endif
ped->ichCaret++;
newMaxSel = newMinSel = ped->ichCaret;
break;
case CTRLDOWN:
/* Clear selection, move caret word right */
ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
newMaxSel = newMinSel = ped->ichCaret;
break;
case SHFTDOWN:
/* Extend selection, move caret right */
#ifdef FE_SB
pText = LMHtoP( ped->hText ) + ped->ichCaret;
if( ECIsDBCSLeadByte( ped, *pText ) )
ped->ichCaret++;
#endif
ped->ichCaret++;
if (MinEqCar && !MinEqMax)
/* Reduce selection extent */
newMinSel = ped->ichCaret;
else
/* Extend selection extent */
newMaxSel = ped->ichCaret;
break;
case SHCTDOWN:
/* Extend selection, move caret word right */
ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
if (MinEqCar && !MinEqMax)
{
/* Reduce selection extent */
newMinSel = ped->ichCaret;
newMaxSel = ped->ichMaxSel;
}
else
/* Extend selection extent */
newMaxSel = ped->ichCaret;
break;
}
changeSelection = TRUE;
}
else
{
/* If the user tries to move right and we are at the last character
and there is a selection, then cancel the selection. */
if (ped->ichMaxSel != ped->ichMinSel &&
(scState == NONEDOWN || scState == CTRLDOWN))
{
newMaxSel = newMinSel = ped->ichCaret;
changeSelection = TRUE;
}
}
break;
case VK_HOME:
ped->ichCaret = 0;
switch (scState)
{
case NONEDOWN:
case CTRLDOWN:
/* Clear selection, move caret home */
newMaxSel = newMinSel = ped->ichCaret;
break;
case SHFTDOWN:
case SHCTDOWN:
/* Extend selection, move caret home */
if (MaxEqCar && !MinEqMax)
{
/* Reduce/negate selection extent */
newMinSel = 0;
newMaxSel = ped->ichMinSel;
}
else
/* Extend selection extent */
newMinSel = ped->ichCaret;
break;
}
changeSelection = TRUE;
break;
case VK_END:
newMaxSel = ped->ichCaret = ped->cch;
switch (scState)
{
case NONEDOWN:
case CTRLDOWN:
/* Clear selection, move caret to end of text */
newMinSel = ped->cch;
break;
case SHFTDOWN:
case SHCTDOWN:
/* Extend selection, move caret to end of text */
if (MinEqCar && !MinEqMax)
/* Reduce/negate selection extent */
newMinSel = ped->ichMaxSel;
/* else Extend selection extent */
break;
}
changeSelection = TRUE;
break;
case VK_DELETE:
if (ped->fReadOnly)
break;
switch (scState)
{
case NONEDOWN:
/* Clear selection. If no selection, delete (clear) character
* right.
*/
if ((ped->ichMaxSel<ped->cch) &&
(ped->ichMinSel==ped->ichMaxSel))
{
/* Move cursor forwards and simulate a backspace.
*/
#ifdef FE_SB
pText = LMHtoP( ped->hText ) + ped->ichCaret;
if( ECIsDBCSLeadByte( ped, *pText ) )
ped->ichCaret++;
#endif
ped->ichCaret++;
ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
SLCharHandler(ped, (WORD) BACKSPACE, 0);
}
if (ped->ichMinSel != ped->ichMaxSel)
SLCharHandler(ped, (WORD) BACKSPACE, 0);
break;
case SHFTDOWN:
/* CUT selection ie. remove and copy to clipboard, or if no
* selection, delete (clear) character left.
*/
if (SendMessage(ped->hwnd, WM_COPY, (WORD)0,0L) ||
(ped->ichMinSel == ped->ichMaxSel))
/* If copy successful, delete the copied text by simulating a
* backspace message which will redraw the text and take care
* of notifying the parent of changes. Or if there is no
* selection, just delete char left.
*/
SLCharHandler(ped, (WORD) BACKSPACE, 0);
break;
case CTRLDOWN:
/* Delete to end of line if no selection else delete (clear)
* selection.
*/
if ((ped->ichMaxSel<ped->cch) &&
(ped->ichMinSel==ped->ichMaxSel))
{
/* Move cursor to end of line and simulate a backspace.
*/
ped->ichMaxSel = ped->ichCaret = ped->cch;
}
if (ped->ichMinSel != ped->ichMaxSel)
SLCharHandler(ped, (WORD) BACKSPACE, 0);
break;
}
/* No need to update text or selection since BACKSPACE message does it
* for us.
*/
break;
case VK_INSERT:
switch (scState)
{
case CTRLDOWN:
/* Copy current selection to clipboard */
SendMessage(ped->hwnd, WM_COPY, (WORD)NULL, (LONG)NULL);
break;
case SHFTDOWN:
if (ped->fReadOnly)
break;
/* Insert contents of clipboard (PASTE) */
/* Unhighlight current selection and delete it, if any */
ECDeleteText(ped);
SLPasteText(ped);
updateText = TRUE;
ECNotifyParent(ped, EN_UPDATE);
break;
}
break;
case VK_F4:
case VK_PRIOR:
case VK_NEXT:
/* Send keys to the listbox if we are a part of a combo box. This
* assumes the listbox ignores keyup messages which is correct right
* now.
*/
if (ped->listboxHwnd)
{
SendKeyToListBox:
/* Handle Combobox support */
SendMessage(ped->listboxHwnd, WM_KEYDOWN, virtKeyCode, 0L);
return;
}
}
if (changeSelection || updateText)
{
hdc = ECGetEditDC(ped,FALSE);
/* Scroll if needed */
SLScrollText(ped,hdc);
if (changeSelection)
SLChangeSelection(ped,hdc,newMinSel,newMaxSel);
if (updateText)
SLDrawText(ped,hdc,0);
/* SLSetCaretPosition(ped,hdc);*/
ECReleaseEditDC(ped,hdc,FALSE);
if (updateText)
ECNotifyParent(ped, EN_CHANGE);
}
}
ICH NEAR PASCAL SLMouseToIch(ped, hdc, mousePt)
register PED ped;
HDC hdc;
POINT mousePt;
/* effects: Returns the closest cch to where the mouse point is.
*/
{
register PSTR pText;
int width = mousePt.x;
int textWidth;
ICH cch;
if (width <= ped->rcFmt.left)
{
/* Return either the first non visible character or return 0 if at
* beginning of text
*/
if (ped->screenStart)
return(ped->screenStart - 1);
else
return(0);
}
if (width > ped->rcFmt.right)
{
pText = LocalLock(ped->hText);
/* Return last char in text or one plus the last char visible */
cch = ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
ped->cch - ped->screenStart,
ped->rcFmt.right-ped->rcFmt.left) +
ped->screenStart;
LocalUnlock(ped->hText);
if (cch >= ped->cch)
return(ped->cch);
else
return(cch+1);
}
/* Check if password hidden chars are being used. */
if (ped->charPasswordChar)
return(umin((width-ped->rcFmt.left)/ped->cPasswordCharWidth,ped->cch));
if (!ped->cch)
return(0);
pText = LocalLock(ped->hText);
cch = ped->cch;
while(((textWidth =
LOWORD(GetTextExtent(hdc, (LPSTR)(pText+ped->screenStart),
cch-ped->screenStart)))
> (width-ped->rcFmt.left)) && (cch-ped->screenStart) )
{
/* For that "feel" */
if ((textWidth - ped->aveCharWidth/2) < (width-ped->rcFmt.left))
break;
cch--;
}
#ifdef FE_SB
cch = ECAdjustIch( ped, pText, cch );
#endif
LocalUnlock(ped->hText);
return(cch);
}
void NEAR PASCAL SLMouseMotionHandler(ped, message, virtKeyDown, mousePt)
register PED ped;
WORD message;
WORD virtKeyDown;
POINT mousePt;
{
LONG selection;
BOOL changeSelection = FALSE;
HDC hdc = ECGetEditDC(ped,FALSE);
ICH newMaxSel = ped->ichMaxSel;
ICH newMinSel = ped->ichMinSel;
ICH mouseIch = SLMouseToIch(ped, hdc, mousePt);
#ifdef FE_SB
LPSTR pText;
pText = LocalLock( ped->hText );
mouseIch = ECAdjustIch( ped, pText, mouseIch );
LocalUnlock( ped->hText );
#endif
switch (message)
{
case WM_LBUTTONDBLCLK:
/* Note that we don't have to worry about this control having the focus
* since it got it when the WM_LBUTTONDOWN message was first sent. If
* shift key is down, extend selection to word we double clicked on else
* clear current selection and select word.
*/
#ifdef FE_SB
pText = LocalLock( ped->hText ) + ped->ichCaret;
selection = ECWord(ped,ped->ichCaret,
(ECIsDBCSLeadByte(ped,*pText) && ped->ichCaret < ped->cch) ? FALSE : TRUE );
LocalUnlock( ped->hText );
#else
selection = ECWord(ped,ped->ichCaret,TRUE);
#endif
newMinSel = LOWORD(selection);
newMaxSel = ped->ichCaret = HIWORD(selection);
changeSelection = TRUE;
/* Set mouse down to false so that the caret isn't reposition on the
* mouseup message or on an accidental move...
*/
ped->fMouseDown = FALSE;
break;
case WM_MOUSEMOVE:
if (ped->fMouseDown)
{
changeSelection = TRUE;
/* Extend selection, move caret word right */
if ((ped->ichMinSel == ped->ichCaret) &&
(ped->ichMinSel != ped->ichMaxSel))
{
/* Reduce selection extent */
newMinSel = ped->ichCaret = mouseIch;
newMaxSel = ped->ichMaxSel;
}
else
/* Extend selection extent */
newMaxSel = ped->ichCaret=mouseIch;
}
break;
case WM_LBUTTONDOWN:
/*
* If we currently don't have the focus yet, try to get it.
*/
if (!ped->fFocus)
{
if (!ped->fNoHideSel)
/* Clear the selection before setting the focus so that we don't
* get refresh problems and flicker. Doesn't matter since the
* mouse down will end up changing it anyway.
*/
ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;
SetFocus(ped->hwnd);
/* If we are part of a combo box, then this is the first time the
* edit control is getting the focus so we just want to highlight
* the selection and we don't really want to position the caret.
*/
if (ped->listboxHwnd)
break;
}
if (ped->fFocus)
{
/* Only do this if we have the focus since a clever app may not want
* to give us the focus at the SetFocus call above.
*/
ped->fMouseDown = TRUE;
SetCapture(ped->hwnd);
changeSelection = TRUE;
if (!(virtKeyDown & MK_SHIFT))
{
/*
* If shift key isn't down, move caret to mouse point and clear
* old selection
*/
newMinSel = newMaxSel = ped->ichCaret = mouseIch;
}
else
{
/* Shiftkey is down so we want to maintain the current selection
* (if any) and just extend or reduce it
*/
if (ped->ichMinSel == ped->ichCaret)
newMinSel = ped->ichCaret = mouseIch;
else
newMaxSel = ped->ichCaret = mouseIch;
}
}
break;
case WM_LBUTTONUP:
if (ped->fMouseDown)
{
ReleaseCapture();
/*SLSetCaretPosition(ped,hdc);*/
ped->fMouseDown = FALSE;
}
break;
}
if (changeSelection)
{
SLScrollText(ped,hdc);
SLChangeSelection(ped, hdc, newMinSel, newMaxSel);
}
ECReleaseEditDC(ped,hdc,FALSE);
}
void NEAR PASCAL SLPaintHandler(ped,althdc)
register PED ped;
HDC althdc;
/* effects: Handles painting of the edit control window. Draws the border if
* necessary and draws the text in its current state.
*/
{
HWND hwnd = ped->hwnd;
HBRUSH hBrush;
register HDC hdc;
PAINTSTRUCT paintstruct;
RECT rcEdit;
HANDLE hOldFont;
/* Had to put in hide/show carets. The first one needs to be done before
* beginpaint to correctly paint the caret if part is in the update region
* and part is out. The second is for 1.03 compatibility. It breaks
* micrografix's worksheet edit control if not there.
*/
HideCaret(hwnd);
/* Allow subclassing hdc */
if (!althdc)
hdc = BeginPaint(hwnd, (PAINTSTRUCT FAR *)&paintstruct);
else
hdc = althdc;
HideCaret(hwnd);
if (!ped->fNoRedraw && IsWindowVisible(ped->hwnd))
{
/* Erase the background since we don't do it in the erasebkgnd message.
*/
hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
FillWindow(ped->hwndParent, hwnd, hdc, hBrush);
if (ped->fBorder)
{
GetClientRect(hwnd, (LPRECT)&rcEdit);
DrawFrame(hdc, (LPRECT)&rcEdit, 1, DF_WINDOWFRAME);
}
if (ped->hFont)
/* We have to select in the font since this may be a subclassed dc
* or a begin paint dc which hasn't been initialized with out fonts
* like ECGetEditDC does.
*/
hOldFont = SelectObject(hdc, ped->hFont);
SLDrawText(ped, hdc, 0);
if (ped->hFont && hOldFont)
SelectObject(hdc, hOldFont);
}
ShowCaret(hwnd);
if (!althdc)
EndPaint(hwnd, (LPPAINTSTRUCT)&paintstruct);
ShowCaret(hwnd);
}
void NEAR PASCAL SLSetFocusHandler(ped)
register PED ped;
/* effects: Gives the edit control the focus and notifies the parent
* EN_SETFOCUS.
*/
{
register HDC hdc;
if (!ped->fFocus)
{
UpdateWindow(ped->hwnd);
ped->fFocus = TRUE; /* Set focus */
/* We don't want to muck with the caret since it isn't created. */
hdc = ECGetEditDC(ped,TRUE);
/* Show the current selection. Only if the selection was hidden when we
* lost the focus, must we invert (show) it.
*/
if (!ped->fNoHideSel)
SLDrawText(ped, hdc, 0);
/* Create the caret. Add in the +1 because we have an extra pixel for
* highlighting around the text. If the font is at least as wide as the
* system font, use a wide caret else use a 1 pixel wide caret.
*/
CreateCaret(ped->hwnd, (HBITMAP)NULL,
(ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
ped->lineHeight+1);
SLSetCaretPosition(ped,hdc);
ECReleaseEditDC(ped,hdc,TRUE);
ShowCaret(ped->hwnd);
}
/* Notify parent we have the focus */
ECNotifyParent(ped, EN_SETFOCUS);
}
void NEAR PASCAL SLKillFocusHandler(ped, newFocusHwnd)
register PED ped;
HWND newFocusHwnd;
/* effects: The edit control loses the focus and notifies the parent via
* EN_KILLFOCUS.
*/
{
RECT rcEdit;
if (ped->fFocus)
{
/* Destroy the caret */
HideCaret(ped->hwnd);
DestroyCaret();
ped->fFocus = FALSE; /* Clear focus */
/* Do this only if we still have the focus. But we always notify the
* parent that we lost the focus whether or not we originally had the
* focus.
*/
/* Hide the current selection if needed */
if (!ped->fNoHideSel && (ped->ichMinSel != ped->ichMaxSel))
{
GetClientRect(ped->hwnd, (LPRECT)&rcEdit);
if (ped->fBorder && rcEdit.right-rcEdit.left &&
rcEdit.bottom-rcEdit.top)
{
/* Don't invalidate the border so that we avoid flicker */
InflateRect((LPRECT)&rcEdit, -1, -1);
}
InvalidateRect(ped->hwnd, (LPRECT)&rcEdit, FALSE);
UpdateWindow(ped->hwnd);
#if 0
SLSetSelectionHandler(ped, ped->ichCaret, ped->ichCaret);
#endif
}
}
/* If we aren't a combo box, notify parent that we lost the focus.
*/
if (!ped->listboxHwnd)
ECNotifyParent(ped, EN_KILLFOCUS);
else
{
/* This editcontrol is part of a combo box and is losing the focus. If
* the focus is NOT being sent to another control in the combo box
* window, then it means the combo box is losing the focus. So we will
* notify the combo box of this fact.
*/
if (!IsChild(ped->hwndParent, newFocusHwnd))
{
/* Focus is being sent to a window which is not a child of the combo
* box window which implies that the combo box is losing the focus.
* Send a message to the combo box informing him of this fact so
* that he can clean up...
*/
SendMessage(ped->hwndParent, CBEC_KILLCOMBOFOCUS, 0, 0L);
}
}
}
/*******************/
/* SLEditWndProc() */
/*******************/
LONG FAR PASCAL SLEditWndProc(hwnd, ped, message, wParam, lParam)
HWND hwnd;
register PED ped;
WORD message;
register WORD wParam;
LONG lParam;
/* effects: Class procedure for all single line edit controls.
Dispatches all messages to the appropriate handlers which are named
as follows:
SL (single line) prefixes all single line edit control procedures while
EC (edit control) prefixes all common handlers.
The SLEditWndProc only handles messages specific to single line edit
controls.
*/
{
/* Dispatch the various messages we can receive */
switch (message)
{
case WM_CLEAR:
/* wParam - not used
lParam - not used */
/*
* Call SLKeyDownHandler with a VK_DELETE keycode to clear the selected
* text.
*/
if (ped->ichMinSel != ped->ichMaxSel)
SLKeyDownHandler(ped, VK_DELETE, NOMODIFY);
break;
case WM_CHAR:
/* wParam - the value of the key
lParam - modifiers, repeat count etc (not used) */
if (!ped->fEatNextChar)
SLCharHandler(ped, wParam, 0);
else
ped->fEatNextChar = FALSE;
break;
case WM_CUT:
/* wParam - not used
lParam - not used */
/* Call SLKeyDownHandler with a VK_DELETE keycode to cut the selected
* text. (Delete key with shift modifier.) This is needed so that apps
* can send us WM_PASTE messages.
*/
if (ped->ichMinSel != ped->ichMaxSel)
SLKeyDownHandler(ped, VK_DELETE, SHFTDOWN);
break;
case WM_ERASEBKGND:
/* wParam - device context handle
lParam - not used */
/* We do nothing on this message and we don't want DefWndProc to do
* anything, so return 1
*/
return(1L);
break;
case WM_GETDLGCODE:
/* wParam - not used
lParam - not used */
return(DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS);
break;
case WM_KEYDOWN:
/* wParam - virt keycode of the given key
lParam - modifiers such as repeat count etc. (not used) */
SLKeyDownHandler(ped, wParam, 0);
break;
case WM_KILLFOCUS:
/* wParam - handle of the window that receives the input focus
lParam - not used */
SLKillFocusHandler(ped, (HWND)wParam);
break;
case WM_MOUSEMOVE:
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
/* wParam - contains a value that indicates which virtual keys are down
lParam - contains x and y coords of the mouse cursor */
SLMouseMotionHandler(ped, message, wParam, MAKEPOINT(lParam));
break;
case WM_CREATE:
/* wParam - handle to window being created
lParam - points to a CREATESTRUCT that contains copies of parameters
passed to the CreateWindow function. */
return(SLCreateHandler(hwnd, ped, (LPCREATESTRUCT) lParam));
break;
case WM_PAINT:
/* wParam - not used - actually sometimes used as a hdc when subclassing
lParam - not used */
SLPaintHandler(ped, wParam);
break;
case WM_PASTE:
/* wParam - not used
lParam - not used */
/* Call SLKeyDownHandler with a SHIFT VK_INSERT keycode to paste the
* clipboard into the edit control. This is needed so that apps can
* send us WM_PASTE messages.
*/
SLKeyDownHandler(ped, VK_INSERT, SHFTDOWN);
break;
case WM_SETFOCUS:
/* wParam - handle of window that loses the input focus (may be NULL)
lParam - not used */
SLSetFocusHandler(ped);
break;
case WM_SETTEXT:
/* wParam - not used
lParam - points to a null-terminated string that is used to set the
window text. */
return(SLSetTextHandler(ped, (LPSTR)lParam));
break;
case WM_SIZE:
/* wParam - defines the type of resizing fullscreen, sizeiconic,
sizenormal etc.
lParam - new width in LOWORD, new height in HIGHWORD of client area */
SLSizeHandler(ped);
return(0L);
break;
case WM_SYSKEYDOWN:
if (ped->listboxHwnd && /* Check if we are in a combo box */
(lParam & 0x20000000L)) /* Check if the alt key is down */
{
/*
* Handle Combobox support. We want alt up or down arrow to behave
* like F4 key which completes the combo box selection
*/
ped->fEatNextChar = FALSE;
if (lParam & 0x1000000)
{
/* This is an extended key such as the arrow keys not on the
* numeric keypad so just drop the combobox.
*/
if (wParam == VK_DOWN || wParam == VK_UP)
goto DropCombo;
else
goto foo;
}
if (GetKeyState(VK_NUMLOCK) < 0)
{
ped->fEatNextChar = FALSE;
/* If numlock down, just send all system keys to dwp */
goto foo;
}
else
/* Num lock is up. Eat the characters generated by the key board
* driver.
*/
ped->fEatNextChar = TRUE;
if (!(wParam == VK_DOWN || wParam == VK_UP))
goto foo;
DropCombo:
if (SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L) & 0x00000001)
{
/* Extended ui doesn't honor VK_F4. */
if (SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L))
return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 0, 0L));
else
return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 1, 0L));
}
else
return(SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L));
}
foo:
if (wParam == VK_BACK)
{
SendMessage(ped->hwnd, EM_UNDO, 0, 0L);
break;
}
goto PassToDefaultWindowProc;
break;
case EM_GETLINE:
/* wParam - line number to copy (always the first line for SL)
lParam - buffer to copy text to. FIrst word is max # of bytes to copy
*/
return(ECGetTextHandler(ped, (*(WORD FAR *)lParam), (LPSTR)lParam));
break;
case EM_LINELENGTH:
/* wParam - ignored
lParam - ignored */
return((LONG)ped->cch);
break;
case EM_SETSEL:
/* wParam - not used
lParam - starting pos in lowword ending pos in high word */
SLSetSelectionHandler(ped, LOWORD(lParam), HIWORD(lParam));
break;
case EM_REPLACESEL:
/* wParam - not used
lParam - points to a null terminated string of replacement text */
SLReplaceSelHandler(ped, (LPSTR)lParam);
break;
case WM_UNDO:
case EM_UNDO:
SLUndoHandler(ped);
break;
default:
PassToDefaultWindowProc:
return(DefWindowProc(hwnd,message,wParam,lParam));
break;
} /* switch (message) */
return(1L);
} /* SLEditWndProc */