Responding to Mouse Clicks

If the user clicks a mouse button while the cursor is over the client area of a window, the window receives one of the following messages.

Message Meaning
WM_LBUTTONDOWN Left button down
WM_LBUTTONUP Left button up
WM_MBUTTONDOWN Middle button down
WM_MBUTTONUP Middle button up
WM_RBUTTONDOWN Right button down
WM_RBUTTONUP Right button up


Recall that the client area is the portion of the window that excludes the frame. For more information about client areas, see What Is a Window?

Mouse Coordinates

In all of these messages, the lParam parameter contains the x- and y-coordinates of the mouse pointer. The lowest 16 bits of lParam contain the x-coordinate, and the next 16 bits contain the y-coordinate. Use the GET_X_LPARAM and GET_Y_LPARAM macros to unpack the coordinates from lParam.

int xPos = GET_X_LPARAM(lParam); 
int yPos = GET_Y_LPARAM(lParam);

These macros are defined in the header file WindowsX.h.

On 64-bit Windows, lParam is 64-bit value. The upper 32 bits of lParam are not used. The MSDN documentation mentions the "low-order word" and "high-order word" of lParam. In the 64-bit case, this means the low- and high-order words of the lower 32 bits. The macros extract the right values, so if you use them, you will be safe.

Mouse coordinates are given in pixels, not device-independent pixels (DIPs), and are measured relative to the client area of the window. Coordinates are signed values. Positions above and to the left of the client area have negative coordinates, which is important if you track the mouse position outside the window. We will see how to do that in a later topic, Capturing Mouse Movement Outside the Window.

Additional Flags

The wParam parameter contains a bitwise OR of flags, indicating the state of the other mouse buttons plus the SHIFT and CTRL keys.

Flag Meaning
MK_CONTROL The CTRL key is down.
MK_LBUTTON The left mouse button is down.
MK_MBUTTON The middle mouse button is down.
MK_RBUTTON The right mouse button is down.
MK_SHIFT The SHIFT key is down.
MK_XBUTTON1 The XBUTTON1 button is down.
MK_XBUTTON2 The XBUTTON2 button is down.


The absence of a flag means the corresponding button or key was not pressed. For example, to test whether the CTRL key is down:

if (wParam & MK_CONTROL) { ...

If you need to find the state of other keys besides CTRL and SHIFT, use the GetKeyState function, which is described in Keyboard Input.

The WM_XBUTTONDOWN and WM_XBUTTONUP window messages apply to both XBUTTON1 and XBUTTON2. The wParam parameter indicates which button was clicked.

UINT button = GET_XBUTTON_WPARAM(wParam);  
if (button == XBUTTON1)
    // XBUTTON1 was clicked.
else if (button == XBUTTON2)
    // XBUTTON2 was clicked.

Double Clicks

A window does not receive double-click notifications by default. To receive double clicks, set the CS_DBLCLKS flag in the WNDCLASS structure when you register the window class.

    WNDCLASS wc = { }; = CS_DBLCLKS;

    /* Set other structure members. */


If you set the CS_DBLCLKS flag as shown, the window will receive double-click notifications. A double click is indicated by a window message with "DBLCLK" in the name. For example, a double click on the left mouse button produces the following sequence of messages:


In effect, the second WM_LBUTTONDOWN message that would normally be generated becomes a WM_LBUTTONDBLCLK message. Equivalent messages are defined for right, middle, and XBUTTON buttons.

Until you get the double-click message, there is no way to tell that the first mouse click is the start of a double click. Therefore, a double-click action should continue an action that begins with the first mouse click. For example, in the Windows Shell, a single click selects a folder, while a double click opens the folder.

Non-client Mouse Messages

A separate set of messages are defined for mouse events that occur within the non-client area of the window. These messages have the letters "NC" in the name. For example, WM_NCLBUTTONDOWN is the non-client equivalent of WM_LBUTTONDOWN. A typical application will not intercept these messages, because the DefWindowProc function handles these messages correctly. However, they can be useful for certain advanced functions. For example, you could use these messages to implement custom behavior in the title bar. If you do handle these messages, you should generally pass them to DefWindowProc afterward. Otherwise, your application will break standard functionality such as dragging or minimizing the window.


Mouse Movement