Shoutbox

[?] WM_MOUSEMOVE doesn't work - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: [?] WM_MOUSEMOVE doesn't work (/showthread.php?tid=94403)

[?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-18-2010 at 07:24 AM

I seem to have a problem detecting mouse movement through WM_MOUSEMOVE. Is there a problem with my script or this message?

The point is: I want to check whether the mouse is over a control or not. I suppose that can be done with this message?


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-18-2010 at 03:01 PM

Likely just a problem with your code. Post what you have and lets take a look.


RE: RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-18-2010 at 05:50 PM

quote:
Originally posted by matty
Likely just a problem with your code.

You're right about that. I have solved it, but now there's another problem: I cannot press any button in the window. In fact, the window behaves as if it were disabled. It gets enabled when the window is deactivated (i.e. minimised) and activated again. Can it be that this has something to do with the SetCapture function?

Figured a lot out: SetCapture causes a window to detect mouse movement, but disables most of its other input stuff. However, not using SetCapture means you cannot detect mouse movement. The disabled-like behaviour is caused by SetCapture. Minimising and restoring position releases capture from the window and allows you to click buttons, etc.

But I still need to detect mouse movement :P

Post no. 700 :o)
RE: [?] WM_MOUSEMOVE doesn't work by CookieRevised on 04-19-2010 at 01:08 AM

Don't use SetCapture for that, because it has some drawbacks and limitations as you have experienced.

SetCapture is meant to be used when you do an action with your mouse. Thus when you already have detected mouse movement over a control. Eg: you invoke it when you press (and hold) a mouse button inside a drawing control to draw lines. It is not meant to track mouse movement to see if you hoover over a control. For that you need _TrackMouseEvent.

http://www.mvps.org/user32/setcapture.html
http://msdn.microsoft.com/en-us/library/ms646266(v=VS.85).aspx
http://msdn.microsoft.com/en-us/library/ms645602(...px#tracking_cursor


RE: RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-19-2010 at 07:12 PM

quote:
Originally posted by MSDN page about _TrackMouseEvent
dwFlags
    DWORD

    Specifies the services requested. This member can be a combination of the following values.

[DWORD values]



There is nothing like TME_ENTER that is fired when the mouse leaves a control. Or do I need to use TME_HOVER for that...?

Surprise, surprise: been messing around a little, and don't get it :s

Problem could be that I've worked from 5 to 8 after school ;)
RE: [?] WM_MOUSEMOVE doesn't work by CookieRevised on 04-20-2010 at 02:05 AM

quote:
Originally posted by SmokingCookie
quote:
Originally posted by MSDN page about _TrackMouseEvent
dwFlags
    DWORD

    Specifies the services requested. This member can be a combination of the following values.

[DWORD values]



There is nothing like TME_ENTER that is fired when the mouse leaves a control. Or do I need to use TME_HOVER for that...?
To detect the mouse leaving the area you're tracking you need to specify TME_LEAVE.


quote:
Originally posted by SmokingCookie
Surprise, surprise: been messing around a little, and don't get it :s

Problem could be that I've worked from 5 to 8 after school ;)
get some sleep first, then read those links I gave ;) :p
RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-20-2010 at 02:10 PM

Well, I'll never do ANY kind of programming/scripting after a full day of school and work, before going to bed. I've been busy with this all night long :S :P

But that's had positive consequences too. I've thought of the following theory: upon a call to _TrackMouseEvent, <some message>* will be posted to the window when the mouse moves over it. When the mouse leaves the window, some other message is posted.

* Can this be WM_MOUSEMOVE?


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 02:52 PM

We used WM_MOUSEMOVE in Screenshot Sender.

http://beta.screenshotsender.com/code/WindowHandl...ectArea_handler.js

Tried something like this?

