2026-01-05 11:47:26 活动前瞻

如果用户在光标位于窗口工作区上时单击鼠标按钮,该窗口将收到以下消息之一。

消息

含义

WM_LBUTTONDOWN

按下左键

WM_LBUTTONUP

松开左键

WM_MBUTTONDOWN

按下中间按钮

WM_MBUTTONUP

松开中间按钮

WM_RBUTTONDOWN

按下右键

WM_RBUTTONUP

松开右侧

WM_XBUTTONDOWN

按下 XBUTTON1 或 XBUTTON2

WM_XBUTTONUP

松开 XBUTTON1 或 XBUTTON2

回想一下,工作区是窗口中不包含框架的部分。 有关工作区的详细信息,请参阅什么是窗口?

鼠标坐标

在所有这些消息中,lParam 参数包含鼠标指针的 x 坐标和 y 坐标。 lParam 的最低 16 位包含 x 坐标,接下来的 16 位包含 y 坐标。 使用 GET_X_LPARAM 和 GET_Y_LPARAM 宏从 lParam 解压缩坐标。

int xPos = GET_X_LPARAM(lParam);

int yPos = GET_Y_LPARAM(lParam);

这些宏已在标头文件 WindowsX.h 中定义。

在 64 位 Windows 上,lParam 是 64 位值。 不使用 lParam 的上 32 位。 如果 Windows 文档提到 lParam 的“低序单词”和“高阶单词”,则 64 位大小写表示低序和低序 32 位的单词。 宏提取正确的值,因此如果您使用它们,您将是安全的。

鼠标坐标以像素为单位,而不是与设备无关的像素 (DIP),并且相对于窗口的工作区进行测量。 坐标为符号值。 工作区上方和左侧的位置具有负坐标,如果跟踪窗口外的鼠标位置,这一点很重要。 我们将在后面的主题中了解如何在窗口外捕获鼠标移动。

其他标志

wParam 参数包含一个按位 OR 的标志,指示其他鼠标按钮的状态以及 Shift 和 Ctrl 键。

标记

含义

MK_CONTROL

按下了 CTRL 键。

MK_LBUTTON

按下了鼠标左键。

MK_MBUTTON

按下了鼠标中键。

MK_RBUTTON

按下了鼠标右键。

MK_SHIFT

按下了 SHIFT 键。

MK_XBUTTON1

XBUTTON1 按钮已按下。

MK_XBUTTON2

XBUTTON2 按钮已按下。

缺少标志意味着未按下相应的按钮或键。 例如,若要测试 CTRL 键是否按下:

if (wParam & MK_CONTROL) { ...

如果需要查找除 Ctrl 和 SHIFT 以外的其他键的状态,请使用键盘输入中介绍的 GetKeyState 函数。

WM_XBUTTONDOWN 和 WM_XBUTTONUP 窗口消息适用于 XBUTTON1 和 XBUTTON2。 wParam 参数表明单击了哪个按钮。

UINT button = GET_XBUTTON_WPARAM(wParam);

if (button == XBUTTON1)

{

// XBUTTON1 was clicked.

}

else if (button == XBUTTON2)

{

// XBUTTON2 was clicked.

}

双击

默认情况下,窗口不会收到双击通知。 若要接收双击,请在注册窗口类时在 WNDCLASS 结构中设置 CS_DBLCLKS 标志。

WNDCLASS wc = { };

wc.style = CS_DBLCLKS;

/* Set other structure members. */

RegisterClass(&wc);

如果按所示设置 CS_DBLCLKS 标志,窗口将收到双击通知。 双击由名称中带有“DBLCLK”的窗口消息表示。 例如,双击鼠标左键将生成以下消息序列:

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_LBUTTONUP

实际上,通常会生成的第二个 WM_LBUTTONDOWN 消息将成为 WM_LBUTTONDBLCLK 消息。 为右侧、中间和 XBUTTON 按钮定义等效消息。

在收到双击消息之前,无法判断鼠标的第一次单击是双击的开始。 因此,双击操作应继续从第一次鼠标单击开始的操作。 例如,在 Windows Shell 中,单击一下会选择一个文件夹,而双击将打开该文件夹。

非客户端鼠标消息

为在窗口的非工作区内发生的鼠标事件定义一组单独的消息。 这些消息的名称中含有字母“NC”。 例如,WM_NCLBUTTONDOWN 是 WM_LBUTTONDOWN 的非客户端等效项。 典型的应用程序不会截获这些消息,因为 DefWindowProc 函数可正确处理这些消息。 但是,它们对于某些高级函数很有用。 例如,可以使用这些消息在标题栏中实现自定义行为。 如果确实处理这些消息,则通常应在处理后将其传递给 DefWindowProc 。 否则,应用程序将破坏标准功能,例如拖动或最小化窗口。

下一步

鼠标移动