Windows 程序设计 第6章

Windows 程序设计 第6章 键盘

sysmets.h 定义显示的文本

#pragma once
#include <Windows.h>
#define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))

struct
{
	int    Index;
	TCHAR    * szLabel;
	TCHAR    * szDesc;
}
sysmetrics[] =
{
	{ SM_CXSCREEN,TEXT("SM_CXSCREEN"),TEXT("Screen width in pixels") },
	{ SM_CYSCREEN,TEXT("SM_CYSCREEN"),TEXT("Screen height in pixels") },
	{ SM_CXVSCROLL,TEXT("SM_CXVSCROLL"),TEXT("Vertical scroll width") },
	{ SM_CYHSCROLL,TEXT("SM_CYHSCROLL"),TEXT("Horizontal scroll height") },
	{ SM_CYCAPTION,TEXT("SM_CYCAPTION"),TEXT("Caption bar height") },
	{ SM_CXBORDER,TEXT("SM_CXBORDER"),TEXT("Window border width") },
	{ SM_CYBORDER,TEXT("SM_CYBORDER"),TEXT("Window border height") },
	{ SM_CXFIXEDFRAME,TEXT("SM_CXFIXEDFRAME"),TEXT("Dialog window frame width") },
	{ SM_CYFIXEDFRAME,TEXT("SM_CYFIXEDFRAME"),TEXT("Dialog window frame height") },
	{ SM_CYVTHUMB,TEXT("SM_CYVTHUMB"),TEXT("Vertical scroll thumb height") },
	{ SM_CXHTHUMB,TEXT("SM_CXHTHUMB"),TEXT("Horizontal scroll thumb width") },
	{ SM_CXICON,TEXT("SM_CXICON"),TEXT("Icon width") },
	{ SM_CYICON,TEXT("SM_CYICON"),TEXT("Icon height") },
	{ SM_CXCURSOR,TEXT("SM_CXCURSOR"),TEXT("Cursor width") },
	{ SM_CYCURSOR,TEXT("SM_CYCURSOR"),TEXT("Cursor height") },
	{ SM_CYMENU,TEXT("SM_CYMENU"),TEXT("Menu bar height") },
	{ SM_CXFULLSCREEN,TEXT("SM_CXFULLSCREEN"),TEXT("Full screen client area width") },
	{ SM_CYFULLSCREEN,TEXT("SM_CYFULLSCREEN"),TEXT("Full screen client area height") },
	{ SM_CYKANJIWINDOW,TEXT("SM_CYKANJIWINDOW"),TEXT("Kanji window height") },
	{ SM_MOUSEPRESENT,TEXT("SM_MOUSEPRESENT"),TEXT("Mouse present flag") },
	{ SM_CYVSCROLL,TEXT("SM_CYVSCROLL"),TEXT("Vertical scroll arrow height") },
	{ SM_CXHSCROLL,TEXT("SM_CXHSCROLL"),TEXT("Horizontal scroll arrow width") },
	{ SM_DEBUG,TEXT("SM_DEBUG"),TEXT("Debug version flag") },
	{ SM_SWAPBUTTON,TEXT("SM_SWAPBUTTON"),TEXT("Mouse buttons swapped flag") },
	{ SM_CXMIN,TEXT("SM_CXMIN"),TEXT("Minimum window width") },
	{ SM_CYMIN,TEXT("SM_CYMIN"),TEXT("Minimum window height") },
	{ SM_CXSIZE,TEXT("SM_CXSIZE"),TEXT("Min/Max/Close button width") },
	{ SM_CYSIZE,TEXT("SM_CYSIZE"),TEXT("Min/Max/Close button height") },
	{ SM_CXSIZEFRAME,TEXT("SM_CXSIZEFRAME"),TEXT("Window sizing frame width") },
	{ SM_CYSIZEFRAME,TEXT("SM_CYSIZEFRAME"),TEXT("Window sizing frame height") },
	{ SM_CXMINTRACK,TEXT("SM_CXMINTRACK"),TEXT("Minimum window tracking width") },
	{ SM_CYMINTRACK,TEXT("SM_CYMINTRACK"),TEXT("Minimum window tracking height") },
	{ SM_CXDOUBLECLK,TEXT("SM_CXDOUBLECLK"),TEXT("Double click x tolerance") },
	{ SM_CYDOUBLECLK,TEXT("SM_CYDOUBLECLK"),TEXT("Double click y tolerance") },
	{ SM_CXICONSPACING,TEXT("SM_CXICONSPACING"),TEXT("Horizontal icon spacing") },
	{ SM_CYICONSPACING,TEXT("SM_CYICONSPACING"),TEXT("Vertical icon spacing") },
	{ SM_MENUDROPALIGNMENT,TEXT("SM_MENUDROPALIGNMENT"),TEXT("Left or right menu drop") },
	{ SM_PENWINDOWS,TEXT("SM_PENWINDOWS"),TEXT("Pen extensions installed") },
	{ SM_DBCSENABLED,TEXT("SM_DBCSENABLED"),TEXT("Double-Byte Char Set enabled") },
	{ SM_CMOUSEBUTTONS,TEXT("SM_CMOUSEBUTTONS"),TEXT("Number of mouse buttons") },
	{ SM_SECURE,TEXT("SM_SECURE"),TEXT("Security present flag") },
	{ SM_CXEDGE,TEXT("SM_CXEDGE"),TEXT("3-D border width") },
	{ SM_CYEDGE,TEXT("SM_CYEDGE"),TEXT("3-D border height") },
	{ SM_CXMINSPACING,TEXT("SM_CXMINSPACING"),TEXT("Minimized window spacing width") },
	{ SM_CYMINSPACING,TEXT("SM_CYMINSPACING"),TEXT("Minimized window spacing height") },
	{ SM_CXSMICON,TEXT("SM_CXSMICON"),TEXT("Small icon width") },
	{ SM_CYSMICON,TEXT("SM_CYSMICON"),TEXT("Small icon height") },
	{ SM_CYSMCAPTION,TEXT("SM_CYSMCAPTION"),TEXT("Small caption height") },
	{ SM_CXSMSIZE,TEXT("SM_CXSMSIZE"),TEXT("Small caption button width") },
	{ SM_CYSMSIZE,TEXT("SM_CYSMSIZE"),TEXT("Small caption button height") },
	{ SM_CXMENUSIZE,TEXT("SM_CXMENUSIZE"),TEXT("Menu bar button width") },
	{ SM_CYMENUSIZE,TEXT("SM_CYMENUSIZE"),TEXT("Menu bar button height") },
	{ SM_ARRANGE,TEXT("SM_ARRANGE"),TEXT("How minimized windows arranged") },
	{ SM_CXMINIMIZED,TEXT("SM_CXMINIMIZED"),TEXT("Minimized window width") },
	{ SM_CYMINIMIZED,TEXT("SM_CYMINIMIZED"),TEXT("Minimized window height") },
	{ SM_CXMAXTRACK,TEXT("SM_CXMAXTRACK"),TEXT("Maximum draggable width") },
	{ SM_CYMAXTRACK,TEXT("SM_CYMAXTRACK"),TEXT("Maximum draggable height") },
	{ SM_CXMAXIMIZED,TEXT("SM_CXMAXIMIZED"),TEXT("Width of maximized window") },
	{ SM_CYMAXIMIZED,TEXT("SM_CYMAXIMIZED"),TEXT("Height of maximized window") },
	{ SM_NETWORK,TEXT("SM_NETWORK"),TEXT("Network present flag") },
	{ SM_CLEANBOOT,TEXT("SM_CLEANBOOT"),TEXT("How system was booted") },
	{ SM_CXDRAG,TEXT("SM_CXDRAG"),TEXT("Avoid drag x tolerance") },
	{ SM_CYDRAG,TEXT("SM_CYDRAG"),TEXT("Avoid drag y tolerance") },
	{ SM_SHOWSOUNDS,TEXT("SM_SHOWSOUNDS"),TEXT("Present sounds visually") },
	{ SM_CXMENUCHECK,TEXT("SM_CXMENUCHECK"),TEXT("Menu check-mark width") },
	{ SM_CYMENUCHECK,TEXT("SM_CYMENUCHECK"),TEXT("Menu check-mark height") },
	{ SM_SLOWMACHINE,TEXT("SM_SLOWMACHINE"),TEXT("Slow processor flag") },
	{ SM_MIDEASTENABLED,TEXT("SM_MIDEASTENABLED"),TEXT("Hebrew and Arabic enabled flag") },
	{ SM_MOUSEWHEELPRESENT,TEXT("SM_MOUSEWHEELPRESENT"),TEXT("Mouse wheel present flag") },
	{ SM_XVIRTUALSCREEN,TEXT("SM_XVIRTUALSCREEN"),TEXT("Virtual screen x origin") },
	{ SM_YVIRTUALSCREEN,TEXT("SM_YVIRTUALSCREEN"),TEXT("Virtual screen y origin") },
	{ SM_CXVIRTUALSCREEN,TEXT("SM_CXVIRTUALSCREEN"),TEXT("Virtual screen width") },
	{ SM_CYVIRTUALSCREEN,TEXT("SM_CYVIRTUALSCREEN"),TEXT("Virtual screen height") },
	{ SM_CMONITORS,TEXT("SM_CMONITORS"),TEXT("Number of monitors") },
	{ SM_SAMEDISPLAYFORMAT,TEXT("SM_SAMEDISPLAYFORMAT"),TEXT("Same color format flag") },
};

