The implementation of the UI of an application sometimes requires the capture of the mouse. The following situations come to mind:
- You need a reliable mouse over detection.
- You are implementing some sort of drag and drop interface.
- You want to know what window the mouse is over.
Notes on the SetCapture API
The action of the
SetCapture() API is somewhat complex, and not well documented in the Platform SDK. You can understand how best to use
SetCapture() in your application if you understand the following limitations of using mouse capture:
Only one window can have the mouse capture at a time. A window can request mouse capture by calling the
SetCapture() API, and that window has the mouse capture until either the
ReleaseCapture() API or
SetCapture() is called directing the mouse capture to a different window.
In addition, there are two types of capture, that I call foreground and background capture. Foreground capture is obtained when the following two conditions are met:
- The current thread is the foreground thread (i.e., it owns the foreground window).
- At least one mouse button is being held down.
Otherwise (if the current thread is not the foreground thread, or no mouse buttons are held down), the window merely gets background capture.
If, at any time, all the mouse buttons are released, the mouse capture will automatically revert to the background.
Here are the differences between foreground and background capture:
A window with foreground capture receives all mouse messages for all windows in the system.
Once the capture has reverted to background capture, the window only receives mouse messages for:
- All windows owned by the same thread
- All windows on all threads if those windows and the window with capture share the same top-level window
Implementing a Drag operation using SetCapture
To implement a drag operation in your application, you would implement the following message handlers:
|A drag operation generally starts when the user clicks on something, and begins to move the mouse. If the user is clicking on something draggable, use the |
DragDetect() API to detect if a drag operation is beginning. Once the beginning of a drag operation is confirmed, call
SetCapture(). Note that various drag enabled controls detect when a drag begins and send their parent a message such as
|If the mouse up finishes the drag (see the below Remarks for more information on why a mouse up might not finish a drag operation) |
ReleaseCapture() must be called to allow other windows access to mouse messages.
|A drag operation can usually be aborted by pressing ESC. If required, abort the drag operation and call |
|The window manager sends this message when it detects a change that requires that an application cancel any modal state it has entered. Abort the drag operation and call |
|The capture has been cleared, or some other window has obtained it. It probably makes no sense to continue your drag operation, so it should be aborted. As you have explicitly lost capture, you don't need to call |
|Mouse capture interrupts the normal flow of mouse processing. |
WM_SETCURSOR messages are not dispatched to a window that has mouse capture - if the cursor should be set to indicate the drag via
SetCursor when the drag operation begins - if the cursor needs to change to provide feedback to the user, it should be set in response to
With the exception of the mouse down or initial drag operation begin detection, most applications implement their drag code in a modal loop to prevent cluttering up the main applications window procedure.
Also note that most system drag operations allow the user to "swap" buttons during a drag by pressing the other button, and then releasing the initial button. If the drag operation is not implemented in a modal loop, this situation would have to be specially catered for to prevent another drag operation being launched.
There are two variations of this API available:
TrackMouseEvent(): Available as a standard window manager function on Windows 98 and above and Windows NT 4 and above.
_TrackMouseEvent(): Available in the common control library on all systems with Internet Explorer 3 and higher.
TrackMouseEvent() if you can ignore Windows 95 as a target. Use
TrackMouseEvent() if you need to target Windows 95, and can assume the machine has at least IE3 installed. If you need
TrackMouseEvent() functionality on Windows 95 and cannot assume at least IE3, then the following quick hack demonstrates the basic functionality.
Rolling Your Own TrackMouseEvent
A full custom implementation of
TrackMouseEvent() would have to implement a message hook so it could hook messages intended for any window. Any window that needs to detect mouse enter, leave or hover events can use code like this:
#define TID_POLLMOUSE 100
#define MOUSE_POLL_DELAY 500
A more responsive version could be made by using
SetCapture() to detect more quickly when the mouse leaves.
#define TID_POLLMOUSE 100
#define MOUSE_POLL_DELAY 500
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
if(hwnd != GetCapture())
The code samples provided differ in a number of ways from the
- In a real application, you need to perform hover detection for child windows. The sample assumes you are performing hover detection over the main window only.
TrackMouseEvent() does not send a
WM_MOUSEENTER message. Nor is there such a message defined. The code simply demonstrates how such a message could be implemented.
TrackMouseEvent is a once off API. Once a notification has been received, you must call it again to receive subsequent notifications. The sample code given will repeatedly send
WM_MOUSEHOVER events - no mechanism is provided whereby notifications can be stopped, or only arrive when requested.
Please feel free to expand the code to fit your own requirements.
Please send any comments or bug reports to me via email. For any updates to this article, check my site here.
Knowledge Base References
More information on this topic can be found in the following KB articles:
- Q135865 HOWTO: Use Win32 API to Draw a Dragging Rectangle on Screen DC
- Q183107 HOWTO: Detect When the Cursor Leaves the Window
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.