3

[Edit] Here's what I've gleaned about mouse input handling thus far. Note that I've learned this via a bunch of different sources and via experimentation, so don't take this as gospel: 1) Mouse event originates with mouse move 2) SetWindowsHookEx(WH_MOUSE_LL) handler LowLevelMouseProc sees event first 3) OS/app framework handles Mouse event at some high level (mouse cursor moves) 4) WM_INPUT event is picked up by app event queue and handled by WndProc (although handling at this time does not stop mouse cursor from moving in step 3). 5) Message is dispatched via ComponentDispatcher 6) PreviewMouseMove and MouseMove events are triggered and may be handled by the app.

Based on this, I think the only way to ensure that the mouse cursor doesn't move is to filter via WH_MOUSE_LL. Of course, as I've mentioned earlier in this post, there isn't sufficient information at this point to know which device this mouse event is coming from, so it's all or nothing filtering, which doesn't meet my requirements.


[Edit] I've verified that I'm able to drop events by hooking WH_MOUSE_LL and returning a value larger than 0 from the handler. Now I just need to figure out how to match a mouse event generated at the WH_MOUSE_LL level with events coming from my device...

I did try returning a value greater than 0 from WndProc. The event was still processed by my app.


I'm trying to integrate a rotary input device that's based upon the Y-axis of a mechanical USB mouse. I'd like for this device to behave solely as a raw input device and for the normal mouse move events generated by the device (at least in the context of my application) to be dropped.

So far, I've been able to hook WndProc into my WPF application MainWindow using WindowIteropHandler and AddHook. I'm able to receive WM_INPUT events and filter those for mouse events from my specific USB VID/PID device (sufficient for my needs).

I would expect that marking the message as handled and returning 0 would cause the message to not be propagated to the rest of the WPF window, but that's not the case... I'm still getting MouseMove events when I move my device. Here's my code (simplified to remove processing the WM_INPUT message, but still exhibits the same issue):

 public partial class MainWindow : Window
{
    private const int WM_INPUT = 0x00FF;

    public MainWindow()
    {
        InitializeComponent();
    }

    public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_INPUT)
        {
            // TODO - figure out why this doesn't halt further processing of this handled event
            handled = true;
        }
        return IntPtr.Zero;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWINPUTDEVICE
    {
        [MarshalAs(UnmanagedType.U2)]
        public ushort usUsagePage;
        [MarshalAs(UnmanagedType.U2)]
        public ushort usUsage;
        [MarshalAs(UnmanagedType.U4)]
        public int dwFlags;
        public IntPtr hwndTarget;
    }

    private const int RIDEV_INPUTSINK = 0x00000100;

    [DllImport("User32.dll")]
    extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);

    private void Window_SourceInitialized(object sender, EventArgs e)
    {
        WindowInteropHelper helper = new WindowInteropHelper(this);
        HwndSource source = HwndSource.FromHwnd(helper.Handle);
        RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];

        rid[0].usUsagePage  = 0x01;
        rid[0].usUsage      = 0x02;
        rid[0].dwFlags      = RIDEV_INPUTSINK; 
        rid[0].hwndTarget   = source.Handle;
        RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));

        source.AddHook(WndProc);
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        e.Handled = true;
    }

    private void button1_MouseMove(object sender, MouseEventArgs e)
    {
        e.Handled = true;
    }
}

Anyone know how to dequeue or otherwise block a mouse event that I've handled in WndProc from being propagated to MainWindow?

TIA!

-Matt

Matt
  • 61
  • 1
  • 7
  • How about using PreviewMouseMove on the MainWindow and setting `e.Handled = true`? – Michael Jul 07 '12 at 00:24
  • Thanks. I think that handling PreviewMouseMove events would filter all mouse events. I still want to handle normal mouse events, but filter for events coming from my specific mouse device. – Matt Jul 09 '12 at 14:30
  • Ah yes that makes sense. I did some work using RawInputDevice some time ago for multiple mice. Will see if I can dig it up again – Michael Jul 09 '12 at 21:54
  • I am a bit confused as to the status of what is working and what is not. Can you summarise? – Michael Jul 09 '12 at 22:23
  • I'm able to receive the raw events from the secondary mouse device, but I'm not able to cause those events to be dropped. Mouse events from my raw device still move the cursor event though I set `handled=true` for those events. I was able to drop mouse events by using LLMouseHook, but there isn't sufficient information in this event to determine which device the mouse event came from... – Matt Jul 09 '12 at 22:30
  • Oh, I also found this: http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/ – Matt Jul 09 '12 at 22:32
  • Nicholas' app uses raw input to receive data from a barcode scanner AND drops the input. It drops the events by informing an IMessageFilter object that the next event received by the application is to be dropped. This doesn't seem like an ideal solution (seems like the wrong event could be dropped?) and it utilizes WinForms Application.AddMessageFilter. I also have a concern that mouse move events may not be 1:1 between the raw input and what the application receives. – Matt Jul 09 '12 at 22:38
  • I'm reading up on Windows Forms and WPF Interop. A bunch of people have posted about the mechanism that I utilized above to catch WM_INPUT events (override HWndSource WndProc); however, I think approach is really more targeted at interop between WPF and Win32. At this point, I'm not sure whether I'm interested in acquiring WM_INPUT messages at the Win32 level or at the WinForms level. I'm reading up on the MSDN article 'Windows Forms and WPF Interoperability Input Architecture': msdn.microsoft.com/en-us/library/ms742474.aspx which suggests using ComponentDispatcher.ThreadFilterMessage – Matt Jul 09 '12 at 22:57
  • I used RawInput a couple of years ago, but it was WinForms not WPF. The doco you are reading seems to be for a hybrid WinForms / WPF app (although it seems to toggle between 'WinForms' and 'Win32' as if they are the same). The line "The ComponentDispatcher class provides hooks to enable external clients to filter messages before WPF processes them" looks very promising. – Michael Jul 09 '12 at 23:41
  • @Michael thanks for your feedback. Once I get this figured out, I'll post back here. – Matt Jul 10 '12 at 00:00

2 Answers2

3

After long hours of Googling, it looks like someone else has already described and solved what I'm trying to do using a UMDF: http://oblita.com/Interception

I was hoping I wouldn't have to go there, but it's looking like this is the only way to actually intercept events coming from a particular device.

Matt
  • 61
  • 1
  • 7
  • 1
    I've been banging my head on this for a couple of months and got to the same road-block as you had. I was trying to queue events in order to match them, but I'm glad I read this thread as it's clear that won't work. I am hopeful The link you provided will be the answer I am looking for - certainly is the closest thing so far. – ChronoFish Dec 28 '12 at 02:22
2

I also had this problem, and I solved it by running my application with Administrator privileges.

It seems that the WM_INPUT message is subject to the UIPI (User Interface Privilege Isolation). Check out the reference here:

SendMessage, PostMessage, and Related Functions

Although the method DefWindowProc() will deliver the message, it does not process it to the next application. But if there is an application that’s running as Administrator, such as Task Manager, Window Device Manager and so on, the lower privileges application can not received some of window messages delivered from the application mentioned above. This problem is not only the WN_IPUT, but alse the Hook.

Tzar
  • 5,132
  • 4
  • 23
  • 57
iDream
  • 76
  • 3