0
votes

I'm trying to catch mouse hovering over the buttons in my window, which I'm programming using plain C++14 in MSVS19 and WinAPI. Here's the code snippet and some context:

  • isTracking is defined as bool earlier
  • hBox is a button created in WM_CREATE using CreateWindowW
    hBox = CreateWindowW(WC_BUTTON, L"TEST BOX", WS_TABSTOP | WS_VISIBLE | WS_CHILD, 300, 250, 100, 33, hWnd, (HMENU)IDC_BUTN10, NULL, NULL);
  • hWnd is a handle to window that a CALLBACK WndProc function receives

        case  WM_MOUSEMOVE:
    {
        HWND hTrack = hBox;
        if (!isTracking) {
            TRACKMOUSEEVENT tme = {};
            tme.cbSize = sizeof(TRACKMOUSEEVENT);
            tme.dwFlags = TME_HOVER | TME_LEAVE;
            tme.hwndTrack = hTrack;
            tme.dwHoverTime = HOVER_DEFAULT;
            TrackMouseEvent(&tme);
            isTracking = true;
        }
            break;
    }
    
    case WM_MOUSEHOVER:
    {
        OutputDebugStringW(L"HOVER\n");
        MessageBox(nullptr, L"Entered", L"Info", MB_OK);
        break;
    }
    
    case WM_MOUSELEAVE:
    {
        isTracking = false;
        MessageBox(nullptr, L"Left", L"Info", MB_OK);
        break;
    
    }
    

And it doesn't work.

However when I set hTrack to hWnd - it detects hovering over main window area (but not over any of the children) and creates message boxes.

I've tried hTrack = GetDlgItem(hWnd,IDC_BUTN10) too - but it doesn't work either for that element or any other. Only hWnd itself gets any reaction from the program - but I want to detect hovering over specific buttons and other UI elements.

1
Not sure if I understand this correctly, but there is a main window and there is a second window (hBox). You are trying to move and track mouse in hBox which isn't happening. What I can think of (can be incorrect though) is that hBox isn't the top level window (or isn't active, not sure the correct phrase for that) because of which the mouse isn't being tracked. - kiner_shah
From reading the documentation it seems that the messages are sent to the window you're tracking. I.e. in your case the events are sent to hBox. - Some programmer dude
The documentation for TRACKMOUSEEVENT has the following on the dwFlags member: "TME_HOVER [...] This flag is ignored if the mouse pointer is not over the specified window or area." I'm not convinced that this is accurate, though if it is then that's likely what's causing your issues. I find that a bit hard to believe, though, as that would essentially mean that there's no way to use TrackMouseEvent for a child window without subclassing that child window. - IInspectable
@IInspectable That is exactly what you would have to do. Subclass the button to intercept its own WM_MOUSEMOVE messages to trigger hover/leave tracking while the mouse is over the button. - Remy Lebeau

1 Answers

0
votes

I tested it using your code, and I succeeded in implementing the functionality you wanted. Maybe you are using the message callback incorrectly, you can refer to my code.

BOOL TestDlg::PreTranslateMessage(MSG* pMsg)
{
switch (pMsg->message)
{
    case  WM_MOUSEMOVE:
    {
        HWND hTrack = hBox;
        if (!isTracking) {
            TRACKMOUSEEVENT tme = {};
            tme.cbSize = sizeof(TRACKMOUSEEVENT);
            tme.dwFlags = TME_HOVER | TME_LEAVE;
            tme.hwndTrack = hTrack;
            tme.dwHoverTime = HOVER_DEFAULT;
            TrackMouseEvent(&tme);
            isTracking = true;
        }
        break;
    }

    case WM_MOUSEHOVER:
    {
        OutputDebugStringW(L"HOVER\n");
        ::MessageBox(nullptr, L"Entered", L"Info", MB_OK);
        break;
    }

    case WM_MOUSELEAVE:
    {
        isTracking = false;
        //::MessageBox(nullptr, L"Left", L"Info", MB_OK);
        break;

    }

}
return CDialogEx::TestDlg(pMsg);
}