Javascript code:
/* Create your window*/
pPlusWnd.RegisterMessageNotification(0x02A1 /* WM_MOUSEHOVER */)
var TRACKMOUSEEVENT = Interop.Allocate(16);
    TRACKMOUSEEVENT.WriteDWORD(0, 16);
    TRACKMOUSEEVENT.WriteDWORD(4, 0x1 /* TME_HOVER */);
    TRACKMOUSEEVENT.WriteDWORD(8, pPlusWnd.GetControlHandle('myControl'));
    TRACKMOUSEEVENT.WriteDWORD(12, 1);
 
function OnWindowSubClassEvent_MessageNotification(pPlusWnd, nMessage, wParam, lParam) {
    switch (nMessage) {
        case 0x02A1 /* WM_MOUSEHOVER */:
            Debug.Trace('i r on your control');
    }
}


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-20-2010 at 04:08 PM

JScript code:
// Windows.js;
 
objPlusWnd.RegisterMessageNotification(WM_MOUSEHOVER,true);
var TRACKMOUSEEVENT = Interop.Allocate(16);
with(TRACKMOUSEEVENT) {
    writeDWORD(0,Size);
    writeDWORD(4,TME_HOVER);
    writeDWORD(8,objPlusWnd.GetControlHandle("BtnViewPage"));
    writeDWORD(12,1);
}
Interop.Call("Comctl32.dll","_TrackMouseEvent",TRACKMOUSEEVENT.DataPtr);
//Interop.Call("User32.dll","TrackMouseEvent",TRACKMOUSEEVENT.DataPtr);
TRACKMOUSEEVENT.Size = 0;
 
// WndSettings_Notif.js;
 
function OnWndSettings_NotifEvent_MessageNotification(PlusWnd,Message,wParam,lParam) {
    if(Hotkey_HandleEvent(PlusWnd,Message,wParam,lParam)) return -1;
    switch(Message) {
        case WM_MOUSEHOVER:
            Print("i r on ur control");
        return 0;
    }
}


But it ain't exactly working... :S
RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 04:25 PM

What is the return value of the TrackMouseEvent call?

What about tracking WM_MOUSEMOVE and use GetCursorPos then use ChildWindowFromPoint comparing the hWnd of the control to that returned from the function?


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-20-2010 at 04:32 PM

I've got the return value 1, suggesting it should work.


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 04:41 PM

This example is from here: http://www.codeguru.com/forum/showthread.php?t=290195

C++ code:
//////////// Globals ////////////
// HWND hWndBtn1 = NULL;
// HWND hWndBtn2 = NULL;
// WNDPROC wpOrigButtonProc = NULL;
// HBITMAP hBmpNormal = NULL;
// HBITMAP hBmpHiLight = NULL;
// BOOL bMouseInWindow = FALSE;
 
// IDC_DLGBTN1 is a button resource
// IDC_DLGBTN2 is a button resource
// IDB_BMP_NORMAL is a bitmap resource
// IDB_BMP_HILIGHT is a bitmap resource
 
// in WM_INITDIALOG of main dialog procedure
hWndBtn1 = GetDlgItem(hWnd, IDC_DLGBTN1);
hWndBtn2 = GetDlgItem(hWnd, IDC_DLGBTN2);
     // load bitmaps
hBmpNormal  = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BMP_NORMAL));
hBmpHiLight = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BMP_HILIGHT));
     // set initial button images        
SendMessage(hWndBtn1, BM_SETIMAGE,
          (WPARAM)IMAGE_BITMAP, (LPARAM)hBmpNormal );
SendMessage(hWndBtn2, BM_SETIMAGE,
          (WPARAM)IMAGE_BITMAP, (LPARAM)hBmpNormal);
     // subclass buttons            
wpOrigButtonProc = (WNDPROC) SetWindowLong(hWndBtn1,
          GWLP_WNDPROC, (LONG) NewButtonProc);
/* same original btn proc */ SetWindowLong(hWndBtn2,
          GWLP_WNDPROC, (LONG) NewButtonProc);
 
