Search code examples
c#wpfvisual-studiomouse-hook

What do I put for the MouseDevice parameter in a MouseButtonEventArgs Constructor?


I'm creating an app in WPF c# that needs to be able to detect mouse click up and click down events separately. In order to do this, I use code for a Global Mouse Hook that I found online. the only problem with the code was that it used EventArgs as the EventHandler so it passed the same function everytime I sent MouseUp and MouseDown in. To fix this, I used the MouseButtonEventArgs constructor. The rpoblem I'm having now is that the constructor needs 3 parameters: MouseDevice, timestamp, and MouseButton for the constructor to actually work. I have figured out timestamp and MouseButton, but I don't know what to put for MouseDevice. What do I put here to make the constructor work? Here is my low level mousehook class code.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;

namespace KeystrokeDisplay
{
    public static class MouseHook
    {
        public static event MouseEventHandler MouseAction = delegate {  };

        public static void Start()
        {
            _hookID = SetHook(_proc);


        }
        public static void stop()
        {
            UnhookWindowsHookEx(_hookID);
        }

        private static LowLevelMouseProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;

        private static IntPtr SetHook(LowLevelMouseProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_MOUSE_LL, proc,
                  GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
            {
                MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                MouseAction(null, new MouseButtonEventArgs(mouse: ????????, timestamp: 0, button: MouseButton.Left)); 
            }
            if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
            {
                MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                MouseAction(null, new MouseButtonEventArgs(mouse: ????????, timestamp: 0, button: MouseButton.Left)); 
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        public const int WH_MOUSE_LL = 14;

        public enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
     
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
          LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
          IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);


    }
}

How do I fix this? Also, I'm fairly new to c# so I might need some extra help understanding your answer.


Solution

  • I don't see any reason to use MouseEventHandler.

    You want to detect mouse click up and click down events separately, so you can create two delegates for mouse click up and click down and pass own event arguments. You are only interested in which mouse button was pressed.

    public delegate void MouseUpEventHandler(object sender, MyMouseEventArgs e);
    public delegate void MouseDownEventHandler(object sender, MyMouseEventArgs e);
    
    public class MyMouseEventArgs : EventArgs
    {
        public MouseButton MouseButton { get; }
    
        public MyMouseEventArgs(MouseButton mouseButton)
        {
            MouseButton = mouseButton;
        }
    }
    

    Then replace

    public static event MouseEventHandler MouseAction = delegate {  };
    

    with

    public static event MouseUpEventHandler MouseUpAction = delegate {  };
    public static event MouseDownEventHandler MouseDownAction = delegate {  };
    

    In HookCallback invoke MouseDownAction or MouseUpAction.

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
        {
            MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
            MouseDownAction(null, new MyMouseEventArgs(MouseButton.Left)); 
        }
        if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
        {
            MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
            MouseUpAction(null, new MyMouseEventArgs(MouseButton.Left)); 
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }