关闭

Win32 键盘事件 - 击键消息、字符消息、插入符号(光标)

标签: Win32击键消息字符消息插入符号光标
12722人阅读 评论(0) 收藏 举报
分类:

注:以下内容为学习笔记,多数是从书本、资料中得来,只为加深印象,及日后参考。然而本人表达能力较差,写的不好。因非翻译、非转载,只好选原创,但多数乃摘抄,实为惭愧。但若能帮助一二访客,幸甚!


以下内容主要来自《Windows 程序设计》

1.焦点

程序用于从消息队列中读取消息的MSG结构中包含一个hwnd字段。此字段指出了接收消息的窗口句柄。消息循环中的DispatchMessage函数传送消息给需要该消息的窗口过程。

接收到这个键盘事件的窗口称为有输入焦点的窗口。

有时没有窗口具有输入焦点。这种情况发生在所以程序都最小化时。

窗口过程通过捕获WM_SETFOCUS和WM_KILLFOCUS消息来确定自己的窗口是否具有输入焦点。


2.队列和同步

当用户按下和释放键盘上的一个键时,Windows和键盘设备驱动程序将硬件扫描码转换为格式化后的消息。但是这些消息并不立即被放入应用程序消息队列,而是由Windows把这些消息存储在系统消息队列中。系统消息队列是一个单独的消息队列,它被Windows用来初步存储用户从键盘和鼠标输入的消息。仅当Windows应用程序完成了对当前一个用户输入消息的处理后,Windows才从系统消息队列中取出下一条消息,并把它放入应用程序消息队列。


3.击键消息

当用户按下一个键时,Windows将WM_KEYDOWN或WM_SYSKEYDOWN消息放入具有输入焦点的消息队列中。当该键被释放时,Windows把WM_KEYUP或WM_SYSKEYUP消息放入相应的消息队列中。其中SYS代表系统,它表明该击键对Windows比对应用程序更加重要。

虚拟键代码存储在WM_KEYDOWN等消息的wParam参数中,确定哪个键被按下或被释放。

当处理击键消息时,可能需要知道是否有转义键(Shift、Ctrl和Alt)或切换键(Caps Lock、Num Lock和Scroll Lock)键被按下。

可以用如下方式:

iState = GetKeyState(VK_SHIFT);

给前面的SYSMETS代码(http://blog.csdn.net/guzhou_diaoke/article/details/8155740   7.滚动条)中添加键盘处理功能:

简单方法:为窗口过程增加WM_KEYDOWN逻辑

更好的方法:把每一个WM_KEYDOWN消息转换为等同的WM_VSCROLL或WM_HSCROLL消息。可以使用:

SendMessage(hwnd, message, wParam, lParam);

当你调用SendMessage函数时,Windows调用窗口句柄hwnd的窗口过程,同时把四个函数变量传递给他。当窗口过程处理完此消息,Windows把控制权还给紧跟着SendMessage调用的下一条语句。

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	// cxChar平均字符宽度,cyChar字符的总高度(包括外部间距),cxCaps大写字符的平均宽度
	// 等宽字体中,cxCaps等于cxChar,变宽字体中,cxCaps等于cxChar的1.5倍
	static int	cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth, iVscrollPos;	
	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;
		// tmPitchAndFamily为1表示变宽字体,为0表示等宽字体
		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;
		}

		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;
		}

		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);
			UpdateWindow(hwnd);
		}
		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].iIndex)));

			// 将对齐方式设回正常方式
			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}


有键盘了,就差鼠标了~很快会有的。


4.字符消息

通过转义状态信息可把击键消息转换为字符消息。

GetMessage从消息队列中取出下一条消息;

TranslateMessage负责把击键消息转换为字符消息;

DispatchMessage调用此消息的窗口过程。


5.消息排序

假如Caps Lock没有锁定,按下再释放A,相应窗口过程会接收:

1)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

2)WM_CHAR:  'a'的字符编码(0x61)

3)WM_KEYUP: 'A' 的虚拟键代码(0x41)


按下Shift+A,释放A,再释放Shift:

1)WM_KEYDOWN:虚拟键代码VK_SHIFT(0x10)

2)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

3)WM_CHAR:  'A' 的字符编码(0x41)

4)WM_KEYUP: 'A' 的虚拟键代码(0x41)

5)WM_UP:虚拟键代码VK_SHIFT(0x10)


连续按住A:

1)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

2)WM_CHAR:  'a'的字符编码(0x61)

3)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

4)WM_CHAR:  'a'的字符编码(0x61)

……

n)WM_KEYUP: 'A' 的虚拟键代码(0x41)


6.控制字符的处理

按照以下基本规则来处理击键和字符消息:如果你需要读取输入到窗口中的键盘字符,就处理WM_CHAR消息;如果你需要读取光标键、功能键、Delete键、Insert键、Shift键、Ctrl键和Alt键,则处理WM_KEYDOWN消息。


/*---------------------------------------------------------------------------
	keyView.cpp -- Displays keyboard and character messages
----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------------
	SysMets4.cpp -- System Metrics Display Program ver4 use keyboard
 *----------------------------------------------------------------------------------*/

#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,										// window class name
						TEXT("Keyboard Message Viewer #1"),				// window caption
						WS_OVERLAPPEDWINDOW,							// window style
						CW_USEDEFAULT,									// initial x position
						CW_USEDEFAULT,									// initial y position
						CW_USEDEFAULT,									// initial x size
						CW_USEDEFAULT,									// initial y size
						NULL,											// parent window handle
						NULL,											// window menu handle
						hInstance,										// program instance handle
						NULL);											// creation parameters

	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)
{
	// cxChar平均字符宽度,cyChar字符的总高度(包括外部间距),cxCaps大写字符的平均宽度
	// 等宽字体中,cxCaps等于cxChar,变宽字体中,cxCaps等于cxChar的1.5倍
	static int		cxChar, cyChar, cxClient, cyClient, cxClientMax, cyClientMax;
	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;

		//return 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);

		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, 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++)
		{
			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));
		}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}



7.插入符号(就是平时说的光标)

插入符号指明你输入的下一个字符将出现在屏幕上的位置。

相关函数:

CreateCaret:创建和窗口关联的插入符号

SetCaretPos:设置窗口内的插入符号的位置

ShowCaret:显式插入符号

HideCaret:隐藏插入符号

DestroyCaret:销毁插入符号

GetCaretPos:获取插入符号位置

GetCaretBlinkTime、SetCaretBlinkTime:获取、设置插入符号闪烁时间


使用插入符号主要规则:在窗口过程处理WM_SETFOCUS消息时调用CreateCaret,处理WM_KILLFOCUS消息时调用DestroyCaret函数。

创建的插入符号是隐藏的,必须调用ShowCaret使之可见。

要在窗口内绘制某些东西时,它必须调用HideCaret隐藏插入符号。结束绘制后,再调用ShowCaret显式插入符号。

HideCaret效果是叠加的。


一个简单的文本编辑器雏形:

/*----------------------------------------------------------------------------
	typer.cpp -- Typing Program
----------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
	keyView.cpp -- Displays keyboard and character messages
----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------------
	SysMets4.cpp -- System Metrics Display Program ver4 use keyboard
 *----------------------------------------------------------------------------------*/

#include <windows.h>

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

#define BUFFER(x, y)	*(pBuffer + y*cxBuffer + x)

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,										// window class name
						TEXT("Typer"),									// window caption
						WS_OVERLAPPEDWINDOW,							// window style
						CW_USEDEFAULT,									// initial x position
						CW_USEDEFAULT,									// initial y position
						CW_USEDEFAULT,									// initial x size
						CW_USEDEFAULT,									// initial y size
						NULL,											// parent window handle
						NULL,											// window menu handle
						hInstance,										// program instance handle
						NULL);											// creation parameters

	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;

	int				x, y, i;
	HDC				hdc;
	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);

	case WM_SIZE:
		if (message == WM_SIZE)
		{
			cxClient = LOWORD(lParam);
			cyClient = HIWORD(lParam);
		}
		
		cxBuffer = max(1, cxClient/cxChar);
		cyBuffer = max(1, cyClient/cyChar);

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

		pBuffer = (TCHAR *)malloc(sizeof(TCHAR) * cxBuffer * cyBuffer);

		for (y = 0; y < cyBuffer; y++)
			for (x = 0; x < cxBuffer; x++)
				BUFFER(x, y) = ' ';

		xCaret = 0;
		yCaret = 0;

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

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

	case WM_SETFOCUS:
		CreateCaret(hwnd, NULL, cxChar, cyChar);
		SetCaretPos(xCaret*cxChar, yCaret*cyChar);
		ShowCaret(hwnd);
		return 0;

	case WM_KILLFOCUS:
		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++)
		{
			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);

		DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}



