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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM