views:

4719

answers:

3

I have a problem with MouseEvents on my WinForm C# application. I want to get ALL mouse clicks on my application, but I don't want to put a listener in every child component neither use Windows mouse hook.

On Flash I could put a listener on Stage to get all the MouseEvents on the movie. Is there such thing on C#? A global MouseListener?


Edit: I create this class from IMessageFilter ans used 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;
 }
}

And put this code on the Controls that need listen global clicks:

GlobalMouseHandler globalClick = new GlobalMouseHandler();
Application.AddMessageFilter(globalClick);

Thank you for the help!

+5  A: 

One straightforward way to do this is to add a message loop filter by calling Application.AddMessageFilter and writing a class that implements the IMessageFilter interface.

Via IMessageFilter.PreFilterMessage, your class gets to see any inputs messages that pass through your application's message loop. PreFilterMessage also gets to decide whether to pass these messages on to the specific control to which they're destined.

One piece of complexity that this approach introduces is having to deal with Windows messages, via the Message struct passed to your PreFilterMessage method. This means referring to the Win32 documention on WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP etc, instead of the conventional MouseDown, MouseMove and MouseUp events.

Tim Robinson
Thank you for the help! Everything works right.I used Application.AddMessageFilter with suscess. I hook the mouse events and create a C# MouseEventHandler to dispatch the event on WinForm level to other controls.
Gustavo Cardoso
+1  A: 

Take a look at this article. It recursively hoooks all the control events and broadcasts them. You could also override WndProc in your form.

JP Alioto
I tried to override WinProc, but ended with the same problem: mouse clicks were only catch when I clicked directly over the form. If I clicked on a child Control Winproc was not called.
Gustavo Cardoso
+2  A: 

If you don't want to handle the messages by overriding Form.PreProcessMessage or Form.WndProc then you could subclass Form to hook an event handler to all the MouseClick events from the various controls on the form.
EDIT: forgot to recurse through child controls of controls on the form.

    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();
      }
   }

Your forms would then need to derive from MousePreviewForm not System.Windows.Forms.Form.

Hamish Smith
You could even use the Form.OnControlAdded event to apply the AllControlsMouseClick handler.
Tim Robinson
But I can't only loop through the first Childs of form, I need go deep in each Control and add the AllControlsMouseClick to its Childs too.
Gustavo Cardoso
The recursion of childs componets is a good tatic. But I don't want to add a listener to every control. To mouse events the Application.AddMessageFilter work, but i think your idea is good to other types of events. Thank you for the help!
Gustavo Cardoso