0
0
查看评论

(win32)解决虚拟按键被输入法截获

(win32)解决虚拟按键被输入法截获
  • kencaber
  • kencaber
  • 2016-05-15 17:11
  • 1455

在windows下pywin32模拟鼠标及键盘动作

前言Windows pywin32允许你像vc一样的形式来使用python开发win32应用。代码风格可以类似win32 sdk,也可以类似MFC,由你选择。如果你仍不放弃vc一样的代码过程在python下,这不错的选择。利用pywin32可以自动化进行电脑操作。包括复制粘贴,鼠标移动,键盘输入等等...
  • qq_33371343
  • qq_33371343
  • 2017-12-27 21:39
  • 277

win32api之虚拟键盘

在做开发的时候,UI上的一些快捷键可以使用虚拟键来触发。比如:revit二次开发中的快捷键后台触发。/// <summary> /// 虚拟键盘. /// </summary> /// <author>YangSen</author> /// <...
  • yangsen600
  • yangsen600
  • 2017-02-21 12:58
  • 431

利用键盘事件keybd_event(Win32 API)模拟键盘按键

云平台第三次重置后,通过FTP传输文件的途径失效,因此需要其他方法向自己的云桌面发送代码。无论云桌面怎么设置,都必须支持接收键盘和鼠标的输入,因此如果可以模拟键盘输入,就可以实现发送代码的功能。 Win32API中提供了 keybd_event 函数 Syntax VOID...
  • qq_21153991
  • qq_21153991
  • 2016-07-01 11:09
  • 6715

win32 键盘 鼠标事件

VC 中用 KeyPress 表示键盘响应的所有事件,包括 OnKeyDown 事件(键按下)、 OnKeyUp 事件(键按下后弹起)和 OnKeyPress 事件(按了某个键)。 OnKeyuUp&...
  • u011822516
  • u011822516
  • 2014-12-19 16:21
  • 1407

【win32】鼠标响应事件

对比于《【mfc】鼠标、键盘响应事件》(点击打开链接),win32的鼠标响应事件更能揭示出窗体程序的本质。鼠标响应事件同样在窗体程序的消息回调函数LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara...
  • yongh701
  • yongh701
  • 2017-02-11 20:51
  • 2999

原谅我今天才学会使用win32的按键消息处理!

之前一直写directX的程序,用到的win32消息并不多,而且大部分的按键捕获都是有directInput完成的,因为能捕获到手柄那样的按键(而且据说还是实时的消息捕获)。。。 今天当我想要自己写一个win32的按键消息处理时就晕了。。 各种google、baidu出来的结果都...
  • zengraoli
  • zengraoli
  • 2013-04-18 10:19
  • 2701

WM_CHAR 获取键盘按下的字符

// DEMO3_11.CPP - WM_CHAR demo// INCLUDES ///////////////////////////////////////////////#define WIN32_LEAN_AND_MEAN  // just say no to MFC#inclu...
  • wenzhoufeng
  • wenzhoufeng
  • 2007-11-23 13:26
  • 7740

Windows键盘消息处理

文大部分来自MSDN和网友的博客,我在实践的基础上再作了一些总结。 1. 虚拟键(VK_*) 键盘上每一个键对应一个扫描码,扫描码是OEM厂商制定的,不同的厂商生产的键盘同样一个按键的扫描码都有可能出现不一致的情况,为了摆脱由于系统设备不一致的情况,通过键盘驱动程序将扫描码映射为统一的虚...
  • leehong2005
  • leehong2005
  • 2013-02-26 11:52
  • 9160

[Win32]键盘消息

1. 为Sysmets3程序添加击键消息:     1) 主要是添加了Page Up、Page Down、
  • Lirx_Tech
  • Lirx_Tech
  • 2014-10-28 14:42
  • 1586
    个人资料
    • 访问:257528次
    • 积分:3557
    • 等级:
    • 排名:第11026名
    • 原创:86篇
    • 转载:0篇
    • 译文:0篇
    • 评论:100条
    博客专栏
    babyos2

    文章:34篇

    阅读:3039
    最新评论