响应鼠标单击

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

消息 含义
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_XBUTTONDOWNWM_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_NCLBUTTONDOWNWM_LBUTTONDOWN 的非客户端等效项。 典型的应用程序不会截获这些消息,因为 DefWindowProc 函数可正确处理这些消息。 但是,它们对于某些高级函数很有用。 例如,可以使用这些消息在标题栏中实现自定义行为。 如果确实处理这些消息,则通常应在处理后将其传递给 DefWindowProc 。 否则,应用程序将破坏标准功能,例如拖动或最小化窗口。

下一步

鼠标移动