Windows响应键盘鼠标事件

文章目录

  • 1. 接收键盘的输入
  • 2. 接收鼠标输入
  • 3. SendMessage和PostMessage


上篇文章中讲了如何创建一个简单的Win32的窗口,这篇文章简单讲一下如何响应鼠标和键盘事件。

1. 接收键盘的输入

当一个按键被按下时,Windows会向获得焦点得窗口所在得线程传递一个WM_KEYDOWNWM_SYSKEYDOWN 消息。当释放这个按键时,Windows会发送一个WM_KEYUPWM_SYSKEYUP 消息。WM_SYSKEYDOWNWM_SYSKEYUP 是用户敲击系统键盘时产生得消息。默认情况下应该把他们交给系统 DefWindowProc 函数来处理。

在这几个消息中, wParam 包含了按键得虚拟键盘码,lParam 包含了另外一些状态信息。

当一个WM_KEYDOWN 消息被 TranslateMessage 函数转化后会有一个 WM_CHAR 消息产生,此消息得 wParam 参数包含了按键得ANSI码。例如当用户敲击键盘“A”键,窗口会一次收到下面三个消息:

  • WM_KEYDOWN: lParam 中为虚拟按键码A"0x41"
  • WM_KEYCHAR: lParam 中为ANSI码A"0x61"
  • WM_KEYUP: lParam 中为虚拟按键码“0x41”

下面是窗口函数处理消息 WM_KEYCHAR 将按下得键绘制到窗口上得代码:

LRESULT CALLBACK MainWindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static std::wstring str;
	switch (message)
	{
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = ::BeginPaint(hwnd, &ps);
		::TextOut(hdc, 0, 0, str.c_str(), str.size());
		::EndPaint(hwnd, &ps);
		return 0;
	}
	case WM_DESTROY:
		::PostQuitMessage(0);
		return 0;
	case WM_CHAR:
		str += char(wParam);
		::InvalidateRect(hwnd, nullptr, 0);
		return 0;
	}

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

函数 InvalidateRect 会使客户区无效,迫使Windows再发送 WM_PAINT 消息,该函数原型为:

BOOL InvalidateRect (HWND hwnd, CONST RECT *lpRect, BOOL bErase)

  • hwnd: 为窗口句柄
  • lpRect: 指定无效区域得范围,如果为nullptr则为整个客户区
  • bErase: 更新区域时,背景是否擦处。

BeginPaint 函数得第二个参数为一个指向 PAINTSTRUCT 结构得指针,此结构包含重画客户区时所需要得信息。

typedef struct tagPAINTSTRUCT {
    HDC         hdc;				// 设备环境句柄
    BOOL        fErase;				// 指定背景是否删除
    RECT        rcPaint;			// 要求重画的区域
    BOOL        fRestore;
    BOOL        fIncUpdate;
    BYTE        rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;

2. 接收鼠标输入

当鼠标被按下或者移动等操作,windows会发送消息给窗口,下面是不同的操作发送不同的消息表格:

按下 弹起 双击
左键 WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBCLCK
中键 WM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBCLCK
右键 WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBCLCK

发送消息时, lParam 参数包含了鼠标的坐标

xPos = LOWORD(lParam);
yPos = HIWORD(lParam);

客户区坐标和屏幕坐标的相互转化可以使用下面的函数:

  • BOOL ClientToScreen (HWND hWnd, LPPOINT lpPoint)
  • BOOL ScreenToClient (HWND hWnd, LPPOINT lpPoint)

wParam 参数包含鼠标的按钮的状态,这些都是以MK_ 前缀,意为 mouse key

  • MK_LBUTTON : 左键按下
  • MK_MBUTTON : 中键按下
  • MK_RBUTTON: 右键按下
  • MK_SHIFT : 《Shift》键按下
  • MK_CONTROL : 《Ctrl》 键按下

下面是当左键按下时,绘制显示当时鼠标位置的窗口函数代码:

LRESULT CALLBACK MainWindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static std::wstring str;
	switch (message)
	{
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = ::BeginPaint(hwnd, &ps);
		::TextOut(hdc, 0, 0, str.c_str(), str.size());
		::EndPaint(hwnd, &ps);
		return 0;
	}
	case WM_DESTROY:
		::PostQuitMessage(0);
		return 0;
	case WM_LBUTTONDOWN:
		WCHAR message[60];
		memset(message, 0, sizeof(message));
		wsprintf(message, L"X=%d, Y=%d", LOWORD(lParam), HIWORD(lParam));
		str = message;
		::InvalidateRect(hwnd, nullptr, FALSE);
		return 0;
	}

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

如果想设置文字的背景色和文本颜色可以使用下面的函数:
SetTextColor(hdc, RGB(255, 0, 0)); // 文本颜色设置为红色
SetBkColor(hdc, RGB(0, 0, 255)); // 背景颜色设置为蓝色

3. SendMessage和PostMessage

  • SendMessage 函数发送的消息不进入消息队列等待 GetMessage 函数而出,而是直接传给窗口函数 MainWndProc ,并等待 MainWndProc 函数返回时再返回,其返回值也就是 MainWndProc 函数的返回值。
  • PostMessage 函数发送消息后会马上返回,不等待消息的运行结果。他不把消息发送给消息的窗口函数 MainWndProc ,而是把消息投放给窗口所在线程的消息队列中等待GetMessage 函数取出。

你可能感兴趣的:(Windows编程)