C#:如何使用钩子检测鼠标的额外按键点击?

3
我正在进行一个个人项目,尝试创建类似APM计算器的东西。为了实现它,我需要能够检测到任何按键和鼠标点击。我正在使用钩子来捕获键盘事件和鼠标事件,但我找不到任何方法来捕获特殊鼠标按钮的点击...
当我谈论特殊鼠标按钮时,我的意思是像游戏鼠标上的附加按钮。例如:Logitech G600
我想知道是否有任何方法可以检测来自任何鼠标按钮或特殊鼠标按钮的鼠标点击?
我已经找到了如何为常规按钮甚至导航按钮完成此操作的方法,但我似乎无法找到有关附加按钮的任何信息。
以下是我删除了所有键盘部分的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Input;

namespace MouseHook
{
    static class Program
    {
        private const int WH_MOUSE_LL = 14;
        private static LowLevelMouseProc _procMouse = HookCallbackMouse;
        private static IntPtr _hookIDMouse = IntPtr.Zero;

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205,
            WM_XBUTTONDOWN = 0x020B

            // MISSING ADDITIONAL BUTTONS
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

        [STAThread]
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            _hookIDMouse = SetHookMouse(_procMouse);

            Application.Run(new Form1());

            UnhookWindowsHookEx(_hookIDMouse);
        }

        private static IntPtr SetHookMouse(LowLevelMouseProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private static IntPtr HookCallbackMouse(int nCode, IntPtr wParam, IntPtr lParam)
        {
            // DEAL WITH ANY BUTTON OR ADDITIONAL BUTTON MOUSE

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

谢谢。

1
大多数游戏鼠标不是都会在设备驱动程序中将“特殊按钮”映射到键盘快捷键吗? - Fildor
也许我会尝试在调试模式下查找键盘快捷键,我会随时向您更新。感谢您的建议。 - Billard Philippe
为什么要调试模式?只需转到设备驱动程序的设置...您可以通过调试验证您的发现,但查找应该更快。 - Fildor
如果你还没有,可以查看MSDN关于鼠标输入 - XBUTTONSWM_APPCOMMAND的内容。 - Jimi
1个回答

0
如果我理解正确,您想找到在单击附加鼠标按钮时发送的WindowsMessages。为了检测这些消息,我建议您创建一个自定义的MessageFilter,该过滤器实现IMessageFilter接口。
class MessageFilter : IMessageFilter
{
    int[] msgToIgnore = new int[] {512, 799, 49632, 49446, 1847, 15, 96, 275, 160, 1848, 674 , 513, 675, 514, 280, 161, 274, 673, 515, 516, 517, 518, 519, 520, 521, 522, 163, 164, 167, 168, 169, 165, 166};

    public bool PreFilterMessage(ref Message m)
    {
        bool match = false;

        foreach (var msg in msgToIgnore)
        {
            if (m.Msg == msg)
                match = true;
        }

        if (!match)
        {
            MessageBox.Show(m.Msg.ToString());
            return true;
        }
        else
            return false;
    }
}

MessageFilter 过滤每一个发送到你的应用程序的 WindowsMessage。所以我基本上添加了 msgToIgnore 数组来忽略所有其他基本的 WindowsMessages,比如任何正常的鼠标点击、移动等等,或者在应用程序启动时发生的任何事情。(我在一个空白的窗体上测试了它,并在窗体的每个部分上单击、双击、拖动等等)这将忽略所有这些 WindowsMessages,但是一旦你发送另一个 WindowsMessage,例如你点击附加鼠标按钮,WindowsMessage 将会显示在一个 MessageBox 中。

要激活这个 MessageFilter,你只需要将它添加到你的应用程序中,在 InitializeComponent() 之后建议这样做。

MessageFilter msgFilter = new MessageFilter();

Application.AddMessageFilter(msgFilter);

告诉我如果我错了,但我需要捕捉任何点击(即使是普通的),并且我需要在没有聚焦于窗口(即APM计算器)的情况下捕捉它们。所以你的解决方案在这种情况下不起作用,对吧? 其实那是我的错,我应该更加精确地说明。 但是感谢您提供的示例,以后可能会有帮助! - Billard Philippe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接