using System; using System.Drawing; using System.Windows.Forms; namespace NullFX.Controls { public class MouseMessageFilter : IMessageFilter { // singleton implementation static object locker = new object(); static MouseMessageFilter instance; public static MouseMessageFilter Instance { get { lock (locker) { if (instance == null) instance = new MouseMessageFilter(); } return instance; } } // win32 message notifications const int WM_LBUTTONDOWN = 0x0201; const int WM_LBUTTONUP = 0x0202; const int WM_LBUTTONDBLCLK = 0x0203; const int WM_RBUTTONDOWN = 0x0204; const int WM_RBUTTONUP = 0x0205; const int WM_RBUTTONDBLCLK = 0x0206; const int WM_MBUTTONDOWN = 0x0207; const int WM_MBUTTONUP = 0x0208; const int WM_MBUTTONDBLCLK = 0x0209; const int WM_XBUTTONDOWN = 0x020B; const int WM_XBUTTONUP = 0x020C; const int WM_XBUTTONDBLCLK = 0x020D; const int WM_MOUSEMOVE = 0x0200; const int WM_MOUSEWHEEL = 0x020A; const int MK_LBUTTON = 0x0001; const int MK_RBUTTON = 0x0002; const int MK_MBUTTON = 0x0010; const int MK_XBUTTON1 = 0x0020; const int MK_XBUTTON2 = 0x0040; // various events to produce public event EventHandler MouseMove; public event EventHandler MouseDown; public event EventHandler MouseUp; public event EventHandler Click; public event EventHandler DoubleClick; public event EventHandler MouseWheel; // event invokers protected virtual void OnMouseMove(MouseEventArgs e) { if (MouseMove != null) MouseMove(this, e); } protected virtual void OnMouseDown(MouseEventArgs e) { if (MouseDown != null) MouseDown(this, e); } protected virtual void OnMouseUp(MouseEventArgs e) { if (MouseUp != null) MouseUp(this, e); } protected virtual void OnClick(MouseEventArgs e) { if (Click != null) Click(this, e); } protected virtual void OnDoubleClick(MouseEventArgs e) { if (DoubleClick != null) DoubleClick(this, e); } protected virtual void OnMouseWheel(MouseEventArgs e) { if (MouseWheel != null) MouseWheel(this, e); } // utility to build up the mouse event args from the win32 message private MouseEventArgs CreateMouseEventArgs(ref Message m, int clicks) { Point a = MakePoint(m.WParam); int delta = a.Y; MouseButtons mb = GetMouseButton(a.X); Point p = MakePoint(m.LParam); return new MouseEventArgs(mb, clicks, p.X, p.Y, delta); } // utility to map the virtual key codes to a MouseButons value private MouseButtons GetMouseButton(int code) { MouseButtons mb = MouseButtons.None; if ((code & MK_LBUTTON) == MK_LBUTTON) mb |= MouseButtons.Left; if ((code & MK_MBUTTON) == MK_MBUTTON) mb |= MouseButtons.Middle; if ((code & MK_RBUTTON) == MK_RBUTTON) mb |= MouseButtons.Right; if ((code & MK_XBUTTON1) == MK_XBUTTON1) mb |= MouseButtons.XButton1; if ((code & MK_XBUTTON2) == MK_XBUTTON2) mb |= MouseButtons.XButton2; return mb; } // utility to get the high and low value of a message parameter private Point MakePoint(IntPtr param) { int x = param.ToInt32() & 0xffff; int y = (param.ToInt32() >> 16); return new Point(x, y); } // method gets called before the message is dispatched to the individual // windows of the application. returning true will keep the message from // being dispatched to the application's message queue public bool PreFilterMessage(ref Message m) { switch (m.Msg) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: { MouseEventArgs e = CreateMouseEventArgs(ref m, 0); OnMouseDown(e); } break; case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: { MouseEventArgs e = CreateMouseEventArgs(ref m, 1); OnClick(e); OnMouseUp(e); } break; case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: { MouseEventArgs e = CreateMouseEventArgs(ref m, 2); OnDoubleClick(e); } break; case WM_XBUTTONDOWN: { MouseEventArgs e = CreateMouseEventArgs(ref m, 0); OnMouseDown(e); } break; case WM_XBUTTONUP: { MouseEventArgs e = CreateMouseEventArgs(ref m, 1); OnClick(e); OnMouseUp(e); } break; case WM_XBUTTONDBLCLK: { MouseEventArgs e = CreateMouseEventArgs(ref m, 2); OnDoubleClick(e); } break; case WM_MOUSEMOVE: { MouseEventArgs e = CreateMouseEventArgs(ref m, 0); OnMouseMove(e); } break; case WM_MOUSEWHEEL: { MouseEventArgs e = CreateMouseEventArgs(ref m, 0); OnMouseWheel(e); } break; } return false; } // private constructor to enforce singleton instanciation private MouseMessageFilter() { } } }