替换鼠标动作后,每隔一个窗口冻结-C#

时间:2018-11-07 14:14:29

标签: c# mouse

我正在编写一个将自定义操作绑定到鼠标按钮的应用程序。例如,我将音量连接到拇指按钮之一。只要我停留在一个窗口中,一切就可以正常工作,因为其他所有窗口和任务栏似乎都冻结了,这需要一些时间才能再次激活这些窗口,或者如果我终止了我正在运行的应用程序或窗口。

在下面的代码中,我捕获了鼠标事件,并检查了应用程序中的设置是否为默认按钮操作或按钮操作是否已更改。如果操作已更改,则应用程序应例如将音量调高2倍。

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetModuleHandle(string name);

    public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

    public static bool usingKeyboard = false;
    public static bool leftButtonDown = false;

    static int hMHook;

    public const int WH_MOUSE_LL = 14;

    //Declare MouseHookProcedure as a HookProc type.
    static HookProc MouseHookProcedure;

    private enum MouseMessages
    {
        WM_LBUTTONDOWN = 0x0201,
        WM_LBUTTONUP = 0x0202,
        WM_MOUSEMOVE = 0x0200,
        WM_MOUSEWHEEL = 0x020A,
        WM_RBUTTONDOWN = 0x0204,
        WM_RBUTTONUP = 0x0205,
        WM_XBUTTONDOWN = 0x020B,
        WM_XBUTTONUP = 0x020C,
        WM_MBUTTONUP = 0x0208,
        WM_MBUTTONDOWN = 0x0207
    }

    [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("kernel32.dll")]
    static extern uint GetLastError();

    [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,
    IntPtr wParam, IntPtr lParam);

    private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
        MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

        MouseUsageMessage message = new MouseUsageMessage(1);
        MouseUsageManager.mouseUsageMessageQueue.Add(message);
        if (nCode >= 0)
        {
            if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
            {
                leftButtonDown = true;
            } else if (MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
            {
                leftButtonDown = false;                   
            } else if (MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
            {

            } else if (MouseMessages.WM_RBUTTONUP == (MouseMessages) wParam) {

            } else if (MouseMessages.WM_XBUTTONUP == (MouseMessages)wParam)
            {
                switch (MyMouseHookStruct.hwnd)
                {
                    case 65536:
                        if (Settings.Default.thumbClick1User != Settings.Default.thumbClick1Default)
                        {
                            ExecuteAction(Settings.Default.thumbClick1User);
                            return 1;
                        }
                        break;
                    case 131072:
                        if (Settings.Default.thumbClick2User != Settings.Default.thumbClick2Default)
                        {
                            ExecuteAction(Settings.Default.thumbClick2User);
                            return 1;
                        }
                        break;
                }
            } else if (MouseMessages.WM_MBUTTONDOWN == (MouseMessages)wParam)
            {

            }
        }
        return CallNextHookEx(hMHook, nCode, wParam, lParam);
    }

为什么其他窗口冻结了?为什么单击拇指按钮后不能在其他窗口上使用鼠标?

编辑:附加代码

private void ExecuteAction(string setting)
    {
        VolumeControl vc = new VolumeControl();
        Keybindings kb = new Keybindings();
        switch (setting)
        {
            case "volUp":
                vc.VolUp();
                break;
            case "volDown":
                vc.VolDown();
                break;
            case "cut":
                kb.Cut();
                break;
            case "selectAll":
                kb.SelectAll();
                break;
            case "copy":
                kb.Copy();
                break;
            default:
                break;
        }
    }

发送到ExecuteAction函数的设置字符串只是具有要执行的动作的字符串,即复制,调高音量,调低音量等。

VolumeControl类:

public class VolumeControl
{
    private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
    private const int APPCOMMAND_VOLUME_UP = 0xA0000;
    private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
    private const int WM_APPCOMMAND = 0x319;

    IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg,
        IntPtr wParam, IntPtr lParam);


    public void VolDown()
    {
        SendMessageW(handle, WM_APPCOMMAND, handle,
            (IntPtr)APPCOMMAND_VOLUME_DOWN);
    }

    public void VolUp()
    {
        SendMessageW(handle, WM_APPCOMMAND, handle,
            (IntPtr)APPCOMMAND_VOLUME_UP);
    }
}

创建Hook函数,该函数在初始化类时被调用:

    private void createHook()
    {
        while (hMHook == 0) //|| hKHook == 0)
        {

            //if (hMHook == 0)
            //{
                //hMHook = SetWindowsHookEx(WH_MOUSE_LL,
                            //MouseHookProcedure,
                            //GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
                            //(IntPtr)0,
                            //0);
            //}

            if (hMHook == 0)
            {
                hMHook = SetWindowsHookEx(WH_MOUSE_LL,
                        MouseHookProcedure,
                        GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
                        0);
            }

            if (hMHook == 0) //|| hKHook == 0)
            {
                Console.WriteLine("SetWindowsHookEx Failed");
                return;
            }
            Console.WriteLine("Hooked");
        }
    }

1 个答案:

答案 0 :(得分:0)

我的解决方案,我已经建立了一个简单的控制台项目

启动程序时,该挂钩被激活,并且可以使用鼠标中键进行切换。右键和letf键向上播放系统音量。

主程序:

using HookInput.API;
using HookInput.Mouse;
using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace ConsoleApp3
{
    public class Program
    {
        private static MouseInput mouseInputHook = null;

        static void Main(string[] args)
        {
            var vc = new  VolumeControl();
            mouseInputHook = new MouseInput(vc);
            mouseInputHook.setHook(true);
            Console.WriteLine("hook activated");
            Application.Run(new ApplicationContext());
        }
    }

    public class VolumeControl
    {
        private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
        private const int APPCOMMAND_VOLUME_UP = 0xA0000;
        private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
        private const int WM_APPCOMMAND = 0x319;

        public IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;

        public void VolDown()
        {
            WindowsHookAPI.SendMessageW(handle, WM_APPCOMMAND, handle, (IntPtr)APPCOMMAND_VOLUME_DOWN);
        }

        public void VolUp()
        {
            WindowsHookAPI.SendMessageW(handle, WM_APPCOMMAND, handle, (IntPtr)APPCOMMAND_VOLUME_UP);
        }
    }
}

API:

using System;
using System.Runtime.InteropServices;

namespace HookInput.API
{
    public class WindowsHookAPI
    {
        //public delegate IntPtr HookDelegate(
        //    Int32 Code, IntPtr wParam, IntPtr lParam);
        public delegate IntPtr HookDelegate(Int32 Code, IntPtr wParam, IntPtr lParam);

        [DllImport("User32.dll")]
        public static extern IntPtr CallNextHookEx(IntPtr hHook, Int32 nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("User32.dll")]
        public static extern IntPtr UnhookWindowsHookEx(IntPtr hHook);


        [DllImport("User32.dll")]
        public static extern IntPtr SetWindowsHookEx(Int32 idHook, HookDelegate lpfn, IntPtr hmod, Int32 dwThreadId);

        [DllImport("user32.dll")]
        public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    }
}

钩子和结构:

using HookInput.API;
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using ConsoleApp3;

namespace HookInput.Mouse
{
    public class MouseInput
    {
        private const Int32 WM_MOUSEMOVE = 0x0200;

        private const Int32 WM_LBUTTONDOWN = 0x0201;
        private const Int32 WM_LBUTTONUP = 0x0202;
        private const Int32 WM_LBUTTONDBLCLK = 0x0203;
        private const Int32 WM_RBUTTONDOWN = 0x0204;
        private const Int32 WM_RBUTTONUP = 0x0205;
        private const Int32 WM_RBUTTONDBLCLK = 0x0206;
        private const Int32 WM_MBUTTONDOWN = 0x0207;
        private const Int32 WM_MBUTTONUP = 0x0208;
        private const Int32 WM_MBUTTONDBLCLK = 0x0209;

        private const Int32 WM_MOUSEWHEEL = 0x020A;

        private const Int32 WM_XBUTTONDOWN = 0x020B;
        private const Int32 WM_XBUTTONUP = 0x020C;
        private const Int32 WM_XBUTTONDBLCLK = 0x020D;

        private MemoryMappedViewAccessor accessor;

        private bool hooked = false;

        private WindowsHookAPI.HookDelegate mouseDelegate;
        private IntPtr mouseHandle;


        private const Int32 WH_MOUSE_LL = 14;

        private readonly VolumeControl vc;
        public MouseInput(VolumeControl vc)
        {
            this.vc = vc;
        }

        public void setHook(bool on)
        {
            if (hooked == on) return;
            if (on)
            {
                mouseDelegate = MouseHookDelegate;
                mouseHandle = WindowsHookAPI.SetWindowsHookEx(WH_MOUSE_LL, mouseDelegate, IntPtr.Zero, 0);
                if (mouseHandle != IntPtr.Zero) hooked = true;
            }
            else
            {
                WindowsHookAPI.UnhookWindowsHookEx(mouseHandle);
                hooked = false;
            }
        }

        private IntPtr MouseHookDelegate(Int32 Code, IntPtr wParam, IntPtr lParam)
        {
            //mouseData:
            //If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta.The low-order word is reserved.
            //    A positive value indicates that the wheel was rotated forward, away from the user;
            //    a negative value indicates that the wheel was rotated backward, toward the user. 
            //    One wheel click is defined as WHEEL_DELTA, which is 120.(0x78 or 0xFF88)
            //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK, 
            //    the high - order word specifies which X button was pressed or released, 
            //    and the low - order word is reserved.This value can be one or more of the following values.Otherwise, mouseData is not used.
            //XBUTTON1  = 0x0001 The first X button was pressed or released.
            //XBUTTON2  = 0x0002  The second X button was pressed or released.

            MSLLHOOKSTRUCT lparam = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
            int command = (int)wParam;
            if (Code < 0 || command == WM_LBUTTONDBLCLK || command == WM_RBUTTONDBLCLK)
                return WindowsHookAPI.CallNextHookEx(mouseHandle, Code, wParam, lParam);

            else if (command == WM_XBUTTONDOWN || command == WM_XBUTTONUP)
            {
                int numbutton = ((int)lparam.mouseData >> 16) - 1;
                //return (IntPtr)1;
            }
            else if (command == WM_LBUTTONDOWN || command == WM_LBUTTONUP)
            {
                if (command == WM_LBUTTONUP)
                {
                    vc.VolDown();
                    Console.WriteLine("L down");
                }
            }
            else if (command == WM_RBUTTONDOWN || command == WM_RBUTTONUP)
            {
                if (command == WM_RBUTTONUP)
                {
                    vc.VolUp();
                    Console.WriteLine("L Up");
                }
            }
            else if (command == WM_MBUTTONDOWN || command == WM_MBUTTONUP)
            {
                if (hooked)
                {
                    setHook(false);
                    Console.WriteLine("hook deactivated");
                }
                else
                {
                    setHook(true);
                    Console.WriteLine("hook activated");
                }
            }
            else if (command == WM_MOUSEWHEEL)
            {

            }

            return WindowsHookAPI.CallNextHookEx(mouseHandle, Code, wParam, lParam);
        }


        ~MouseInput()
        {

        }

        [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;
        }
    }
}