Jamona Mican
Jamona Mican

Reputation: 1654

Any way to access mouse Raw Input from WPF?

I'm currently using a global mouse hook to make an app appear if it the mouse cursor reaches the corner of the screen. I just read about the existence of Raw Input and from what I understand, this is a more robust method as a slowdown in my hook will not impact the overall system.

Problem is I can't find any examples anywhere about using Raw Input in WPF.

Closest I got was SlimDX with the following code:

  Device.RegisterDevice(UsagePage.Generic, UsageId.Mouse, 
                        DeviceFlags.None);

  Device.MouseInput += new EventHandler<MouseInputEventArgs>(mouse_MouseInput);

But that does not seem to work in WPF, only winforms.

Upvotes: 2

Views: 1722

Answers (1)

BurnsBA
BurnsBA

Reputation: 4939

Those DeviceFlags.None need to be InputSink to capture input in the background. SharpDX flags there are actually a wrapper for the RAWINPUTDEVICEFLAGS (InputSink = 0x00000100).

In WPF, you want to 1) override OnSourceInitialized and 2) hook WndProc there. While the window pointer is available you need to define the RAWINPUTDEVICE's you want to watch, flag InputSink.

It will look something like

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
    source.AddHook(WndProc);

    var win = source.Handle;

    RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[2];

    rid[0].UsagePage = (HIDUsagePage)0x01;
    rid[0].Usage = (HIDUsage)0x05;                 // adds game pad
    rid[0].Flags = RawInputDeviceFlags.InputSink;  // accept input in background
    rid[0].WindowHandle = win;

    rid[1].UsagePage = (HIDUsagePage)0x01;
    rid[1].Usage = (HIDUsage)0x04;                 // adds joystick
    rid[1].Flags = RawInputDeviceFlags.InputSink;  // accept input in background
    rid[1].WindowHandle = win;

    if (RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0])) == false)
    {
        var err = Marshal.GetLastWin32Error();
        if (err > 0)
        {
            throw new Win32Exception($"GetLastWin32Error: {err}");
        }
        else
        {
            throw new Win32Exception("RegisterRawInputDevices failed with error code 0. Parameter count mis-match?");
        }
    }
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case WM_INPUT:
            {
                System.Diagnostics.Debug.WriteLine("Received WndProc.WM_INPUT");
                DoTheThing(lParam);
            }
            break;
    }
    return hwnd;
}

Upvotes: 0

Related Questions