Search code examples
c#wpfmouseeventimessagefilter

WPF Intercept global mouse movements (like using IMessageFilter in Windows Form)


I'm converting a UserControl from Windows Form to WPF, Here is my Windows Form working code:

GlobalMouseHandler mouseHandler = new GlobalMouseHandler();
mouseHandler.MouseMove += OnGlobalMouseMove;
mouseHandler.MouseButtonUp += OnGlobalMouseButtonUp;

public class GlobalMouseHandler : IMessageFilter, IDisposable
{
    public event MouseMovedEvent MouseMove;
    public event MouseButtonUpEvent MouseButtonUp;

    public GlobalMouseHandler(){
        Application.AddMessageFilter(this);
    }

    public bool PreFilterMessage(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_MOUSEMOVE:
                MouseMove?.Invoke();
                break;
            case WM_LBUTTONUP:
                MouseButtonUp?.Invoke();
                break;
        }
        return false;
    }
}

I used IMessageFilter to get the mouse move and mouse up events in my application and attach to them.

Now, I know that IMessageFilter is not available in WPF, but is there a simple way to record these simple mouse events in WPF?


Solution

  • You can handle messages similar way (mouse move for example):

    Xaml:

    <Window ... Loaded="Window_OnLoaded">
        ...
    </Window>
    

    Code-behind:

        using System.Windows.Interop;
    
        ...
    
        private const int WM_MOUSEMOVE = 0x0200;
    
        private void Window_OnLoaded(object sender, RoutedEventArgs e)
        {
            HwndSource.FromHwnd(new WindowInteropHelper(this).Handle)?.AddHook(this.WndProc);
        }
    
        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_MOUSEMOVE:
                    // MouseMove?.Invoke();
                    break;
            }
    
            return IntPtr.Zero;
        }
    

    Of course, if you don't want to do it in native WPF manner (left button up for example):

    <Window ... PreviewMouseLeftButtonUp="Window_OnPreviewMouseLeftButtonUp">
        ...
    </Window>
    
    private void Window_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        // e.Handled = true if you want to prevent following MouseLeftButtonUp event processing
    }