web-dev-qa-db-ja.com

すべてのコンポーネントからのマウスイベントのキャプチャ

WinForm C#アプリケーションでMouseEventsに問題があります。

アプリケーションでallマウスクリックを取得したいのですが、すべての子コンポーネントにリスナーを配置し、Windowsマウスフックを使用したくありません。

Flashでは、リスナーをステージに配置して、映画のすべてのMouseEventを取得できます。

C#にそのようなものはありますか?グローバルなMouseListener?


編集:

このクラスはIMessageFilterから作成し、Application.AddMessageFilterを使用しました。

public class GlobalMouseHandler : IMessageFilter{

    private const int WM_LBUTTONDOWN = 0x201;

    public bool PreFilterMessage(ref Message m){
        if (m.Msg == WM_LBUTTONDOWN) {
            // Do stuffs
        }
        return false;
    }
}

そして、このコードを、グローバルクリックをリッスンする必要があるコントロールに配置します。

GlobalMouseHandler globalClick = new GlobalMouseHandler();
Application.AddMessageFilter(globalClick);
30
Gustavo Cardoso

これを行う簡単な方法の1つは、Application.AddMessageFilterを呼び出し、IMessageFilterインターフェースを実装するクラスを記述することにより、メッセージループフィルターを追加することです。

IMessageFilter.PreFilterMessageを介して、クラスはアプリケーションのメッセージループを通過するすべての入力メッセージを確認できます。 PreFilterMessageは、これらのメッセージを宛先の特定のコントロールに渡すかどうかも決定します。

このアプローチがもたらす複雑さの1つは、PreFilterMessageメソッドに渡されるMessage構造体を介してWindowsメッセージを処理する必要があることです。これは、従来のMouseDownMouseMoveおよびMouseUpイベントではなく、WM\_LBUTTONDOWN, WM\_MOUSEMOVEWM\_LBUTTONUPなどに関するWin32ドキュメントを参照することを意味します。

15
Tim Robinson

サンプルクラス

class CaptureEvents : IMessageFilter
{
    #region IMessageFilter Members
    public delegate void Callback(int message);
    public event Callback MessageReceived;

    IntPtr ownerWindow;
    Hashtable interestedMessages = null;
    CaptureEvents(IntPtr handle, int[] messages)
    {
        ownerWindow = handle;
        for(int c = 0; c < messages.Length ; c++)
        {
            interestedMessages[messages[c]] = 0;
        }
    }
    public bool PreFilterMessage(ref Message m)
    {
        if (m.HWnd == ownerWindow && interestedMessages.ContainsKey(m.Msg))
        {
            MessageReceived(m.Msg);
        }
        return true;
    }

    #endregion
}
5
Renjith V

この記事をご覧ください 。すべてのコントロールイベントを再帰的にフックし、ブロードキャストします。フォームで WndProc をオーバーライドすることもできます。

3
JP Alioto

Form.PreProcessMessageまたはForm.WndProcをオーバーライドしてメッセージを処理しない場合は、Formをサブクラス化して、フォーム上のさまざまなコントロールからのすべてのMouseClickイベントにイベントハンドラーをフックできます。
編集:フォーム上のコントロールの子コントロールを再帰するのを忘れました。

    public class MousePreviewForm : Form
    {
      protected override void OnClosed(EventArgs e)
      {
         UnhookControl(this as Control);
         base.OnClosed(e);
      }

      protected override void OnLoad(EventArgs e)
      {
         base.OnLoad(e);

         HookControl(this as Control);
      }

      private void HookControl(Control controlToHook)
      {
         controlToHook.MouseClick += AllControlsMouseClick;
         foreach (Control ctl in controlToHook.Controls)
         {
            HookControl(ctl);
         }      
      }

      private void UnhookControl(Control controlToUnhook)
      {
         controlToUnhook.MouseClick -= AllControlsMouseClick;
         foreach (Control ctl in controlToUnhook.Controls)
         {
            UnhookControl(ctl);
         }
      }

      void AllControlsMouseClick(object sender, MouseEventArgs e)
      {
         //do clever stuff here...
         throw new NotImplementedException();
      }
   }

フォームは、System.Windows.Forms.Formではなく、MousePreviewFormから派生する必要があります。

3
Hamish Smith