SYSMTES4.cpp 代码 键盘控制上下左右

#include <windows.h>
#include "sysmets.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("SysMets4");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon  = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor  = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("Program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, TEXT("Get System Metrics No. 4"),
		WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth;
	HDC hdc;
	int i, x, y, iVertPos, iHorzPos, iPaintBeg, iPaintEnd;
	PAINTSTRUCT ps;
	SCROLLINFO si;
	TCHAR szBuffer[10];
	TEXTMETRIC tm;

	switch (message)
	{
	case WM_CREATE:

		//获取字体信息
		hdc = GetDC(hwnd);

		GetTextMetrics(hdc, &tm);
		cxChar = tm.tmAveCharWidth;
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
		cyChar = tm.tmHeight + tm.tmExternalLeading;

		ReleaseDC(hwnd, hdc);

		// 保存三列的宽度

		iMaxWidth = 40 * cxChar + 22 * cxCaps;
		return 0;

	case WM_SIZE:

		//获取客户区大小以及设置滚动条
		cxClient = LOWORD(lParam);
		cyClient = HIWORD(lParam);

		// 设置垂直滚动条范围和页面大小

		si.cbSize = sizeof(si);
		si.fMask = SIF_RANGE | SIF_PAGE;
		si.nMin = 0;
		si.nMax = NUMLINES - 1;
		si.nPage = cyClient / cyChar;
		SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

		// 设置水平滚动条范围和页面大小

		si.cbSize = sizeof(si);
		si.fMask = SIF_RANGE | SIF_PAGE;
		si.nMin = 0;
		si.nMax = 2 + iMaxWidth / cxChar;
		si.nPage = cxClient / cxChar;
		SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
		return 0;

	case WM_VSCROLL:
		// 处理垂直滚动条消息   

		si.cbSize = sizeof(si);
		si.fMask = SIF_ALL;
		GetScrollInfo(hwnd, SB_VERT, &si);

		// 保存位置以便以后比较

		iVertPos = si.nPos;

		switch (LOWORD(wParam))
		{
		case SB_TOP:
			si.nPos = si.nMin;
			break;

		case SB_BOTTOM:
			si.nPos = si.nMax;
			break;

		case SB_LINEUP:
			si.nPos -= 1;
			break;

		case SB_LINEDOWN:
			si.nPos += 1;
			break;

		case SB_PAGEUP:
			si.nPos -= si.nPage;
			break;

		case SB_PAGEDOWN:
			si.nPos += si.nPage;
			break;

		case SB_THUMBTRACK:
			si.nPos = si.nTrackPos;
			break;

		default:
			break;
		}
		// 设置位置,然后检索。  由于调整
		//   在Windows中,它可能与值集不相同。

		si.fMask = SIF_POS;
		SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
		GetScrollInfo(hwnd, SB_VERT, &si);

		// 如果位置已更改,请滚动窗口并进行更新

		if (si.nPos != iVertPos)
		{
			ScrollWindow(hwnd, 0, cyChar * (iVertPos - si.nPos),
				NULL, NULL);
			UpdateWindow(hwnd);
		}
		return 0;

	case WM_HSCROLL:
		// 处理水平滚动条消息

		si.cbSize = sizeof(si);
		si.fMask = SIF_ALL;

		// 保存位置以供以后进行比较

		GetScrollInfo(hwnd, SB_HORZ, &si);
		iHorzPos = si.nPos;

		switch (LOWORD(wParam))
		{
		case SB_LINELEFT:
			si.nPos -= 1;
			break;

		case SB_LINERIGHT:
			si.nPos += 1;
			break;

		case SB_PAGELEFT:
			si.nPos -= si.nPage;
			break;

		case SB_PAGERIGHT:
			si.nPos += si.nPage;
			break;

		case SB_THUMBPOSITION:
			si.nPos = si.nTrackPos;
			break;

		default:
			break;
		}
		// 设置位置,然后检索。  由于调整
		//   在Windows中,它可能与值集不相同。

		si.fMask = SIF_POS;
		SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
		GetScrollInfo(hwnd, SB_HORZ, &si);

		// 如果位置已更改,请滚动窗口并进行更新

		if (si.nPos != iHorzPos)
		{
			ScrollWindow(hwnd, cxChar * (iHorzPos - si.nPos), 0,
				NULL, NULL);
		}
		return 0;

	case WM_KEYDOWN:
		switch (wParam)//指明了虚拟键码
		{
		case VK_HOME://SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0); //不进入队列,直接发送给窗口
			break;
		case VK_END: //尾
			SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0);
			break;
		case VK_PRIOR: //上一页
			SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
			break;
		case VK_NEXT: //下一页

			SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
			break;
		case VK_UP: //上一行

			SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
			break;
		case VK_DOWN://下一页
			SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
			break;
		case VK_LEFT: //水平前一页
			SendMessage(hwnd, WM_HSCROLL, SB_PAGEUP, 0);
			break;
		case VK_RIGHT://水平后一页
			SendMessage(hwnd, WM_HSCROLL, SB_PAGEDOWN, 0);
			break;
		}

		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		// 获取垂直滚动条位置

		si.cbSize = sizeof(si);
		si.fMask = SIF_POS;
		GetScrollInfo(hwnd, SB_VERT, &si);
		iVertPos = si.nPos;

		// 获取水平滚动条位置

		GetScrollInfo(hwnd, SB_HORZ, &si);
		iHorzPos = si.nPos;

		// 寻找绘画极限

		iPaintBeg = max(0, iVertPos + ps.rcPaint.top / cyChar);
		iPaintEnd = min(NUMLINES - 1,
			iVertPos + ps.rcPaint.bottom / cyChar);

		for (i = iPaintBeg; i <= iPaintEnd; i++)
		{
			x = cxChar * (1 - iHorzPos);
			y = cyChar * (i - iVertPos);

			TextOut(hdc, x, y,
				sysmetrics[i].szLabel,
				lstrlen(sysmetrics[i].szLabel));

			TextOut(hdc, x + 22 * cxCaps, y,
				sysmetrics[i].szDesc,
				lstrlen(sysmetrics[i].szDesc));

			SetTextAlign(hdc, TA_RIGHT | TA_TOP);

			TextOut(hdc, x + 22 * cxCaps + 40 * cxChar, y,szBuffer,
				wsprintf(szBuffer, TEXT("%5d"),
					GetSystemMetrics(sysmetrics[i].Index)));

			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

KEYVIEW1.cpp 代码 键盘上按下就会显示

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("KeyView1");
	HWND  hwnd;
	MSG  msg;
	WNDCLASS  wndclass;

	wndclass.style  = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc  = WndProc;
	wndclass.cbClsExtra  = 0;
	wndclass.cbWndExtra  = 0;
	wndclass.hInstance  = hInstance;
	wndclass.hIcon  = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor  = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, TEXT("Keyboard Message Viewer #1"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}



LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int  cxClientMax, cyClientMax, cxClient, cyClient, cxChar, cyChar;
	static int  cLinesMax, cLines;
	static PMSG  pmsg;
	static RECT  rectScroll;
	static TCHAR szTop[] = TEXT("Message        Key       Char     ")
		TEXT("Repeat Scan Ext ALT Prev Tran ");
	static TCHAR szUnd[] = TEXT("_______        ___       ____      ")
		TEXT("______ ____ ___ ___ ____ ____ ");

	static TCHAR * szFormat[2] = {
		TEXT("%-13s %3d %-15s%c%6u %4d %3s %3s %4s %4s "),
		TEXT("%-13s            0x%04X%1s%c %6u %4d %3s %3s %4s %4s ") };

	static TCHAR * szYes  = TEXT("Yes ");
	static TCHAR * szNo  = TEXT("No ");
	static TCHAR * szDown = TEXT("Down ");
	static TCHAR * szUp  = TEXT("Up ");

	static TCHAR * szMessage[] = {
		TEXT("WM_KEYDOWN "), TEXT("WM_KEYUP "),
		TEXT("WM_CHAR "), TEXT("WM_DEADCHAR "),
		TEXT("WM_SYSKEYDOWN "), TEXT("WM_SYSKEYUP "),
		TEXT("WM_SYSCHAR "), TEXT("WM_SYSDEADCHAR ") };
	HDC  hdc;
	int	 i, iType;
	PAINTSTRUCT	 ps;
	TCHAR	 szBuffer[128], szKeyName[32];
	TEXTMETRIC	 tm;

	switch (message)
	{
	case WM_CREATE:
	case WM_DISPLAYCHANGE:

		//获取客户端区域的最大大小

		cxClientMax = GetSystemMetrics(SM_CXMAXIMIZED);
		cyClientMax = GetSystemMetrics(SM_CYMAXIMIZED);



		// 获取固定间距字体的字符大小

		hdc = GetDC(hwnd);

		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
		GetTextMetrics(hdc, &tm);
		cxChar = tm.tmAveCharWidth;
		cyChar = tm.tmHeight;

		ReleaseDC(hwnd, hdc);



		// 为显示行分配内存

		if (pmsg)
			free(pmsg);

		cLinesMax = cyClientMax / cyChar;	 //窗口最大化时显示字符行
		pmsg = (PMSG)malloc(cLinesMax * sizeof(MSG));
		cLines = 0;
		// fall through  连续执行下面一个标签
	case WM_SIZE:
		if (message == WM_SIZE)
		{
			cxClient = LOWORD(lParam);
			cyClient = HIWORD(lParam);
		}


		// 计算滚动矩形

		rectScroll.left   = 0;
		rectScroll.right  = cxClient;
		rectScroll.top  = cyChar;
		rectScroll.bottom = cyChar * (cyClient / cyChar);  // 取(cyClient / cyChar)整数



		InvalidateRect(hwnd, NULL, TRUE);
		return 0;

	case WM_KEYDOWN:
	case WM_KEYUP:
	case WM_CHAR:
	case WM_DEADCHAR:
	case WM_SYSKEYDOWN:
	case WM_SYSKEYUP:
	case WM_SYSCHAR:
	case WM_SYSDEADCHAR:
		// 重新排列存储阵列
		for (i = cLinesMax - 1; i > 0; i--)
		{
			// 丢弃最后一个结构中的数据,预留第一个结构。
			// 可以这样理解,把全部结构数据向后顺移一位。
			pmsg[i] = pmsg[i - 1];
		}

		// 存储新消息

		pmsg[0].hwnd = hwnd;
		pmsg[0].message = message;
		pmsg[0].wParam = wParam;
		pmsg[0].lParam = lParam;

		//有按键消息来时,cLines加1,最大不超过窗口最大化时显示字符行
		cLines = min(cLines + 1, cLinesMax);
		// 向上滚动显示屏
		ScrollWindow(hwnd, 0, -cyChar, &rectScroll, &rectScroll);

		break;// 例如,调用DefWindowProc以便系统消息工作

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));


		//因为两个字符串绘画坐标一样,必须设定透明模式以防止第二个字符串擦除第一个字符串
		SetBkMode(hdc, TRANSPARENT);
		TextOut(hdc, 0, 0, szTop, lstrlen(szTop));
		TextOut(hdc, 0, 0, szUnd, lstrlen(szUnd));



		for (i = 0; i < min(cLines, cyClient / cyChar - 1); i++)
		{

			//如果是字符消息则标记 1 ,如果是按键消息则标记 0
			iType = pmsg[i].message == WM_CHAR ||
				pmsg[i].message == WM_SYSCHAR ||
				pmsg[i].message == WM_DEADCHAR ||
				pmsg[i].message == WM_SYSDEADCHAR;


			GetKeyNameText(pmsg[i].lParam, szKeyName, sizeof(szKeyName) / sizeof(TCHAR));

			TextOut(hdc, 0, (cyClient / cyChar - 1 - i) * cyChar, szBuffer, wsprintf(szBuffer, szFormat[iType],

				//计算得出消息类型,并索引。
				szMessage[pmsg[i].message - WM_KEYFIRST],

				//如果是按键消息就输出虚拟键代码,显示为十进制有符号整数,宽度为3个字符。
				//如果是字符消息就输出ANSI或Unicode字符代码,显示为大写十六进制数,宽度为4个字符,空白处用 0 填充。
				pmsg[i].wParam,

				//如果是按键消息就输出键名(szKeyName),并采用左对齐,宽度为15个字符。
				//如果是字符消息就输出空格,宽度为1个字符。
				(PTSTR)(iType ? TEXT(" ") : szKeyName),

				// 如果是按键消息就输出空格。
				// 如果是字符消息就输出该字符。pmsg[i].wParam = wParam (字符的对应编码,使用强制类型转换得到相应字符)
				(TCHAR)(iType ? pmsg[i].wParam : ' '),

				//低十六位记录着按键的重复计数次数。用十进制方式显示为无符号整数,宽度为6个字符。
				LOWORD(pmsg[i].lParam),

				//取高十六位中的低八位,解释为键盘扫描码(OEM),显示为十进制有符号整数,宽度为4个字符。
				HIWORD(pmsg[i].lParam) & 0xFF,

				// 0000 0001 0000 0000 0000 0000 0000 0000 读取 扩充键旗标(Extended Key Flag) 状态。
				0x01000000 & pmsg[i].lParam ? szYes  : szNo,

				// 0010 0000 0000 0000 0000 0000 0000 0000 读取 内容代码(Context Code) 状态。
				0x20000000 & pmsg[i].lParam ? szYes  : szNo,

				// 0100 0000 0000 0000 0000 0000 0000 0000 读取 键的先前状态(Previous Key State)
				0x40000000 & pmsg[i].lParam ? szDown : szUp,

				// 1000 0000 0000 0000 0000 0000 0000 0000 读取 转换状态(Transition State)
				0x80000000 & pmsg[i].lParam ? szUp  : szDown));
		}
		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

