将鼠标侧按钮绑定到VisualStudio操作

时间:2016-08-12 19:48:29

标签: c# .net winforms visual-studio visual-studio-extensions

我尝试将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实现相同的本地方式?

1 个答案:

答案 0 :(得分:6)

解决方案

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

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

        var dte = (EnvDTE.DTE)this.GetService(typeof(EnvDTE.DTE));
        dte.ExecuteCommand("Build.BuildSolution");
        
        1. 解决方案关闭时,不要忘记使用this取消挂钩。
        2. 注意:

          • 要查找所需的命令,请转至Tools → Options → Environment → KeyBoard并找到所需的命令。

          • 你会发现很多关于如何注册像Visual Studio Add-in这样的全局鼠标钩子的资源,我改变了一些并用于测试。在帖子的最后,您可以找到完整的源代码。

          • 在Visual Studio 2013中,不推荐使用添加项,因此虽然您可以使用{{3}}项目执行相同操作,但最好使用VSPackage执行此操作。

          Implementaion

          首先创建一个Visual Studio Package项目,然后将包的代码更改为我在此处发布的代码。还要将我用于全局鼠标挂钩和Windows API的类添加到解决方案中。

          <强>封装

          以下是我的套餐的完整代码:

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