开发者

Detect when mouse leaves my app

Hello I am creating an app in win32 that will display the x, y position(In screen coords) of the mouse whereever the mouse is (inside my app client/NC area & outside).

I am at the stage where I want to detect when the mouse leaves my application completely. I have written a simple win32 app that should detect & notify myself when the mouse leaves my app, BUT its not working, I never receive the messages WM_MOUSELEAVE & WM_NCMOUSELEAVE.

What do you think is wrong? Am I using the wrong win32 functions?

// Track Mouse.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <windows.h>
#include <vector>
#include <string>
#include <cstdlib>

static HINSTANCE gInstance;


// Globals //
enum   MouseStatus { DEFAULT = 50001, LEFT_CLIENT, LEFT_NCLIENT }; 
static MouseStatus mouseState = DEFAULT;
static COLORREF    bkCol      = RGB(0,255,255);

// Functions List //

BOOL TrackMouse( HWND hwnd )
{
    // Post:

    TRACKMOUSEEVENT mouseEvt;
    ZeroMemory( &mouseEvt, sizeof(TRACKMOUSEEVENT) );

    mouseEvt.cbSize      = sizeof(TRACKMOUSEEVENT);
    mouseEvt.dwFlags     = TME_LEAVE | TME_NONCLIENT;
    //mouseEvt.dwHoverTime = HOVER_DEFAULT;
    mouseEvt.hwndTrack   = hwnd;

    return TrackMouseEvent( &mouseEvt );
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch(msg)
    {
    case WM_CREATE:
        {               
            // Track mouse so I can be notified when it leaves my application (Client & NC areas)
            BOOL trackSuccess = TrackMouse( hwnd ); // Returns successful, so I correctly track the mouse

            if ( trackSuccess == 0 )
            {
                MessageBoxW( hwnd, L"Failed to track mouse", L"Error", MB_OK|MB_ICONEXCLAMATION );
            }
            else MessageBoxW( hwnd, L"Tracking mouse", L"Success", MB_OK|MB_ICONEXCLAMATION );
        }    
        break;
    case WM_MOUSELEAVE:
        {
            // I never receive this message

            // Detect when the mouse leaves the client area
            mouseState = LEFT_CLIENT;
            bkCol = RGB(50,50,50);
            InvalidateRect( hwnd, NULL, true );
        }
        break;
    case WM_NCMOUSELEAVE :
        {
            // I never receive this message

            // If the mouse has left the client area & then leaves the NC area开发者_高级运维 then I know
            // that the mouse has left my app
            if ( mouseState == LEFT_CLIENT )
            {
                mouseState = LEFT_NCLIENT;
                BOOL trackSuccess = TrackMouse( hwnd );

                if ( trackSuccess == 0 )
                {
                    bkCol = RGB(255,255,0);
                    MessageBoxW( hwnd, L"On WM_NCMOUSELEAVE: Failed to track mouse", L"Error", MB_OK|MB_ICONEXCLAMATION );
                }
                else MessageBoxW( hwnd, L"On WM_NCMOUSELEAVE: Tracking mouse", L"Success", MB_OK|MB_ICONEXCLAMATION );

                InvalidateRect( hwnd, NULL, true );
            }
        }
        break;
    case WM_ACTIVATE:
    case WM_MOUSEHOVER:
        {
            // The mouse is back in my app
            mouseState = DEFAULT;
            bkCol      = RGB(0,255,255);
            InvalidateRect( hwnd, NULL, true );
        }
        break;
    case WM_PAINT:
        {
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = BeginPaint( hwnd, &ps );

            SetBkColor( hdc, bkCol );
            Rectangle( hdc, 10, 10, 200, 200 );

            EndPaint( hwnd, &ps );
        }
        break;
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default: 
        break;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}


int WINAPI WinMain(HINSTANCE gInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;


    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = gInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(DKGRAY_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = L"Custom Class";
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    // if registration of main class fails
    if(!RegisterClassEx(&wc))
    {
        MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        L"Custom Class",
        L"App Name",
        WS_CAPTION|WS_MINIMIZEBOX|WS_VISIBLE|WS_OVERLAPPED|WS_SYSMENU,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 500,
        NULL, NULL, gInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}


The key component your missing is SetCapture(hwnd); which directs all mouse messages to that hwnd until you call ReleaseCapture();

HANDLE_DLGMSG(hwnd, WM_RBUTTONDOWN,     SKDemo_OnRButtonDown);
HANDLE_DLGMSG(hwnd, WM_MOUSEMOVE,       SKDemo_OnMouseMove);
HANDLE_DLGMSG(hwnd, WM_RBUTTONUP,       SKDemo_OnRButtonUp);

void SKDemo_OnRButtonDown (HWND hwnd, BOOL fDbClk, int x, int y, UINT keyFlags)
{
     // Force all mouse messages to come to this window.
     SetCapture(hwnd);

     // Change the mouse cursor to eyes. This provides a visual indication
     // to the user that Voyeur is "peering."
     SetCursor(LoadCursor(GetWindowInstance(hwnd),
        MAKEINTRESOURCE(IDC_POINTER)));
}

void SKDemo_OnMouseMove (HWND hwnd, short x, short y, UINT keyFlags) 
{
    if( GetCapture() == NULL ) {
        return;
    }
// do something with the message here
}

void SKDemo_OnRButtonUp (HWND hwnd, int x, int y, UINT keyFlags) 
{
   ReleaseCapture();
}


I think you need the mouse to be over your window before you all TrackMouseEvent. Try calling whilst you handle a mouse move message.


As written in Win32 documentation, the request expires each time the mouse leaves the window. So you need to call TrackMouseEvent also in your WM_MOUSELEAVE handler. Note also that if the mouse isn't in your window at the time TrackMouseEvent is called, WM_MOUSELEAVE is generated immediately.


The win32 API is more or less ridiculous. It doesn't have a mouse enter/leave. A google search for "MFC mouse enter leave" turned up this:

http://www.codeproject.com/KB/cpp/mouseenterleave.aspx

Note that MFC is just a thin wrapper around win32 proper. You can basically take any member function of a WND and call a C function with the exact same name and HWND as first parameter...the rest being all exactly the same.

Have fun. This kind of crap is why I hate all things win32.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