how to detect when mouse leaves the window win32 - c++

I am creating an application with the win32 api and I have a boolean isLeftClickPressed which is set to true when I receive a WM_LBUTTONDOWN message. when I receive a WM_LBUTTONUP message I set it to false. this works fine, however if I hold down the left mouse button and move my cursor out of the window and release my mouse, it never send a WM_LBUTTONUP message. I am not looking for a way to get around this rather just to find out when my mouse leaves the window and then set isLeftClickPressed to false.
any help would be appreciated.

Call TrackMouseEvent and check for WM_MOUSELEAVE

Related

Win32 C++ - Check if the Window PositionX/PositionY and Width/Height changed

It is possible to check whenever the X/Y position of the window changed? Also, if it's possible to check if the Window Width/Height changed too.
You're looking for the WM_MOVE and WM_SIZE messages.
As already answered, you can handle WM_SIZE and WM_MOVE. But you can also intercept the messages before they have any effect by checking WM_WINDOWPOSCHANGING (except in the case where a call to SetWindowPos passes SWP_NOSENDCHANGING - but that is usually deliberate and completely under your control). This message is useful for cleanly handling window size/position restrictions or doing window snapping. If you force stuff to happen during WM_SIZE or WM_MOVE you will get flickering etc.

MFC C++: does setfocus set the capture as well?

I have a CDialog that is calling DoModal(), the dialog is opened, everything else is disabled, but for some reason I have only the keyboard capture and not the mouse.
The mouse capture is still on the last item it was on.
If I call setfocus before the DoModal, it doesn't work, but if I do setCapture before the DoModal it works.
Can anyone explain it to me?
What is the problem? I want to understand why I need to call to setCapture or releaseCapture before the DoModal (btw- releaseCapture works as well...)
There is no such thing as 'keyboard capture'. There is just keyboard focus.
A window that has the keyboard focus is the one that receives the keyboard related messages.
Mouse messages are normally sent to the window just beneath the mouse cursor, without regard to the focus. That is unless the mouse is "captured", in this case mouse messages are sent to the windows that has captured the mouse, no matter where the mouse cursor is.
That said, do you really need to capture the mouse? Actually that is rarely necessary. And it should be done only as a consequence to a user action, never on your own.
PS. Due to security concerns, in Windows there are actually two different kinds of mouse captures:
Local captures: mouse messages are sent to the capturing window, only if the mouse is over a window that belongs to the same application.
Global capture: mouse messages are sent to the capturing window, no matter where the mouse cursor is.
The SetCapture function creates a global capture only if it is called while processing a WM_?BUTTON_DOWN message.

How to check if a mouse is over a control

