views:

66

answers:

5

Hi All,

Is there a way to log all of the clicks in a Win Forms application? I'd like to intercept clicks and record the action and the name of the control that caused it.

Is this possible?

Thanks in advance.

UPDATE: I'm looking for an application wide solution, is there no way to add a listener to the windows event queue (or what ever it is called)?

A: 

Well, you could subscribe to the Click or MouseDown event of every control on the form.

Paulo Santos
obviously, but I'm looking for something that takes care of this as a cross cutting concern. In a large application this approach just isn't feasible.
chillitom
A: 

use MouseEventArgs like this:

    private  void Form_MouseDown(object sender, System.WinForms.MouseEventArgs e) 
{ 
switch (e.Button) 
{ 
    case MouseButtons.Left: 
    MessageBox.Show(this,"Left Button Click"); 
    break; 
    case MouseButtons.Right: 
    MessageBox.Show(this,"Right Button Click" ); 
    break; 
    case MouseButtons.Middle: 
    break; 
    default: 
    break; 
} 

EventLog.WriteEntry("source", e.X.ToString() + " " + e.Y.ToString()); //or your own Log function

} 
David
+1  A: 

You could use Spy++ or WinSpy++ to achieve this.

alt text

But I'm not sure how you can achieve the same thing yourself. If it's possible you'd need to do it via a low-level Windows API hook or a message handler that gives you access to all the message in your applications queue.

Matt Warren
A: 

The NunitForms test project has a recorder application that watches for this and many other events. The code is very clever and worth a good look. It's a ThoughtWorks project.

That's the rolls Royce solution though!...

Try recursively walking the Controls collection of the form and subscibe to the event based on the type.

PK :-)

Paul Kohler
+2  A: 

You can do this by having your app's main form implement the IMessageFilter interface. You can screen the Window messages it gets and look for clicks. For example:

  public partial class Form1 : Form, IMessageFilter {
    public Form1() {
      InitializeComponent();
      Application.AddMessageFilter(this);
      this.FormClosed += (o, e) => Application.RemoveMessageFilter(this);
    }

    public bool PreFilterMessage(ref Message m) {
      if (m.Msg == 0x201 || m.Msg == 0x203) {  // Trap left click + double-click
        string name = "Unknown";
        Control ctl = Control.FromHandle(m.HWnd);
        if (ctl != null) name = ctl.Name;
        Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
        Console.WriteLine("Click {0} at {1}", name, pos);
      }
      return false;
    }
  }

Note that this logs all clicks in any window of your app.

Hans Passant
Perfect! Thank you. I'd seen Application.AddMessageFilter but had no idea how to get a control from a handle.
chillitom