Mesoscopic Programming

タコさんプログラミング専門

Programming Tips #1 子ウィンドウのマウスイベント

はじめに

開発中に気づいた事などあとで書こうと思っていても、プログラミング講座の方だと忘れてたりすでに疲れきっていて書けないことが多い。
そこで気づいたらすぐ書くシリーズを始めました。


子ウィンドウのマウスイベント

ツリービューを作っていて分かったのだ。子ウィンドウ側で個別にマウスイベントを親へ通知するのは無理があると。
それはツリービュークラスの子ウィンドウであるツリービューコントロールのマウスイベントを検知する必要から判明した。
結局、コントロールのマウスイベントを検知しようとするとコントロールのウィンドウプロシージャをフックしなければならないからだ。
そんなことをするぐらいなら最上層でフックした方がいいに決まってる。
そこでメインループでマウスイベントをフックするように変更しました。

メインループ

以下はアプリケーションクラスのメッセージループ関数である。

int App :: Run()
{
    MSG msg;

    while ( GetMessage( & msg, NULL, 0, 0 ) )
    {
        if ( TranslateAccelerator( hwnd, hAccel, & msg ) == 0 )
        {
            if ( ! HookMessage( & msg ) )
            {
                TranslateMessage( & msg );
                DispatchMessage( & msg );
            }
        }
    }

    DestroyAcceleratorTable( hAccel );

    return ( int ) msg.wParam;
}

キーボードアクセラレータのあとにメッセージを各ウィンドウに渡す前にフック処理を実行している。
ここならばコントロールを含むすべての子ウィンドウに対するメッセージを検知可能である。

フック関数

メッセージの種類と宛先をチェックして必要なフック処理を実施する。

BOOL App :: HookMessage( LPMSG pmsg )
{
    NMMOUSE nmMouse;

    if ( IsChild( hwnd, pmsg->hwnd ) && ( pmsg->message == WM_MOUSEMOVE || pmsg->message == WM_NCMOUSEMOVE ) )
    {
        ZeroMemory( & nmMouse, sizeof nmMouse );

        nmMouse.hdr.hwndFrom = pmsg->hwnd;
        nmMouse.hdr.idFrom   = GetDlgCtrlID( pmsg->hwnd );
        nmMouse.hdr.code     = WM_MOUSEMOVE;

        GetCursorPos( & nmMouse.pt );

        if ( SendMessage( hwnd, WM_NOTIFY, pmsg->wParam, ( LPARAM ) & nmMouse ) )
        {
            return TRUE;
        }
    }

    return FALSE;
}

今回はマウス移動イベントだけが必要なので子ウィンドウ宛てのメッセージをチェックしている。
但しコンボボックスコントロールなどでは、非子ウィンドウがマウスをキャプチャしているので注意が必要である。