// in WM_CLOSE of main dialog procedure
SetWindowLong(hWndBtn1, GWLP_WNDPROC, (LONG)wpOrigButtonProc);
SetWindowLong(hWndBtn2, GWLP_WNDPROC, (LONG)wpOrigButtonProc);
 
// NewButtonProc window procedure
LRESULT CALLBACK NewButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
     switch(uMsg)
     {
          case WM_MOUSEMOVE:
          {            
               if (!bMouseInWindow)
               {
                    bMouseInWindow = true;
                    SendMessage(hWnd, BM_SETIMAGE,
                         (WPARAM)IMAGE_BITMAP, (LPARAM)hBmpHiLight );
                    TRACKMOUSEEVENT tme;
                    tme.cbSize = sizeof(tme);
                    tme.dwFlags = TME_LEAVE;
                    tme.hwndTrack = hWnd;
                    TrackMouseEvent(&tme);
               }
          }
          break;
          case WM_MOUSELEAVE:
          {
               bMouseInWindow = false;
               SendMessage(hWnd, BM_SETIMAGE,
                    (WPARAM)IMAGE_BITMAP, (LPARAM)hBmpNormal);
          }
          break;
          default:
               return CallWindowProc(wpOrigButtonProc, hWnd,
                    uMsg, wParam, lParam);
     }
     return true;
}


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-20-2010 at 04:43 PM

Gotta admit that I'm absolutely rubbish at C++, but I'll give it a try...


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 04:46 PM

It is simply saying to declare the event from within WM_MOUSEMOVE but not sure why it should matter...

Anyways:

quote:
Originally posted by matty
What about tracking WM_MOUSEMOVE and use GetCursorPos then use ChildWindowFromPoint comparing the hWnd of the control to that returned from the function?

RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-20-2010 at 04:50 PM

Well, I've got my own version of ChildWindowFromPoint. But the entire problem is the "tracking WM_MOUSEMOVE": I am not receiving it at all.


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 05:19 PM

quote:
Originally posted by SmokingCookie
Well, I've got my own version of ChildWindowFromPoint. But the entire problem is the "tracking WM_MOUSEMOVE": I am not receiving it at all.
That has to be something in your code then.

Attachment is untested as I am at work but let me know.

Not sure if it will work because I think the x and y coordiniates are in relation to the window not the screen. If this is the case then change the subclass routine to

Javascript code:
function OnwndSubclassEvent_MessageNotification(pPlusWnd, nMessage, wParam, lParam) {
    switch (nMessage) {
        case WM_MOUSEMOVE:
            var POINT = Interop.Allocate(8);
            Interop.Call('user32', 'GetCursorPos', POINT);
                           
            var r = Interop.Call('user32', 'ChildWindowFromPointW', pPlusWnd.Handle, POINT);
            if (r !== null)
                Debug.Trace('i r on a control: '+r);
           
            return -1; // Process the message little one
    }
}


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-20-2010 at 05:23 PM

Got bad news for ya: it does not work. No message notifications are received.

Oh and btw:

quote:
Originally posted by MSDN article on WM_MOUSEMOVE
Return Value

If an application processes this message, it should return zero.

RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 05:24 PM

Check the update :)


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-20-2010 at 05:25 PM

Nope, still the same


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 05:28 PM

quote:
Originally posted by SmokingCookie
Oh and btw:

quote:
Originally posted by MSDN article on WM_MOUSEMOVE
Return Value

If an application processes this message, it should return zero.

The -1 allows the window itself to process the message. The window will return 0.

I will investigate when I get home. This works fine with Screenshot Sender.
RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-20-2010 at 09:26 PM

Add this. All will be good :)

XML code:
        <Attributes>
            <LockOnClick>False</LockOnClick>
        </Attributes>


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-21-2010 at 02:58 PM

But.. That disables moving the window, right? And besides, I get tons of notification messages with the LockOnClick thingy, except when the mouse is over a control.


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-21-2010 at 04:35 PM

quote:
Originally posted by SmokingCookie
But.. That disables moving the window, right? And besides, I get tons of notification messages with the LockOnClick thingy, except when the mouse is over a control.
It will disable moving the window yes. Sorry I wasn't clear in my post. I didn't spend the time trying to figure out what control the cursor was on. I can take a look later if you cannot figure it out.
RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-21-2010 at 05:40 PM

The other possibility is to create regions for different buttons and monitor the position of the cursor when it is on the window. That is quite intense though.


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-21-2010 at 07:38 PM

Regions? Never really heard of that, I think...

The attachment includes an example of what I want to do with this. It's written in MS Visual C# Express 2010.


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-22-2010 at 12:27 AM

Good news... bad news...

Good news is I managed to get it to work with the Plus! Window. Unfortunately I can't see how it will work with controls.

Javascript code:
var WM_MOUSEMOVE = 0x200;
var WM_MOUSEHOVER = 0x02A1;
var TME_HOVER = 1;
var wndSubclass;
 
function OnEvent_Initialize() {
    if (Messenger.MyStatus < STATUS_INVISIBLE) return false;
    Debug.DebuggingWindowVisible = true;
    wndSubclass = MsgPlus.CreateWnd('wndSubclass.xml', 'wndSubclass');
    wndSubclass.RegisterMessageNotification(WM_MOUSEMOVE);
    wndSubclass.RegisterMessageNotification(WM_MOUSEHOVER);
}
 
function OnEvent_SigninReady() {
    OnEvent_Initialize();
}
 
function OnwndSubclassEvent_MessageNotification(pPlusWnd, nMessage, wParam, lParam) {
    switch (nMessage) {
        case WM_MOUSEMOVE:
            Debug.ClearDebuggingWindow();
            Debug.Trace('WM_MOUSEMOVE');
            var TRACKMOUSEEVENT = Interop.Allocate(16);
            with(TRACKMOUSEEVENT) {
                WriteDWORD(0, Size);
                WriteDWORD(4, TME_HOVER);
                WriteDWORD(8, pPlusWnd.Handle);
                WriteDWORD(12, 1);
            }
            Interop.Call('user32','TrackMouseEvent',TRACKMOUSEEVENT.DataPtr);
            return -1; // Process the message little one
        case WM_MOUSEHOVER:
            Debug.ClearDebuggingWindow();
            Debug.Trace('WM_MOUSEHOVER');
            return -1;
    }
}


[Image: attachment.php?pid=992973]
RE: [?] WM_MOUSEMOVE doesn't work by CookieRevised on 04-22-2010 at 04:14 AM

I'll try to explain a few things. Because some misconceptions have cropped up and stuff Matty posted didn't work because of certain things and the 'fixes' for them weren't the proper fixes, and they introduced other misconceptions...


(1)

A window has a client area and a non-client area.
The non-client area of a standard window in Windows is the title/caption bar (plus the borders).
Clicking and holding the button in the caption area of the non-client area of a window and you can move the window for example.

Plus!, by default, flags the whole window as the non-client area, making it possible to click anywhere to move the window (can be disabled by setting LockOnClick to false).

WM_MOUSEMOVE (and other notifications like this), only work in the client area. For the non-client area you need to use other notifications! eg: WM_NCMOUSEMOVE, WM_NCLBUTTONDOWN, etc...

In short, instead of setting LockOnClick to false, use WM_NCMOUSEMOVE.

So, refering back to this post from Matty: it wouldn't work because:
a) WM_NCMOUSEMOVE should have been used when LockOnClick is true (default).
b) the syntax of the ChildWindowFromPoint is wrong. The POINT structure must be passed literally, not as an object reference. See attached script for correct syntax.
c) ChildWindowFromPoint expects coordinates in client coordinates. Matty forgot to convert the screen coordinates from the cursor into client coordinates.
d) see (2)

