zoukankan      html  css  js  c++  java
  • c#全局鼠标事件以及鼠标事件模拟

    最近在编写Max插件时,其主容器FlowLayoutPanel由于隐藏了滚动条,要实现按住鼠标中键上下拖动的功能,因此尝试了全局鼠标事件、以及鼠标勾子,可惜由于Max不争气?都未能实现,于是代码报废,故将其分享于此。

    一、全局鼠标事件,首先构建鼠标事件处理器

    public delegate void MouseMovedEvent();
    public delegate void MouseMDownEvent();
    public delegate void MouseMUpEvent();
    public class GlobalMouseHandler : IMessageFilter
    {
        private const int WM_MOUSEMOVE = 0x0200;
        private const int WM_MBUTTONDOWN = 0x0207;
        private const int WM_MBUTTONUP = 0x0208;
        public event MouseMovedEvent TheMouseMoved;
        public event MouseMDownEvent TheMouseMDown;
        public event MouseMUpEvent TheMouseMUp;
        #region IMessageFilter Members
        public bool PreFilterMessage(ref Message m)
        {
            if (m.Msg == WM_MOUSEMOVE)
                if (TheMouseMoved != null)
                    TheMouseMoved();
            if (m.Msg == WM_MBUTTONDOWN)
                if (TheMouseMDown != null)
                    TheMouseMDown();
            if (m.Msg == WM_MBUTTONUP)
                if (TheMouseMUp != null)
                    TheMouseMUp();
            // Always allow message to continue to the next filter control
            return false;
        }
        #endregion
    }
    View Code

    然后在FlowLayoutPanel的构造函数中添加如下代码(其事件,我这里使用的Lambda表达式)

    GlobalMouseHandler gmh = new GlobalMouseHandler();
    bool mFlag = false;
    int scY = 0;
    int msY = 0;
    Cursor tempCur = null;
    
    gmh.TheMouseMDown += () =>
    {
        mFlag = true;
        scY = VerticalScroll.Value;
        msY = Cursor.Position.Y;
        tempCur = Cursor;
        Cursor = RCurs.Pan;
    };
    gmh.TheMouseMoved += () =>
    {
        if (mFlag)
        {
            int val = scY + msY - Cursor.Position.Y;
            if (val < VerticalScroll.Minimum) val = VerticalScroll.Minimum;
            if (val > VerticalScroll.Maximum) val = VerticalScroll.Maximum;
            VerticalScroll.Value = val;
        }
    };
    gmh.TheMouseMUp += () =>
    {
        mFlag = false;
        Cursor = tempCur;
    };
    Application.AddMessageFilter(gmh); //Application在Max中无效
    View Code

    二、鼠标勾子,此法亦在Max中行不通(后来是通过对FlowLayoutPanel中的各个控件实行事件穿透解决的)

    public class MouseHook
    {
        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;
    
        //全局的事件  
        public event MouseEventHandler OnMouseActivity;
    
        static int hMouseHook = 0; //鼠标钩子句柄  
    
        //鼠标常量  
        public const int WH_MOUSE_LL = 14; //mouse hook constant  
    
        HookProc MouseHookProcedure; //声明鼠标钩子事件类型.  
    
        //声明一个Point的封送类型  
        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;
            public int y;
        }
    
        //声明鼠标钩子的封送结构类型  
        [StructLayout(LayoutKind.Sequential)]
        public class MouseHookStruct
        {
            public POINT pt;
            public int hWnd;
            public int wHitTestCode;
            public int dwExtraInfo;
        }
    
        //装置钩子的函数  
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
    
        //卸下钩子的函数  
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
    
        //下一个钩挂的函数  
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
    
        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
    
        /// <summary>  
        /// 墨认的构造函数构造当前类的实例.  
        /// </summary>  
        public MouseHook()
        {
        }
    
        //析构函数.  
        ~MouseHook()
        {
            Stop();
        }
    
        public void Start()
        {
            //安装鼠标钩子  
            if (hMouseHook == 0)
            {
                //生成一个HookProc的实例.  
                MouseHookProcedure = new HookProc(MouseHookProc);
    
                hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]), 0);
    
                //如果装置失败停止钩子  
                if (hMouseHook == 0)
                {
                    Stop();
                    throw new Exception("SetWindowsHookEx failed.");  //Max中会抛出异常
                }
            }
        }
    
        public void Stop()
        {
            bool retMouse = true;
            if (hMouseHook != 0)
            {
                retMouse = UnhookWindowsHookEx(hMouseHook);
                hMouseHook = 0;
            }
    
            //如果卸下钩子失败  
            if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed.");
        }
    
        private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            //如果正常运行并且用户要监听鼠标的消息  
            if ((nCode >= 0) && (OnMouseActivity != null))
            {
                MouseButtons button = MouseButtons.None;
                int clickCount = 0;
    
                switch (wParam)
                {
                    case WM_MBUTTONDOWN:
                        button = MouseButtons.Middle;
                        clickCount = 1;
                        break;
                    case WM_MBUTTONUP:
                        button = MouseButtons.Middle;
                        clickCount = 0;
                        break;
                }
    
                //从回调函数中得到鼠标的信息  
                MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
                MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);
                //if(e.X>700)return 1;//如果想要限制鼠标在屏幕中的移动区域可以在此处设置  
                OnMouseActivity(this, e);
            }
            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
        }
    }
    View Code

    调用的方法为:

    MouseHook mouse = new MouseHook();
    mouse.OnMouseActivity += (s, e) =>
    {
        string str = "X:" + e.X + "  Y:" + e.Y + " " + e.Button + " " + e.Clicks;
        this.Text = str;
    };
    mouse.Start();  

    三、鼠标事件模拟

    //切换到窗口
    [DllImport("user32.dll")]
    public static extern bool SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
    //获取鼠标所在窗口名柄
    [DllImport("user32.dll")]
    internal static extern IntPtr WindowFromPoint(Point Point);
    [DllImport("user32.dll")]
    internal static extern bool GetCursorPos(out Point lpPoint);
    public static IntPtr GetMouseWindow()
    {
        Point p;
        GetCursorPos(out p);
        return WindowFromPoint(p);
    }
    //获取前台窗口
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    
    /// <summary>
    /// 模拟鼠标操作
    /// </summary>
    [DllImport("user32")]
    private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
    //移动鼠标 
    const int MOUSEEVENTF_MOVE = 0x0001;
    //模拟鼠标左键按下 
    const int MOUSEEVENTF_LEFTDOWN = 0x0002;
    //模拟鼠标左键抬起 
    const int MOUSEEVENTF_LEFTUP = 0x0004;
    //模拟鼠标右键按下 
    const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
    //模拟鼠标右键抬起 
    const int MOUSEEVENTF_RIGHTUP = 0x0010;
    //模拟鼠标中键按下 
    const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
    //模拟鼠标中键抬起 
    const int MOUSEEVENTF_MIDDLEUP = 0x0040;
    //标示是否采用绝对坐标 
    const int MOUSEEVENTF_ABSOLUTE = 0x8000;
    public static void MouseMove(int x, int y)
    {
        mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);
    }
    public static void MouseClick()
    {
        mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); //再复制一份则为双击
    }
    public static void MouseDown()
    {
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
    }
    public static void MouseUp()
    {
        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    }
    View Code
  • 相关阅读:
    day09总结
    day09作业
    删除循环中选中的id
    数组套数组 获取数据
    vue for each循环出来数组的某一项 再重新合并成一个新数组
    全是没见过的
    vue element 分页
    解决iphonex屏幕过长背景图片或者放在元素里面的图片不能铺满的问题
    实在自动现在APK,微信跳浏览器下载
    js判断是否在微信浏览器中打开
  • 原文地址:https://www.cnblogs.com/lged/p/5499445.html
Copyright © 2011-2022 走看看