The example in this section is taken from a simple word-processing application. It includes code that enables the user to set the position of the caret by clicking anywhere on a line of text, and to select (highlight) a line of text by double-clicking anywhere on the line.
LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)
HWND hwndMain;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
{
HDC hdc; /* handle of device context */
TEXTMETRIC tm; /* font size data */
int i, j; /* loop counters */
int cCR = 0; /* count of carriage returns */
char ch; /* character from input buffer */
static int nBegLine; /* beginning of selected line */
static int nCurrentLine = 0; /* currently selected line */
static int nLastLine = 0; /* last text line */
static int nCaretPosX = 0; /* x-coordinate of caret */
static int cch = 0; /* number of characters entered */
static int nCharWidth = 0; /* exact width of a character */
static char szHilite[128]; /* text string to highlight */
static DWORD dwCharX; /* average width of characters */
static DWORD dwLineHeight; /* line height */
static POINTS ptsCursor; /* coordinates of mouse cursor */
static COLORREF crPrevText; /* previous text color */
static COLORREF crPrevBk; /* previous background color */
static PTCHAR pchInputBuf; /* address of input buffer */
static BOOL fTextSelected = FALSE; /* text-selection flag */
switch (uMsg) {
case WM_CREATE:
/* Get the metrics of the current font. */
hdc = GetDC(hwndMain);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndMain, hdc);
/* Save the average character width and height. */
dwCharX = tm.tmAveCharWidth;
dwLineHeight = tm.tmHeight;
/* Allocate a buffer to store keyboard input. */
pchInputBuf = (LPSTR) GlobalAlloc(GPTR,
BUFSIZE * sizeof(TCHAR));
return 0;
case WM_CHAR:
switch (wParam) {
case 0x08: /* backspace */
case 0x0A: /* linefeed */
case 0x1B: /* escape */
MessageBeep(0xFFFFFFFF);
return 0;
case 0x09: /* tab */
/* Convert tabs to four consecutive spaces. */
for (i = 0; i < 4; i++)
SendMessage(hwndMain, WM_CHAR, 0x20, 0);
return 0;
case 0x0D: /* carriage return */
/*
* Record the carriage return, and position the
* caret at the beginning of the new line.
*/
pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCurrentLine += 1;
break;
default: /* displayable character */
ch = (char) wParam;
HideCaret(hwndMain);
/*
* Retrieve the character's width, and display the
* character.
*/
hdc = GetDC(hwndMain);
GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam,
&nCharWidth);
TextOut(hdc, nCaretPosX,
nCurrentLine * dwLineHeight, &ch, 1);
ReleaseDC(hwndMain, hdc);
/* Store the character in the buffer. */
pchInputBuf[cch++] = ch;
/*
* Calculate the new horizontal position of
* the caret. If the new position exceeds the
* maximum, insert a carriage return and
* reposition the caret at the beginning of
* the next line.
*/
nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwMaxCharX) {
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCurrentLine;
}
ShowCaret(hwndMain);
break;
}
SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
nLastLine = max(nLastLine, nCurrentLine);
break;
.
. /* Process other messages. */
.
case WM_LBUTTONDOWN:
/*
* If a line of text is currently highlighted, redraw
* the text to remove the highlighting.
*/
if (fTextSelected) {
hdc = GetDC(hwndMain);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
TextOut(hdc, 0, nCurrentLine * dwLineHeight,
szHilite, lstrlen(szHilite));
ReleaseDC(hwndMain, hdc);
ShowCaret(hwndMain);
fTextSelected = FALSE;
}
/* Save the current mouse-cursor coordinates. */
ptsCursor = MAKEPOINTS(lParam);
/*
* Determine which line the cursor is on, and save
* the line number. Do not allow line numbers greater
* than the number of the last line of text. The
* line number is later multiplied by the average height
* of the current font. The result is used to set the
* y-coordinate of the caret.
*/
nCurrentLine = min((int)(ptsCursor.y / dwLineHeight),
nLastLine);
/*
* Parse the text input buffer to find the first
* character in the selected line of text. Each
* line ends with a carriage return, so it is possible
* to count the carriage returns to find the selected
* line.
*/
cCR = 0;
nBegLine = 0;
if (nCurrentLine != 0) {
for (i = 0; (i < cch) &&
(cCR < nCurrentLine); i++) {
if (pchInputBuf[i] == 0x0D)
++cCR;
}
nBegLine = i;
}
/*
* Starting at the beginning of the selected line,
* measure the width of each character, summing the
* width with each character measured. Stop when the
* sum is greater than the x-coordinate of the cursor.
* The sum is used to set the x-coordinate of the caret.
*/
hdc = GetDC(hwndMain);
nCaretPosX = 0;
for (i = nBegLine;
(pchInputBuf[i] != 0x0D) && (i < cch); i++) {
ch = pchInputBuf[i];
GetCharWidth32(hdc, (int) ch, (int) ch, &nCharWidth);
if ((nCaretPosX + nCharWidth) > ptsCursor.x)
break;
else
nCaretPosX += nCharWidth;
}
ReleaseDC(hwndMain, hdc);
/* Set the caret to the user-selected position. */
SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
break;
case WM_LBUTTONDBLCLK:
/* Copy the selected line of text to a buffer. */
for (i = nBegLine, j = 0; (pchInputBuf[i] != 0x0D) &&
(i < cch); i++)
szHilite[j++] = pchInputBuf[i];
szHilite[j] = '\0';
/*
* Hide the caret, invert the background and foreground
* colors, and then redraw the selected line.
*/
HideCaret(hwndMain);
hdc = GetDC(hwndMain);
crPrevText = SetTextColor(hdc, RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc, RGB(0, 0, 0));
TextOut(hdc, 0, nCurrentLine * dwLineHeight, szHilite,
lstrlen(szHilite));
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
ReleaseDC(hwndMain, hdc);
fTextSelected = TRUE;
break;
.
. /* Process other messages. */
.
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}