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
API is somewhat complex, and not well documented in the
Platform SDK. You can unserstand how best to use
in you 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
SetCapture() API, and that window has the mouse capture untill either
ReleaseCapture() API or
SetCapture() is called directing the
mouse capture to a diffrent window.
In addition, there are two types of capture, that I call foreground and background
capture. Foreground capture is obtained when the follwoing two conditions are met:
- The current thread is the foreground thread (ie. 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 bacground.
Here are the diffrences between foreground and background capture:
- Foreground Capture
- A window with foreground capture receives all mouse messages for all windows in the system.
- Background Capture
- Once the capture has reverted to background capture, the window only receives mouse messages
- 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
|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 dectect 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
|If the mouse up finishes the drag (see the below
Remarks for more info on why a mouse up might not finish a drag operation)
ReleaseCapture() must be called to allow other windows access to mouse
|A drag operation can ususally be aborted by pressing ESC.
If required abort the drag operation and call |
|The window maanger 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
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 resoponse 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
Also note that most system drag operations allows 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 ahve to be specially catered for to prevent
another drag operation being launched.
There are two variations of this API available:
- Available as a standard window manager function on Windows 98 and above and Windows NT
4 and above.
- Available in the common control library on all systems with Internet Explorer 3 and
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
Rolling your own TrackMouseEvent
A full custom implementation of
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 perfrom hover detection for child windows. The sample
assumes you are perfroming 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
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
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
Knowledge Base References
More information on this topic can be found in the following KB articles:
HOWTO: Use Win32 API to Draw a Dragging Rectangle on Screen DC
HOWTO: Detect When the Cursor Leaves the Window