|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static DWORD dwCharSet = DEFAULT_CHARSET;
static int cxChar, cyChar, cxClient, cyClient, cxBuffer, cyBuffer,
xCaret, yCaret;
static TCHAR * pBuffer = NULL;
HDC hdc;
int x, y, i;
PAINTSTRUCT ps;
TEXTMETRIC tm;
// 从WM_INPUTLANGCHANGE消息开始一直往下直到WM_SIZE消息结束,都没有break或者return语句。
// 这意味着即使程序收到的是WM_INPUTLANGCHANGE消息,它也会一直执行到WM_SIZE消息。
switch (message)
{
case WM_INPUTLANGCHANGE: // 当改变键盘布局的时候就会收到这个消息
dwCharSet = wParam; // dwCharSet里存储的是字符集ID --> DEFAULT_CHARSET。
// 给该变量重新付值的唯一可能的原因就是键盘布局变了。而且我们可以看出该消息的wParam字段里有新的字符集ID。
// fall through
case WM_CREATE:
hdc = GetDC(hwnd);
SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL)); // 默认字符集 固定字宽
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight;
DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT))); // 系统默认的是宋体
ReleaseDC(hwnd, hdc);
// fall through
case WM_SIZE:
// obtain window size in pixels
if (message == WM_SIZE)
{
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
}
// calculate window size in characters
cxBuffer = max(1, cxClient / cxChar); // cxBuffer 保存客户区中可显示字符的行数
cyBuffer = max(1, cyClient / cyChar); // cyBuffer 保存客户区中可显示字符的列数
// allocate memory for buffer and clear it
if (pBuffer != NULL)
free(pBuffer);
pBuffer = (TCHAR *)malloc(cxBuffer * cyBuffer * sizeof(TCHAR)); //根据行数和列数创建 cxBuffer * cyBuffer 个动态字符数组
// 当客户区尺寸改变或者改变了键盘布局的时候程序会释放该动态数组,然后重新分配数组
for (y = 0; y < cyBuffer; y++) // 客户区用空格填满。我们可以把空格改成其它的什么,比如: BUFFER(x, y) = 'A';
for (x = 0; x < cxBuffer; x++)
BUFFER(x, y) = ' ';
// set caret to upper left corner
xCaret = 0; // xCaret yCaret是光标的位置
yCaret = 0;
if (hwnd == GetFocus()) // 函数GetFocus返回拥有输入焦点的窗口句柄
SetCaretPos(xCaret * cxChar, yCaret * cyChar); // 光标移到客户区左上角
InvalidateRect(hwnd, NULL, TRUE); // 刷新整个客户区
return 0;
// 当我们改变了键盘布局(WM_INPUTLANGCHANGE),或是创建窗口(WM_CREATE),或是改变窗口尺寸(WM_SIZE)的时候
// 我们对窗口客户区所做的改动都会消失。窗口会变成刚开始时候的样子,也就是一大片空格。
case WM_SETFOCUS:
// create and show the caret
CreateCaret(hwnd, NULL, cxChar, cyChar); // 创建插入字符的高度和宽度
SetCaretPos(xCaret * cxChar, yCaret * cyChar); // 设置插入字符的位置
ShowCaret(hwnd); // 使插入字符可见
return 0;
case WM_KILLFOCUS:
// hide and destroy the caret
HideCaret(hwnd);
DestroyCaret();
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_HOME:
xCaret = 0;
break;
case VK_END:
xCaret = cxBuffer - 1;
break;
case VK_PRIOR:
yCaret = 0;
break;
case VK_NEXT:
yCaret = cyBuffer - 1;
break;
case VK_LEFT:
xCaret = max(xCaret - 1, 0);
break;
case VK_RIGHT:
xCaret = min(xCaret + 1, cxBuffer - 1);
break;
case VK_UP:
yCaret = max(yCaret - 1, 0);
break;
case VK_DOWN:
yCaret = min(yCaret + 1, cyBuffer - 1);
break;
case VK_DELETE: // 删除掉当前位置的字符,然后后继列左移一个单位,来填补空出来的位置。最后一列补一空格
for (x = xCaret; x < cxBuffer - 1; x++)
BUFFER(x, yCaret) = BUFFER(x + 1, yCaret);
BUFFER(cxBuffer - 1, yCaret) = ' ';
HideCaret(hwnd);
hdc = GetDC(hwnd);
SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));
TextOut(hdc, xCaret * cxChar, yCaret * cyChar, &BUFFER(xCaret, yCaret), cxBuffer - xCaret);
DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
ReleaseDC(hwnd, hdc);
ShowCaret(hwnd);
break;
}
SetCaretPos(xCaret * cxChar, yCaret * cyChar); // 改变当前光标所在位置
return 0;
case WM_CHAR:
for (i = 0; i < (int)LOWORD(lParam); i++) // LOWORD (lParam)是按键的重复次数
{
switch (wParam)
{
case '\b': // backspace
if (xCaret > 0) // 先把插入符左移一个单位,然后就是 WM_KEYDOWS 的 VK_DELETE部分了
{
xCaret--;
SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1);
}
break;
case '\t': // tab 按下 tab 键后插入符可能的位置是:(i*8,0)
do
{
SendMessage(hwnd, WM_CHAR, ' ', 1); // 执行WM_CHAR的default部分
} while (xCaret % 8 != 0); // SendMessage()传递的是一个空格,
break; // 所以 yCaret 行 xCaret 列的内容变成了空格。然后用TextOut()把变化后的内容显示出来
case '\n': // line feed意思就是将光标位置往下挪一行,对应++yCaret
if (++yCaret == cyBuffer) // 但如果已经挪到最下面一行的话yCaret == cyBuffer,就挪到最上面一行
yCaret = 0;
break;
case '\r': // carriage return
xCaret = 0; // 将光标挪到最左边
if (++yCaret == cyBuffer) // 同'\n'功能相同
yCaret = 0;
break;
case '\x1B': // escape对应键盘Esc键,功能是将光标挪到最左上角,并将以前输入的字符全部擦除
for (y = 0; y < cyBuffer; y++)
for (x = 0; x < cxBuffer; x++)
BUFFER(x, y) = ' ';
xCaret = 0;
yCaret = 0;
InvalidateRect(hwnd, NULL, FALSE);
break;
default: // character codes
BUFFER(xCaret, yCaret) = (TCHAR)wParam;
HideCaret(hwnd);
hdc = GetDC(hwnd);
SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));
TextOut(hdc, xCaret * cxChar, yCaret * cyChar, &BUFFER(xCaret, yCaret), 1);
DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
ReleaseDC(hwnd, hdc);
ShowCaret(hwnd);
if (++xCaret == cxBuffer) // 每改变一个字符位,插入符前进一位 如果移动到行的末尾(客户区的最右边)
{
xCaret = 0; // 将光标挪到行首
if (++yCaret == cyBuffer) // 如果已经挪到最下面一行的话yCaret == cyBuffer,就挪到最上面一行(0,0)位置
yCaret = 0;
}
break;
}
}
SetCaretPos(xCaret * cxChar, yCaret * cyChar);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));
for (y = 0; y < cyBuffer; y++)
TextOut(hdc, 0, y * cyChar, &BUFFER(0, y), cxBuffer);
DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
|
评分
-
查看全部评分
|