Windows supports mice with multiple buttons and a scroll wheel. Early versions of Windows were designed around the assumption of a three-button mouse (left, right, and middle buttons) plus an optional wheel. Modern versions of Windows (Windows XP onwards, and especially Windows 7, 10 and 11) support additional mouse buttons. Mouse messages are generated whenever the user moves the mouse, clicks a mouse button, or rotates the scroll wheel within either the client area or the non-client area of a window. The non-client area consists of the window border, title bar, menu bar, scroll bars, and the minimise, maximise, and close buttons.
Client Area Mouse Messages
The table below lists the most commonly used client-area mouse messages together with their MFC message-map macros and handler functions.
| Description | Message map macro | Handling function |
|---|---|---|
| Left mouse button pressed. | ON_WM_LBUTTONDOWN | OnLButtonDown |
| Left mouse button released. | ON_WM_LBUTTONUP | OnLButtonUp |
| Left mouse button double-clicked. | ON_WM_LBUTTONDBLCLK | OnLButtonDblClk |
| Middle mouse button pressed. | ON_WM_MBUTTONDOWN | OnMButtonDown |
| Middle mouse button released. | ON_WM_MBUTTONUP | OnMButtonUp |
| Middle mouse button double-clicked. | ON_WM_MBUTTONDBLCLK | OnMButtonDblClk |
| Right mouse button pressed. | ON_WM_RBUTTONDOWN | OnRButtonDown |
| Right mouse button released. | ON_WM_RBUTTONUP | OnRButtonUp |
| Right mouse button double-clicked. | ON_WM_RBUTTONDBLCLK | OnRButtonDblClk |
| Cursor moved over client area. | ON_WM_MOUSEMOVE | OnMouseMove |
The prototype for each client-area message handler is:
afx_msg void OnMsgName (UINT nFlags, CPoint point)
Where
point – contains the cursor location reported in device coordinates relative to the upper left corner of the window’s client area.
nFlags – contains additional information about the mouse state and Shift and Ctrl as detailed below.
MK_LBUTTON – The left mouse button is pressed.
MK_MBUTTON – The middle mouse button is pressed.
MK_RBUTTON – The right mouse button is pressed.
MK_CONTROL – The Ctrl key is pressed.
MK_SHIFT – The Shift key is pressed.
Nonclient-Area Mouse Messages
A non-client-area message is generated whenever the mouse is moved or a mouse button is pressed over a window’s non-client area.
| Message | Message-Map Macro | Handling Function |
|---|---|---|
| WM_NCLBUTTONDOWN | ON_WM_NCLBUTTONDOWN | OnNcLButtonDown |
| WM_NCLBUTTONUP | ON_WM_NCLBUTTONUP | OnNcLButtonUp |
| WM_NCLBUTTONDBLCLK | ON_WM_NCLBUTTONDBLCLK | OnNcLButtonDblClk |
| WM_NCMBUTTONDOWN | ON_WM_NCMBUTTONDOWN | OnNcMButtonDown |
| WM_NCMBUTTONUP | ON_WM_NCMBUTTONUP | OnNcMButtonUp |
| WM_NCMBUTTONDBLCLK | ON_WM_NCMBUTTONDBLCLK | OnNcMButtonDblClk |
| WM_NCRBUTTONDOWN | ON_WM_NCRBUTTONDOWN | OnNcRButtonDown |
| WM_NCRBUTTONUP | ON_WM_NCRBUTTONUP | OnNcRButtonUp |
| WM_NCRBUTTONDBLCLK | ON_WM_NCRBUTTONDBLCLK | OnNcRButtonDblClk |
| WM_NCMOUSEMOVE | ON_WM_NCMOUSEMOVE | OnNcMouseMove |
The message map handler function will be of the following format
afx_msg void OnMsgName (UINT nHitTest, CPoint point)
where
nHitTest – contains a hit-test code that identifies where in the window’s nonclient area the event occurred. A selection of these hit-test codes is shown in the list below.
| Value | Corresponding Location |
| HTCAPTION | The title bar |
| HTCLOSE | The close button |
| HTGROWBOX | The restore button (same as HTSIZE) |
| HTHSCROLL | The window’s horizontal scroll bar |
| HTMENU | The menu bar |
| HTREDUCE | The minimize button |
| HTSIZE | The restore button (same as HTGROWBOX) |
| HTSYSMENU | The system menu box |
| HTVSCROLL | The window’s vertical scroll bar |
| HTZOOM | The maximize button |
point – specifies the screen coordinates at which the event occurred. Unlike client-area mouse messages, the coordinates are expressed in screen coordinates rather than client coordinates. They can be converted using CWnd::ScreenToClient().
Miscellaneous Mouse Messages
WM_NCHITTEST
Before a window receives a client-area or nonclient-area mouse message, it receives a WM_NCHITTEST message accompanied by the cursor’s screen coordinates. Windows uses this message to determine whether to send a client-area or nonclient-area mouse message. For a complete description of the message parameters, consult the Microsoft documentation for WM_NCHITTEST.
The Mouse Wheel
The WM_MOUSEWHEEL message is sent when the mouse wheel is rotated.
MFC’s ON_WM_MOUSEWHEEL macro maps WM_MOUSEWHEEL messages to the message handler OnMouseWheel. The prototype of OnMouseWheel is:
BOOL OnMouseWheel (UINT nFlags, short zDelta, CPoint point)
Where
The nFlags and point parameters are identical to those passed to OnLButtonDown.zDelta is the distance the wheel was rotated. zDelta is expressed in multiples (or fractions) of WHEEL_DELTA, whose value is 120.. A value less than zero indicates rotating while a value greater than zero indicates rotating forward (away from the user).
Double Clicks
By default, Windows does not generate double-click messages. To receive them, the window class must be registered with the CS_DBLCLKS style.To register a double click, a window must be set up to be notified of a double click event by including the WNDCLASS style CS_DBLCLKS during Windows registration. This is set by default in a frame windows declaration. The MFC Message-Map Macro and associated Handling Function for dealing with a double click are
ON_WM_LBUTTONDBLCLK – OnLButtonDblClk(UINT, CPoint)
ON_WM_RBUTTONDBLCLK – OnRButtonDblClk(UINT, CPoint)
ON_WM_MBUTTONDBLCLK – OnMButtonDblClk(UINT, CPoint)
Capturing the Mouse
A window procedure normally receives mouse messages only when the mouse cursor is positioned over the client or nonclient area of the window however a program might need to receive mouse messages when the mouse is outside the window. For example, if a mouse button is clicked inside a window but the mouse moves outside the window’s client area before releasing that button then the window will not receive the button-up event. To remedy this problem, Windows allows the application to ‘capture’ the mouse and continue to receive mouse messages when a cursor moves outside the application window. Windows will then continue to receive messages until the button is released or the capture is cancelled. The mouse is captured with CWnd member function SetCapture() and released with CWnd member function ReleaseCapture(). These functions are normally executed in the button-down and button-up handlers
The Hourglass Cursor
When an application undertakes a lengthy processing task the usual procedure is to display an hourglass to indicate that the application is “busy.” The CWaitCursor class allows any application to display a wait cursor. To display a WaitCursor create a CWaitCursor object variable before the code that performs the lengthy operation, the object’s constructor will automatically cause the wait cursor to be displayed. When the object goes out of scope its destructor will set the cursor to the previous cursor.
void LengthyFunction( )
{
CWaitCursor wait; // display wait cursor
//lengthy process
} // wait cursor removed when function goes out of scope
Changing the Mouse Icon
The Win32 API function SetCursor() changes the shape of the mouse cursor. The cursor can be created with CreateCursor() or loaded with LoadCursor() or LoadImage(). In MFC applications, cursor changes are typically performed in response to the WM_SETCURSOR message.
HCURSOR SetCursor(HCURSOR hCursor);
Where hCursor is a handle to the cursor. The cursor can be created by the CreateCursor() function or loaded by the LoadCursor() or LoadImage() function. If this parameter is NULL, the cursor is removed from the screen.
The return value is the handle to the previous cursor or NULL if there was no previous cursor.
For further information about setting the cursor icon go to the following link
https://support.microsoft.com/en-gb/help/131991/how-to-change-the-mouse-pointer-for-a-window-in-mfc-by-using-visual-c
Determining the Mouse Position
An application often needs to determine the current position of the mouse cursor independently of mouse messages. For example, a program may need to display a context menu at the current cursor position, track the cursor while performing a background operation, or determine the cursor position when a timer expires.
The Win32 API function GetCursorPos() retrieves the current position of the mouse cursor in screen coordinates. Its prototype is:
BOOL GetCursorPos(LPPOINT lpPoint);)
where lpPoint points to a POINT structure that receives the screen coordinates of the cursor.
Example
POINT pt;
if (GetCursorPos(&pt))
{
printf("Screen Coordinates: (%ld, %ld)\n", pt.x, pt.y);
}
In MFC applications, the POINT structure is equivalent to the CPoint class:
CPoint pt;
if (GetCursorPos(&pt))
{
TRACE("Screen Coordinates: (%d, %d)\n", pt.x, pt.y);
}
Many applications require the cursor position relative to a window’s client area rather than the desktop. The ScreenToClient() member function converts screen coordinates into client coordinates.
CPoint pt;
GetCursorPos(&pt);
ScreenToClient(&pt);
TRACE("Client Coordinates: (%d, %d)\n", pt.x, pt.y);
Conversely, the ClientToScreen() member function converts client coordinates into screen coordinates.
CPoint pt(20, 30); ClientToScreen(&pt); // pt now contains the corresponding screen coordinates.
When handling mouse messages such as WM_MOUSEMOVE, WM_LBUTTONDOWN, or WM_RBUTTONDOWN, it is unnecessary to call GetCursorPos(), because the cursor position is already supplied in the handler’s CPoint parameter. GetCursorPos() is primarily used when the application needs to determine the cursor position outside the context of a mouse message.
Example
The following short program demonstrates how Windows handles messages from both the client and non-client areas of the screen, together with the ALT and CTRL keys. Output describing the area clicked and the coordinate of the area clicked is displayed in the main window.