2011-02-04 21 views
3

こんにちは私はWin32で、マウスが(私のアプリケーションクライアント/ NCエリア&の外側に)マウスのx、y位置(画面座標で)を表示するアプリケーションを作成しています。マウスが私のアプリケーションを離れるときを検出する

私はマウスが私のアプリケーションを完全に離れるときを検出したい段階にあります。私は&がマウスが私のアプリを離れるときに自分自身に通知するが、動作していない、WM_MOUSELEAVE & WM_NCMOUSELEAVEというメッセージを受信しないことを検出する単純なwin32アプリを書いた。

あなたはどう思いますか?間違ったwin32関数を使用していますか?

// 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; 
} 

答えて

2

私はあなたのマウスはあなたのすべてTrackMouseEvent前に、あなたの窓の上にあることする必要があると思います。マウスの移動メッセージを処理しているときに電話をかけてみてください。

-4

win32 APIは多分ばかげています。マウスの出入りはありません。 MFCは、周りだけ薄いラッパーで、適切なWin32のこと

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

注:「まま入力しますMFCマウス」のためのGoogle検索では、これを上がって。あなたは基本的にWNDの任意のメンバ関数を取り、最初のパラメータと全く同じ名前とHWNDを持つC関数を呼び出すことができます。残りはまったく同じです。

楽しんでください。この種の駄目は私がすべてのものを憎む理由です。

+4

私は同意しません。 Win APIは優れています。基本的には25年ほど経ちました。もちろん、それにはいくつかのしわがありますが、基本的なデザインはまだ機能しており、まだ機能しています。何年にもわたって何かをデザインしたことがあり、決してデザインの選択肢を後悔しませんでしたか? –

+0

このようなものを除くすべての井戸と良いものは、彼らの必要性が明らかになったときに非常に簡単に追加できました。 –

+2

いいえ、[マウス離脱](http://msdn.microsoft.com/en-us/library/ms645615%28v=vs.85%29.aspx)があります。マウス入力は[最初のマウス移動イベント]です(http://blogs.msdn.com/b/oldnewthing/archive/2003/10/13/55279.aspx)。 –

3

重要なコンポーネントあなたの欠落は、Win32のドキュメントに書かれたとして、あなたは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(); 
} 
+1

OPは、マウスを捕捉することなくマウスを入力してウィンドウを離れることを検出することができますが、これはかなり侵略的な手順です。もちろん、ウィンドウがフォアグラウンドのときだけキャプチャできます。 –

+0

@DavidHeffernan: 'TrackMouseEvent'の実装はOSのバージョンによって異なりますが、それらのいくつかはまさにこれを行います:マウスをウィンダウンに入れたままキャプチャし、マウスが動いたときにリリースします。マウスをキャプチャする前景ウィンドウである必要はありません、マウスはウィンドウの上にある必要があります。このアプローチはうまくいくはずです。もしあなたが礼儀正しく、ウィンドウを離れたマウスの動きを再投稿すれば、それはあまり侵略的ではありません。 –

+0

@AdrianMcCarthy:私はこれが正しいとは思わない。 [SetCapture](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646262)のドキュメントを参照してください。aspx):* "フォアグラウンドウィンドウだけがマウスをキャプチャできます" *マウスをキャプチャすることによって 'TrackMouseEvent'を実装する単一のOSはありません。フォアグラウンドウィンドウではないウィンドウであっても、 'TrackMouseEvent'がすべてのOSで機能するので、これは容易に確認できます。ロジックは、これを実装するために 'SetCapture'を使うことはできません。 – IInspectable

1

を呼び出すまで、そのHWNDに、すべてのマウスメッセージを指示したSetCapture(hwnd);で、要求は、マウスがウィンドウを離れるたびに満了します。したがって、WM_MOUSELEAVEハンドラでもTrackMouseEventを呼び出す必要があります。 TrackMouseEventが呼び出された時点でマウスがウィンドウ内にない場合は、すぐにWM_MOUSELEAVEが生成されます。

関連する問題