【问题标题】:Bind Mouse Side Buttons to VisualStudio Actions将鼠标侧键绑定到 VisualStudio 操作
【发布时间】:2016-08-12 19:48:28
【问题描述】:

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

【问题讨论】:

  • 我没有访问VS2015,所以使用VS2013实现了解决方案。但它也应该使用 VS2015 工作。创建 VS2015 Visual Studio Package 项目时,复制VSPackage1Package 类的InstalledProductRegistration 属性并使用而不是我使用的属性。

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


【解决方案1】:

解决方案

主要思想是注册一个全局鼠标钩子并处理所需的鼠标事件并运行 Visual Studio 命令。这样做:

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

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

注意:

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

  • 你会发现很多关于如何注册全局鼠标钩子的资源,比如this,我对其进行了一些更改并用于测试。在文末您可以找到完整的源代码。

  • 在 Visual Studio 2013 中,插件已弃用,因此虽然您可以使用 Visual Studio Add-in 项目执行相同操作,但最好使用 VSPackages。

实施

首先创建一个 Visual Studio 包项目并将包的代码更改为我在此处发布的代码。还将我用于全局鼠标钩子和 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);
    }
}

【讨论】:

    猜你喜欢
    • 2010-10-16
    • 2020-12-18
    • 2011-11-28
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2017-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多