this post of Matty (setting LockOnClick to false) would only solve point a.

If the four points above would have been correct, that little script would have worked correctly, except for the fact that:

(2)

Since a button control is a window on its own, you wont get any notifications when you move (or hoover) over the button control though.

You need to subclass that button control instead to get a MOUSEMOUVE notification when you move over that control. But this not possible in Plus! without an external DLL.

---------

(3)

Note that detecting WM_NOTIFY, WM_PRINTCLIENT and WM_CTLCOLORBTN messages, send to the parent window, can also be used to detect the mouse entering and leaving a button on the Plus! window. Unfortunalty you can't distinct entering or leaving with these APIs alone.

WM_PRINTCLIENT gives the hDC of the button
WM_NOTIFY gives the control/window id
WM_CTLCOLORBTN gives the hDC and hWnd of the button (use this one as the hWnd is the most easiest to check on)


However, this isn't detecting hovering though. But it might be a solution depending on what you exactly want.

---------

(4)

If all else fails, you could use a timer and check the mouse coordinates if they are in the button's view port coordinates and if the parent window is in the foreground. If so, you are over the button. Another timer can then be used to detect the 'hovering'.

---------

(5)

Of course, using (4) requires constant polling and we all know how we hate that ;p

But you can combine the advantages of (3)(check on WM_CTLCOLORBTN) and (4)(check coordinates) together so you don't have the disadvantage of pure (4)(constant polling with timers) and the problem of (2)(no MOUSEMOVE event when you are on a child control):

When you detect WM_CTLCOLORBTN, check the mouse coordinates against the button's view port and you know if the mouse is over the button or not.

Beware though, with this method, the final event (the debug messages in the example script) is also fired when the window is put in focus and out of focus (eg: <alt><tab>). This shouldn't be a problem in general, but for certain stuff (dunno exactly what you're going to do) it might be troublesome.

See attachment for a crude script using this method. Only the cancel button will generate the "I ENTERED"/"I LEFT" debug messages, not the Start button, neither the minimize or close button.

PS: In this script I have also included the WM_NCMOUSEMOVE notification, and the MOUSETRACK events to show how they work. You don't need those for this method to work though....

Hopefully this long jabber isn't too confusing or too messy. And hopefully you'll eventually find a solution for what you want to do... :p


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-22-2010 at 01:02 PM

Looks good Cook! Thanks for the explanation. I couldn't seem to come up with a message that was sent to the parent that we could act on.


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-23-2010 at 11:40 AM

Not supposed to be online now; at school.

Anyways, cannot download Cookie's attachment, so I'll take a look at it later today, or tomorrow. Meanwhile, what exactly does it do?


RE: [?] WM_MOUSEMOVE doesn't work by matty on 04-23-2010 at 11:42 AM

Captures mouse enter/leaving of a button.


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 04-24-2010 at 09:16 AM

@ CookieRevised: I've made a similar implementation of your script, yet I've got a problem with it. It works fine until the window is deactivated. When the window is activated again, it works for controls within the parent window, but not for controls in a child window.


RE: [?] WM_MOUSEMOVE doesn't work by CookieRevised on 04-24-2010 at 01:31 PM

You probably need to subclass that child window because it is this child window which is the parent for the control on it.

small additional note: it might be possible that using WM_CTLCOLORBTN wont work anymore in the future though. Because this greatly depends on how Plus! paints its stuff. So, if that changes (eg: in version 5, dunno), this whole method might not work either.

Oh, and this is only tested on a button control. Other controls might not work.


RE: [?] WM_MOUSEMOVE doesn't work by SmokingCookie on 05-01-2010 at 10:40 AM

I've added the message notification stuff to the child window as well, but that doesn't make any difference.

There's a slight delay between the mouse entering the button's client area and the actual showing of the StaticControl. However, it doesn't work every time. I don't really know how to reproduce the error, other than just bringing another window to the foreground.