将鼠标侧边按钮绑定到VisualStudio动作

本文关键字:VisualStudio 动作 绑定 按钮 鼠标 | 更新日期: 2023-09-27 18:02:17

我尝试将XButton 1和2(鼠标的侧边按钮)重定向到特定的Visual Studio操作。

当我按下XButton1时,我想编译项目/构建它。默认绑定到F6

当我按下XButton2时,我想在代码和设计视图(WinForms)之间切换。这被绑定到F7

在使用Visual Studio内置工具进行了几次尝试之后,我使用AutoHotKey创建了以下脚本:

XButton2:: 
IfWinActive Microsoft Visual Studio
{ 
  Send {F7}
  return 
}

XButton1:: 
IfWinActive Microsoft Visual Studio
{ 
  Send {F6}
  return 
} 

然而,我想知道是否有人知道与Visual Studio 2015实现相同的原生方式?

将鼠标侧边按钮绑定到VisualStudio动作

解决方案

主要思想是注册一个全局鼠标钩子和处理所需的鼠标事件,并运行一个visual studio命令。

    从创建一个Visual Studio Package项目开始。
  • 使用SetWindowsHookEx通过传递WH_MOUSE_LL注册全局鼠标钩子,并处理所需的鼠标事件,例如WM_XBUTTONDOWN。在解决方案加载时执行注册。
  • 使用DTE.ExecuteCommand传递合适的命令运行所需的Visual Studio命令,例如Build.BuildSolution:

    var dte = (EnvDTE.DTE)this.GetService(typeof(EnvDTE.DTE));
    dte.ExecuteCommand("Build.BuildSolution");
    
  • 当解决方案关闭时,不要忘记使用UnhookWindowsHookEx解除挂钩。

    注意:

    • 找到你需要的命令,进入Tools → Options → Environment → KeyBoard,找到你需要的命令

    • 你会发现很多关于如何注册像这样的全局鼠标钩子的资源,我改变了一点,并用于测试。在文章的末尾,你可以找到完整的源代码。

    • 在Visual Studio 2013中不推荐使用Add- ins,所以虽然你可以使用Visual Studio Add- In项目来做同样的事情,但最好使用vpackages。

    Implementaion

    首先创建一个Visual Studio Package项目,并将包的代码更改为我在这里发布的代码。还添加了我用于全局鼠标钩子和windows API的类到解决方案。

    下面是我的Package的完整代码:

    using Microsoft.VisualStudio.Shell;
    using System;
    using System.Runtime.InteropServices;
    [PackageRegistration(UseManagedResourcesOnly = true)]
    [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
    [Guid(GuidList.guidVSPackage1PkgString)]
    [ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids80.SolutionExists)]
    public sealed class VSPackage1Package : Package
    {
        public VSPackage1Package() { }
        EnvDTE.DTE dte;
        protected override void Initialize()
        {
            base.Initialize();
            dte = (EnvDTE.DTE)this.GetService(typeof(EnvDTE.DTE));
            dte.Events.SolutionEvents.Opened += SolutionEvents_Opened;
            dte.Events.SolutionEvents.AfterClosing += SolutionEvents_AfterClosing;
        }
        void SolutionEvents_AfterClosing() { MouseHook.Stop(); }
        void SolutionEvents_Opened()
        {
            MouseHook.Start();
            MouseHook.MouseAction += MouseHook_MouseAction;
        }
        void MouseHook_MouseAction(object sender, EventArgs e)
        {
            dte.ExecuteCommand("Build.BuildSolution");
        }
    }
    

    Windows API消息、结构和方法

    using System;
    using System.Runtime.InteropServices;
    public class Win32
    {
        public delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
        public const int WH_MOUSE_LL = 14;
        public enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201, WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200, WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204, WM_RBUTTONUP = 0x0205
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT { public int x; public int y; }
        [StructLayout(LayoutKind.Sequential)]
        public 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)]
        public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn,
            IntPtr hMod, uint dwThreadId);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam,
            IntPtr lParam);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);
    }
    

    全局鼠标钩子

    因为我没有XButton在我的鼠标,我处理WM_RBUTTONDOWN事件。

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    public static class MouseHook
    {
        public static event EventHandler MouseAction = delegate { };
        private static Win32.LowLevelMouseProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
        public static void Start() { _hookID = SetHook(_proc); }
        public static void Stop() { Win32.UnhookWindowsHookEx(_hookID); }
        private static IntPtr SetHook(Win32.LowLevelMouseProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                var handle = Win32.GetModuleHandle(curModule.ModuleName);
                return Win32.SetWindowsHookEx(Win32.WH_MOUSE_LL, proc, handle, 0);
            }
        }
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && 
                Win32.MouseMessages.WM_RBUTTONDOWN == (Win32.MouseMessages)wParam)
            {
                Win32.MSLLHOOKSTRUCT hookStruct = 
                    (Win32.MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, 
                        typeof(Win32.MSLLHOOKSTRUCT));
                MouseAction(null, new EventArgs());
            }
            return Win32.CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
    }