5

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)?

chillitom
  • 24,888
  • 17
  • 83
  • 118
  • create a new class that derives form class, then put David Fox's code in your new class. on consumer form, inherit from your new class instead of default Form. public class Form1 : MagicForm – Michael Buen Apr 06 '10 at 10:41

5 Answers5

6

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());
        Console.WriteLine("Click {0} at {1}", name, pos);
      }
      return false;
    }
  }

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

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Perfect! Thank you. I'd seen Application.AddMessageFilter but had no idea how to get a control from a handle. – chillitom Apr 06 '10 at 12:45
1

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

alt text http://www.catch22.net/sites/default/files/images/winspy1.img_assist_custom.jpg

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.

Community
  • 1
  • 1
Matt Warren
  • 10,279
  • 7
  • 48
  • 63
0

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

Paulo Santos
  • 11,285
  • 4
  • 39
  • 65
  • 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 Apr 06 '10 at 10:37
0

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 Fox
  • 10,603
  • 9
  • 50
  • 80
0

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,684
  • 18
  • 31