结果显示
在这里插入图片描述
STOKFONT.cpp 代码

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("StokFont");
	HWND  hwnd;
	MSG  msg;
	WNDCLASS  wndclass;

	wndclass.style  = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc     = WndProc;
	wndclass.cbClsExtra  = 0;
	wndclass.cbWndExtra  = 0;
	wndclass.hInstance  = hInstance;
	wndclass.hIcon  = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor  = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("Program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, TEXT("Stock Fonts"),
		WS_OVERLAPPEDWINDOW | WS_VSCROLL,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	//该结构体保存系统各种字体信息
	static struct
	{
		int  idStockFont;
		TCHAR * szStockFont;
	}
	stockfont[] = { OEM_FIXED_FONT, TEXT("OEM_FIXED_FONT"),
		ANSI_FIXED_FONT, TEXT("ANSI_FIXED_FONT"),
		ANSI_VAR_FONT, TEXT("ANSI_VAR_FONT"),
		SYSTEM_FONT, TEXT("SYSTEM_FONT"),
		DEVICE_DEFAULT_FONT, TEXT("DEVICE_DEFAULT_FONT"),
		SYSTEM_FIXED_FONT, TEXT("SYSTEM_FIXED_FONT"),
		DEFAULT_GUI_FONT, TEXT("DEFAULT_GUI_FONT") };

	static int iFont, cFonts = sizeof stockfont / sizeof stockfont[0];
	HDC  hdc;
	int  i, x, y, cxGrid, cyGrid;
	PAINTSTRUCT ps;
	TCHAR  szFaceName[LF_FACESIZE], szBuffer[LF_FACESIZE + 64];
	TEXTMETRIC  tm;

	switch (message)
	{
	case WM_CREATE:
		SetScrollRange(hwnd, SB_VERT, 0, cFonts - 1, TRUE);//设置滚动条范围
		return 0;

	case WM_DISPLAYCHANGE:
		InvalidateRect(hwnd, NULL, TRUE);
		return 0;

	case WM_VSCROLL:

		//处理滚动条消息
		switch (LOWORD(wParam))
		{
		case SB_TOP: iFont = 0; break;
		case SB_BOTTOM: iFont = cFonts - 1; break;
		case SB_LINEUP:
		case SB_PAGEUP: iFont -= 1; break;
		case SB_LINEDOWN:
		case SB_PAGEDOWN: iFont += 1; break;
		case SB_THUMBPOSITION: iFont = HIWORD(wParam);  break;
		}
		iFont = max(0, min(cFonts - 1, iFont));
		SetScrollPos(hwnd, SB_VERT, iFont, TRUE);
		InvalidateRect(hwnd, NULL, TRUE);
		return 0;

	case WM_KEYDOWN:

		//处理按钮消息时,直接把消息发给滚动条
		switch (wParam)
		{
		case VK_HOME: SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0); break;
		case VK_END: SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0); break;
		case VK_PRIOR:
		case VK_LEFT:
		case VK_UP: SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); break;
		case VK_NEXT:
		case VK_RIGHT:
		case VK_DOWN: SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); break;
		}
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		SelectObject(hdc, GetStockObject(stockfont[iFont].idStockFont));//把第一种字体装入设备描述表
		GetTextFace(hdc, LF_FACESIZE, szFaceName); //获得结构体第一个成员对应的字体名称,保存在szFaceName中

												   //获取字体大小信息
		GetTextMetrics(hdc, &tm);
		cxGrid = max(3 * tm.tmAveCharWidth, 2 * tm.tmMaxCharWidth);
		cyGrid = tm.tmHeight + 3;

		//输出标题栏

		TextOut(hdc, 0, 0, szBuffer,
			wsprintf(szBuffer, TEXT(" %s: Face Name = %s, CharSet = %i"),
				stockfont[iFont].szStockFont, //字体标示符
				szFaceName, tm.tmCharSet));//字体名称

		SetTextAlign(hdc, TA_TOP | TA_CENTER);



		for (i = 0; i < 17; i++)
		{

			// 画垂直线
				MoveToEx(hdc, (i + 2) * cxGrid, 2 * cyGrid, NULL);
			LineTo (hdc, (i + 2) * cxGrid, 19 * cyGrid);

			//水平线

			MoveToEx(hdc, cxGrid, (i + 3) * cyGrid, NULL);
			LineTo (hdc, 18 * cxGrid, (i + 3) * cyGrid);
		}




		for (i = 0; i < 16; i++)
		{

			//行标 0 -- F
			TextOut(hdc, (2 * i + 5) * cxGrid / 2, 2 * cyGrid + 2, szBuffer,
				wsprintf(szBuffer, TEXT("%X-"), i));

			//列标题0 -- F

			TextOut(hdc, 3 * cxGrid / 2, (i + 3) * cyGrid + 2, szBuffer,
				wsprintf(szBuffer, TEXT("-%X"), i));
		}
		// 输出各种字体的字符集

		for (y = 0; y < 16; y++)
			for (x = 0; x < 16; x++)
			{
				TextOut(hdc, (2 * x + 5) * cxGrid / 2,
					(y + 3) * cyGrid + 2, szBuffer,
					wsprintf(szBuffer, TEXT("%c"), 16 * x + y));
			}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

