using System;
using System.Collections.Generic;
using System.Text;

using System.Diagnostics;
using System.Runtime.InteropServices;
#pragma warning disable CS0649 // 命名样式
namespace _SCREEN_CAPTURE
{
    /// <summary>
    /// 
    /// </summary>
    internal class MouseHook
    {
        #region Win32
        /// <summary>
        /// 
        /// </summary>
        /// <param name="idHook"></param>
        /// <param name="lpfn"></param>
        /// <param name="hmod"></param>
        /// <param name="dwThreadid"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]   //设置钩子  第二个参数为回调函数指针
        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hmod, int dwThreadid);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hHook"></param>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]   //传递到下一个钩子
        public static extern int CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hHook"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]   //卸载钩子
        public static extern bool UnhookWindowsHookEx(IntPtr hHook);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="lpModuleName"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll")] //获取模块句柄  
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        private const int WH_MOUSE_LL = 14;//全局鼠标Hook 7是局部的 13全局键盘 2局部键盘
        private const uint WM_LBUTTONDOWN = 0x201;
        private const uint WM_LBUTTONUP = 0x202;
        private const uint WM_RBUTTONDOWN = 0x204;
        private const uint WM_RBUTTONUP = 0x205;
        /// <summary>
        /// 
        /// </summary>
        public struct POINT
        {
            /// <summary>
            /// 
            /// </summary>
            public int X;
            /// <summary>
            /// 
            /// </summary>
            public int Y;
        }
        /// <summary>
        /// 鼠标结构信息
        /// </summary>
        public struct MSLLHOOTSTRUCT
        {
            /// <summary>
            /// 
            /// </summary>
            public POINT pt;
            /// <summary>
            /// 
            /// </summary>
            public int mouseData;
            /// <summary>
            /// 
            /// </summary>
            public int flags;
            /// <summary>
            /// 
            /// </summary>
            public int time;
            /// <summary>
            /// 
            /// </summary>
            public int dwExtraInfo;
        }

        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void MHookEventHandler(object sender, MHookEventArgs e);
        /// <summary>
        /// 
        /// </summary>
        public event MHookEventHandler MHookEvent;

        private IntPtr hHook = IntPtr.Zero;
        /// <summary>
        /// 
        /// </summary>
        public IntPtr HHook {
            get { return hHook; }
        }

        GCHandle gc;
        //Hook回调函数
        private int MouseHookProcedure(int nCode, IntPtr wParam, IntPtr lParam) {
            if (nCode >= 0 && MHookEvent != null) {
                MSLLHOOTSTRUCT stMSLL = (MSLLHOOTSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOTSTRUCT));
                ButtonStatus btnStatus = ButtonStatus.None;
                if (wParam == (IntPtr)WM_LBUTTONDOWN)
                    btnStatus = ButtonStatus.LeftDown;
                else if (wParam == (IntPtr)WM_LBUTTONUP)
                    btnStatus = ButtonStatus.LeftUp;
                else if (wParam == (IntPtr)WM_RBUTTONDOWN)
                    btnStatus = ButtonStatus.RightDown;
                else if (wParam == (IntPtr)WM_RBUTTONUP)
                    btnStatus = ButtonStatus.RightUp;
                MHookEvent(this, new MHookEventArgs(btnStatus, stMSLL.pt.X, stMSLL.pt.Y));
            }
            return CallNextHookEx(hHook, nCode, wParam, lParam);
        }
        /// <summary>
        /// 设置Hook
        /// </summary>
        /// <returns></returns>
        public bool SetHook() {
            if (hHook != IntPtr.Zero)
                return false;
            HookProc mouseCallBack = new HookProc(MouseHookProcedure);
            hHook = SetWindowsHookEx(WH_MOUSE_LL, mouseCallBack,
                GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
            if (hHook != IntPtr.Zero) {
                gc = GCHandle.Alloc(mouseCallBack);
                return true;
            }
            return false;
        }
        /// <summary>
        /// 卸载Hook
        /// </summary>
        /// <returns></returns>
        public bool UnLoadHook() {
            if (hHook == IntPtr.Zero)
                return false;
            if (UnhookWindowsHookEx(hHook)) {
                hHook = IntPtr.Zero;
                gc.Free();
                return true;
            }
            return false;
        }
    }
    /// <summary>
    /// 鼠标状态枚举值
    /// </summary>
    internal enum ButtonStatus {
        /// <summary>
        /// 
        /// </summary>
        LeftDown,
        /// <summary>
        /// 
        /// </summary>
        LeftUp,
        /// <summary>
        /// 
        /// </summary>
        RightDown,
        /// <summary>
        /// 
        /// </summary>
        RightUp,
        /// <summary>
        /// 
        /// </summary>
        None }
    /// <summary>
    /// 事件参数
    /// </summary>
    internal class MHookEventArgs : EventArgs
    {
        private readonly ButtonStatus mButton;
        /// <summary>
        /// 
        /// </summary>
        public ButtonStatus MButton {
            get { return mButton; }
        }

        private readonly int x;
        /// <summary>
        /// 
        /// </summary>
        public int X {
            get { return x; }
        }

        private readonly int y;
        /// <summary>
        /// 
        /// </summary>
        public int Y {
            get { return y; }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="btn"></param>
        /// <param name="cx"></param>
        /// <param name="cy"></param>
        public MHookEventArgs(ButtonStatus btn, int cx, int cy) {
            this.mButton = btn;
            this.x = cx;
            this.y = cy;
        }
    }
}