How does one check if the mouse is over a certain HWND? I have tried using the WM_MOUSELEAVE and WM_MOUSEMOVE messages to keep track, but if you click a button and drag the mouse out of the button, it doesn't receive the WM_MOUSELEAVE until the mouse is released, which is too late, because:
When you click a button, the WM_COMMAND message is only sent if:
1. The mouse was originally depressed over the button
2. The mouse is over the button
3. The mouse is released over the button
I need to replicate this functionality.
To duplicate this functionality, just call SetCapture() so that mouse messages are sent to your window even if the mouse leaves it. You can read the current mouse position as it moves and determine if it is still over your window/button (I'm still not 100% sure what you are doing). And, when the mouse button is released, you can call ReleaseCapture() to restore where mouse messages are sent.
EDIT: Oh, and you can use the Windows API function WindowFromPoint() to determine which window the mouse is over.
This is built-in to Windows, it is called 'mouse capture', SetCapture(hWnd). It ensures you get mouse messages even though the mouse has moved outside of the window. You call it on the WM_LBUTTONDOWN message notification.

WM_MOUSELEAVE not being generated when left mouse button is held

In my Win32 app, I don't get WM_MOUSELEAVE messages when I hold down the left mouse button and quickly move the mouse pointer out of the window. But If I, holding down the left mouse button, start from the inside of the window and move slowly past the window edge, it'll generate a WM_MOUSELEAVE.
If I don't hold the left mouse button, I get WM_MOUSELEAVE messages every time no matter how fast the mouse pointer moves off the window.
What's the difference? What can I do to handle both cases properly?
EDIT: If I left click and hold, move out of the window and then let go of the left mouse button I get the WM_MOUSELEAVE message. But it's way too late.
On Windows 7, I was trying to make an owner-drawn button. I subclassed the button in order to get more accurate mouseenter/mouseleave events, essentially. When doing this, I used TrackMouseEvent when I got a WM_MOUSEMOVE because this is only posted when the mouse is over the button. If not already set, I would then set a boolean to specify that the mouse is over the button as well as call TrackMouseEvent so that whenever the mouse left, I could unset my boolean. However, like you, I was not getting the WM_MOUSELEAVE when I pressed and held the left mouse button on the owner drawn button, then dragging the mouse out. Upon releasing the mouse outside of the button, I suddenly get the WM_MOUSELEAVE message - way too late.
I determined that the reason for this behavior was that the default button proc's handling for WM_LBUTTONDOWN calls SetCapture, and releases it later. The usage of SetCapture is what is breaking our reception of the WM_MOUSELEAVE event. However, as a side-effect of SetCapture being called, we will get WM_MOUSEMOVE events even if the control is not under the mouse. Thus, my workaround is duplicating the logic in WM_MOUSELEAVE in the WM_MOUSEMOVE handler to unset my boolean that indicates the mouse is over the button if I get a mousemove event that is outside of my button's area. If SetCapture isn't actually used inside WM_LBUTTONDOWN for the default button proc, then we'll already be getting our WM_MOUSELEAVE message and the code will still work... so this workaround works in both cases.
Your problem sounds like it is likely identical to mine, so hopefully this helps you.
WM_MOUSELEAVE is so that you can detect the mouse leaving your window when you don't have capture. When you have capture, you are responsible for detecting that yourself (if you care).
so It doesn't make any sense to SetCapture AND TrackMouseEvent at the same time, you would use one or the other.
Now, if it would be more convenient for you to see the WM_MOUSELEAVE messages while you have capture, it's a relatively simple matter to do that by yourself in your message pump.
You would just add code that looks something like this between the GetMessage() and the DispatchMessage() calls in your message pump.
GetMessage(pmsg, ...);
.....
if ((IS_WITHIN(pmsg->message, WM_MOUSEFIRST, WM_MOUSELAST) ||
IS_WITHIN(pmsg->message, WM_NCMOUSEMOVE, WM_NCMBUTTONDBLCLK)) &&
MyMouseLeaveDetection(pmsg, g_hwndNotifyMouseLeave))
{
MSG msg = *pmsg;
msg.message = WM_MOUSELEAVE;
msg.hwnd = g_hwndNotifyMouseLeave; // window that want's
msg.lParam = 0xFFFFFFFF;
g_hwndNotifyMouseLeave = NULL;
DispatchMessage (&msg);
}
.....
TranslateMessage(pmsg);
DispatchMessage(pmsg);
As waiting for a WM_MOUSELEAVE is unreliable, the best solution I've found is to directly look at the mouse position during a WM_MOUSEMOVE. I compare the mouse position against the client area and if the position is outside then I handle that as a mouse leave.
I also make sure to call SetCapture when the mouse position is within the client area and ReleaseCapture when it leaves.

Intercepting mouse clicks when the mouse is hovering above a control

I'm working on a MFC C++ dialog where I need to respond to right mouse click events for a dialog even if the mouse is hovering over a control.
I could write event handler code for each control to delegate the work to the parent dialog, but I'm hoping there is a more elegant solution?
I'm hoping there is some way to intercept the windows messages, but I'm still figuring that part out. I've tried listening to the WM_COMMAND messages with Spy++ but I didn't see what I needed.
Any suggestions?
You could set up a hook to intercept mouse messages. Take a look at SetWindowsHookEx and WH_MOUSE