显示结果
在这里插入图片描述

KEYVIEW2.cpp 代码 键盘输入字符

#include<windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static DWORD dwCharSet = DEFAULT_CHARSET;          //字符集
	static int cxClientMax, cyClientMax, cxClient, cyClient, cxChar, cyChar;
	static int cLinesMax, cLines;
	static PMSG pmsg;
	static RECT rectScroll;
	static TCHAR szTop[] = TEXT("Message        Key       Char     ")
		TEXT("Repeat Scan Ext ALT Prev Tran");
	static TCHAR szUnd[] = TEXT("_______        ___       ____     ")
		TEXT("______ ____ ___ ___ ____ ____");

	static TCHAR * szFormat[2] = {

		TEXT("%-13s %3d %-15s%c%6u %4d %3s %3s %4s %4s"),
		TEXT("%-13s            0x%04X%1s%c %6u %4d %3s %3s %4s %4s") };
	static TCHAR * szYes = TEXT("Yes");
	static TCHAR * szNo = TEXT("No");
	static TCHAR * szDown = TEXT("Down");
	static TCHAR * szUp = TEXT("Up");

	static TCHAR * szMessage[] = {
		TEXT("WM_KEYDOWN"),    TEXT("WM_KEYUP"),
		TEXT("WM_CHAR"),       TEXT("WM_DEADCHAR"),
		TEXT("WM_SYSKEYDOWN"), TEXT("WM_SYSKEYUP"),
		TEXT("WM_SYSCHAR"),    TEXT("WM_SYSDEADCHAR")
	};
	HDC hdc;
	int i, itype;
	PAINTSTRUCT ps;
	TEXTMETRIC tm;
	TCHAR szBuffer[128], szKeyName[32];

	switch (message)
	{
	case WM_INPUTLANGCHANGE://表示输入法发生了改变,wparam:该输入法使用的字符集,lparam:该输入法的键盘布局
		dwCharSet = wParam;
	case WM_CREATE:
	case WM_DISPLAYCHANGE://表示显示器分辨率发生了改变,wparam:色深,像素位数,lparam:高低位分别对应垂直和水平分辨率
		cxClientMax = GetSystemMetrics(SM_CXMAXIMIZED);
		cyClientMax = GetSystemMetrics(SM_CYMAXIMIZED);
		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);
		if (pmsg)
			free(pmsg);
		cLinesMax = cyClientMax / cyChar;
		pmsg = (PMSG)malloc(cLinesMax * sizeof(MSG));
		cLines = 0;
	case WM_SIZE:
		if (message == WM_SIZE)
		{
			cxClient = LOWORD(lParam);
			cyClient = HIWORD(lParam);
		}
		rectScroll.left = 0;
		rectScroll.right = cxClient;
		rectScroll.top = cyChar;
		rectScroll.bottom = cyChar*(cyClient / cyChar);
		InvalidateRect(hwnd, NULL, true);
		if (message == WM_INPUTLANGCHANGE)
			return true;
		return 0;
	case WM_KEYDOWN:
	case WM_KEYUP:
	case WM_CHAR:
	case WM_DEADCHAR:
	case WM_SYSKEYDOWN:
	case WM_SYSKEYUP:
	case WM_SYSCHAR:
	case WM_SYSDEADCHAR:
		for (i = cLinesMax - 1; i>0; i--)
		{
			pmsg[i] = pmsg[i - 1];
		}
		pmsg[0].hwnd = hwnd;
		pmsg[0].message = message;
		pmsg[0].wParam = wParam;
		pmsg[0].lParam = lParam;
		cLines = min(cLines + 1, cLinesMax);
		ScrollWindow(hwnd, 0, -cyChar, &rectScroll, &rectScroll);    //将窗口向下滑动一行
		break;
	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));
		SetBkMode(hdc, TRANSPARENT);
		TextOut(hdc, 0, 0, szTop, lstrlen(szTop));
		TextOut(hdc, 0, 0, szUnd, lstrlen(szUnd));
		for (i = 0; i<min(cLines, cyClient / cyChar - 1); i++)
		{
			itype = pmsg[i].message == WM_CHAR ||
				pmsg[i].message == WM_SYSCHAR ||
				pmsg[i].message == WM_DEADCHAR ||
				pmsg[i].message == WM_SYSDEADCHAR;
			GetKeyNameText(pmsg[i].lParam, szKeyName, sizeof(szKeyName) / sizeof(TCHAR));//该函数检取表示键名的字符串。

			TextOut(hdc, 0, (cyClient / cyChar - 1 - i) * cyChar, szBuffer,
				wsprintf(szBuffer, szFormat[itype],
					szMessage[pmsg[i].message - WM_KEYFIRST],
					pmsg[i].wParam,
					(PTSTR)(itype ? TEXT(" ") : szKeyName),
					(TCHAR)(itype ? pmsg[i].wParam : ' '),
					LOWORD(pmsg[i].lParam),
					HIWORD(pmsg[i].lParam) & 0xFF,
					0x01000000 & pmsg[i].lParam ? szYes : szNo,
					0x20000000 & pmsg[i].lParam ? szYes : szNo,
					0x40000000 & pmsg[i].lParam ? szDown : szUp,
					0x80000000 & pmsg[i].lParam ? szUp : szDown));
		}
		DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
		EndPaint(hwnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

int WINAPI WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd)
{
	static TCHAR szAppName[] = TEXT("KEYVIEW2");
	HWND hwnd;
	WNDCLASS wndclass;
	MSG msg;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hInstance = hInstance;
	wndclass.lpfnWndProc = WndProc;
	wndclass.lpszClassName = szAppName;
	wndclass.lpszMenuName = NULL;
	wndclass.style = CS_VREDRAW | CS_HREDRAW;
	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("注册类信息发生错误"), szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, TEXT("JUST A EXAMPLE"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT
		, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, nShowCmd);
	UpdateWindow(hwnd);
	while (GetMessage(&msg, hwnd, NULL, NULL))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

显示结果
在这里插入图片描述
TYPER.cpp 代码 光标输入字符

#include <windows.h>

#define BUFFER(x,y) *(pBuffer + y * cxBuffer + x)    //定义了一个缓冲区,要访问缓冲区的内容,需要知道行和列的位置,才能访问具体某个位置的内容

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("Typer");
	HWND         hwnd;
	MSG          msg;
	WNDCLASS     wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, TEXT("Typing Program"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

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;

	switch (message)
	{
	case WM_INPUTLANGCHANGE:
		dwCharSet = wParam;

	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);
		cyBuffer = max(1, cyClient / cyChar);

		// allocate memory for buffer and clear it

		if (pBuffer != NULL)
			free(pBuffer);

		pBuffer = (TCHAR *)malloc(cxBuffer * cyBuffer * sizeof(TCHAR));//缓冲区大小:行和列相乘,在乘每一个点对于的大小

		for (y = 0; y < cyBuffer; y++)
			for (x = 0; x < cxBuffer; x++)
				BUFFER(x, y) = ' ';                      //对缓冲区每个点初始化为空

														 // set caret to upper left corner

		xCaret = 0;
		yCaret = 0;

		if (hwnd == GetFocus())
			SetCaretPos(xCaret * cxChar, yCaret * cyChar);

		InvalidateRect(hwnd, NULL, TRUE);
		return 0;

	case WM_SETFOCUS:                                //窗体获得焦点,在wm_create和wm_size,wm_paint消息后被调用
													 // create and show the caret

		CreateCaret(hwnd, NULL, cxChar, cyChar);
		SetCaretPos(xCaret * cxChar, yCaret * cyChar);
		ShowCaret(hwnd);               //会一直的闪烁,直到碰到setcaretpos函数,重新确定光标的坐标
		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);  //在这个坐标位置闪烁,不需要调用ShowCaret,因为第一次调用ShowCaret后,就一直闪烁
		return 0;          //碰到SetCaretPos,重新确定了坐标,就在这个位置一直闪烁

	case WM_CHAR:
		for (i = 0; i < (int)LOWORD(lParam); i++)
		{
			switch (wParam)
			{
			case '\b':                    // backspace
				if (xCaret > 0)
				{
					xCaret--;
					SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1);
				}
				break;

			case '\t':                    // tab
				do
				{
					SendMessage(hwnd, WM_CHAR, ' ', 1);
				} while (xCaret % 8 != 0);
				break;

			case '\n':                    // line feed
				if (++yCaret == cyBuffer)
					yCaret = 0;
				break;

			case '\r':                    // carriage return
				xCaret = 0;

				if (++yCaret == cyBuffer)
					yCaret = 0;
				break;

			case '\x1B':                  // escape
				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 = 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);//着行输出窗口中的内容,其中cychar为每一行高度,cxbuffer为每行显示的字符数
																 //cybuffer用于控制行,每次循环,行数加一,输出该行的内容

		DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

显示结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值