【问题标题】:How to prevent raw mouse clicks outside an application using c#如何使用 c# 防止在应用程序外部单击鼠标
【发布时间】:2012-11-30 03:10:43
【问题描述】:

我正在尝试控制两只“老鼠”。主鼠标(鼠标)用于控制普通 UI 控制的光标(我不想拦截),而辅助“鼠标”只能用作我正在编写的应用程序的输入,否则将被忽略。

我成功地捕获了鼠标消息并根据需要进行了过滤。即使我的应用不在焦点上(根据需要),我也可以成功捕获鼠标输入。

剩下的唯一问题是我似乎无法阻止鼠标与其他应用程序交互。所以我基本上可以监视鼠标,但不能完全使用消息。

我“相信”在处理过滤后的鼠标消息时,我正在阻止调用“base.WndProc(ref message)”,但系统似乎仍在点击鼠标。

C# (Visual Studio Express 2010) 可以做到这一点吗?

感谢您提供的任何帮助。

【问题讨论】:

  • heq 的回答似乎是最正确的。重写 base.WndProc 只控制 your 应用程序接收的 Windows 消息,但与控制其他应用程序的 Windows 消息无关。全局鼠标钩子是要走的路。它实际上很受欢迎。
  • 鼠标钩只是成功的一半。我实际上两者都需要。该钩子用于防止点击表单转到其他应用程序,但我需要原始鼠标,所以我需要哪个实际设备进行点击。真正的答案是 C# (.net) 不是正确的工具——很遗憾。
  • 你需要原始鼠标是什么意思,所以你[知道]哪个实际设备做了点击?在钩住鼠标单击时,您可以确定活动窗口(GetActiveWindow())和单击的位置,然后您可以确定该单击是否发生在您的表单上。
  • 我正在使用两只鼠标。一种用于标准鼠标导航,另一种用于备用输入设备。 Rawmouse 可以区分设备,而 mousehook 则不能。我希望主“鼠标”像鼠标一样工作,但我希望辅助鼠标只向我的应用发送输入(否则它会无意中向其他应用发送“鼠标”点击)
  • 我终于找到了想要做我正在做的事情的人——他的帖子有一个指向似乎可以解决问题的库的链接:stackoverflow.com/questions/11370911/…

标签: c# mouse


【解决方案1】:

原始输入可能是您正在寻找的。 Here 是一个 MSDN 讨论,其中包含一个类似问题的链接,该链接指向关于在 C# 中处理多个键盘的 codeproject 文章。

【讨论】:

  • 这是让我走到现在为止的主要参考资料。除了限制其他应用程序中的输入外,它“有效”。不过还是谢谢。
  • this 文章来看,我认为不可能全局过滤输入。让我这么想的句子是:“请注意,鼠标和键盘也是 HID,因此来自它们的数据既可以通过 HID 消息 WM_INPUT 也可以来自传统消息。应用程序可以通过正确选择标志来选择任何一种方法在 RAWINPUTDEVICE 中。”
  • 我会给你答案,因为它在 C# 或 .net 中“不可能”。虽然这是可能的 - 但你必须使用非 .net DLL,这基本上意味着用 C/C++ 编程
【解决方案2】:

您可以使用全局鼠标钩子。我不记得我在哪里找到的,但here 是示例

【讨论】:

  • 我一直在尝试使用全局鼠标钩子——这可能是我需要使用的......但到目前为止我只能让它为 WH_MOUSE 工作,它只为我的捕获消息应用程序,其中 WH_MOUSE_LL 应该捕获所有消息-但我无法获取启动捕获的代码(它出错了)。 (看来我在无人区,并且有一些 C# 不受支持的功能)。谢谢
  • 另外,我不会说或读俄语,所以论坛链接对我没有帮助。
  • 无需阅读俄语,这是鼠标钩示例的链接,cmets 全部为英文。它包含您需要的一些东西,例如:private const int WH_KEYBOARD_LL = 13;hMouseHook = SetWindowsHookEx( WH_MOUSE_LL, MouseHookProcedure, Marshal.GetHINSTANCE( Assembly.GetExecutingAssembly().GetModules()[0]), 0);
  • 看看就好。我添加了这个链接,因为我的“收藏夹”中有它,哈哈。无需阅读俄语
【解决方案3】:

正如其他人所说,这至少在 dot net 中很麻烦。我强烈建议您切换到 C++ / Win32 来实现这一点。我认为从长远来看,您会省去很多麻烦。

【讨论】:

  • 是的,你是对的。这就是我要走的路……但在我看来,MS 在 API 方面做得很差,以至于用 C++ 进行编程令人恼火。我会完成它,一直踢和尖叫到最后。在这个时代,从注册表中取出一个字符串并将其发布到控件应该是微不足道的 - 但是你必须跳过箍才能得到一个“LPCTSTR”来打印到“cout”......
  • 如果你真的想避免使用 C++,你可以试试 VB6。我在 VB6 和 Win32 上咬牙切齿 :) 据我所知,它在使用 win32 api 时非常有效(但作为一种语言有点有限)。另一个很棒的事情是它已经存在了一段时间,并且仍然被大量使用,那里也有很多好的文档。
【解决方案4】:

我认为无法通过 C# .Net 阻止鼠标单击。但是,您可以通过 ClipCursor 将鼠标指针锁定在一个位置。以下链接可能会帮助您。

如果您本质上想阻止使用一只鼠标,为什么不直接禁用鼠标,就像您转到设备管理器并单击“禁用”一样。这可以通过编程方式解决here

这是从上面链接复制的代码:

public static class DisableHardware
{
    const uint DIF_PROPERTYCHANGE = 0x12;
    const uint DICS_ENABLE = 1;
    const uint DICS_DISABLE = 2;  // disable device
    const uint DICS_FLAG_GLOBAL = 1; // not profile-specific
    const uint DIGCF_ALLCLASSES = 4;
    const uint DIGCF_PRESENT = 2;
    const uint ERROR_INVALID_DATA = 13;
    const uint ERROR_NO_MORE_ITEMS = 259;
    const uint ERROR_ELEMENT_NOT_FOUND = 1168;

    static DEVPROPKEY DEVPKEY_Device_DeviceDesc;
    static DEVPROPKEY DEVPKEY_Device_HardwareIds;

    [StructLayout(LayoutKind.Sequential)]
    struct SP_CLASSINSTALL_HEADER
    {
        public UInt32 cbSize;
        public UInt32 InstallFunction;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SP_PROPCHANGE_PARAMS
    {
        public SP_CLASSINSTALL_HEADER ClassInstallHeader;
        public UInt32 StateChange;
        public UInt32 Scope;
        public UInt32 HwProfile;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SP_DEVINFO_DATA
    {
        public UInt32 cbSize;
        public Guid classGuid;
        public UInt32 devInst;
        public IntPtr reserved;     // CHANGE #1 - was UInt32
    }

    [StructLayout(LayoutKind.Sequential)]
    struct DEVPROPKEY
    {
        public Guid fmtid;
        public UInt32 pid;
    }

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern IntPtr SetupDiGetClassDevsW(
        [In] ref Guid ClassGuid,
        [MarshalAs(UnmanagedType.LPWStr)]
string Enumerator,
        IntPtr parent,
        UInt32 flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiDestroyDeviceInfoList(IntPtr handle);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet,
        UInt32 memberIndex,
        [Out] out SP_DEVINFO_DATA deviceInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiSetClassInstallParams(
        IntPtr deviceInfoSet,
        [In] ref SP_DEVINFO_DATA deviceInfoData,
        [In] ref SP_PROPCHANGE_PARAMS classInstallParams,
        UInt32 ClassInstallParamsSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiChangeState(
        IntPtr deviceInfoSet,
        [In] ref SP_DEVINFO_DATA deviceInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiGetDevicePropertyW(
            IntPtr deviceInfoSet,
            [In] ref SP_DEVINFO_DATA DeviceInfoData,
            [In] ref DEVPROPKEY propertyKey,
            [Out] out UInt32 propertyType,
            IntPtr propertyBuffer,
            UInt32 propertyBufferSize,
            out UInt32 requiredSize,
            UInt32 flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiGetDeviceRegistryPropertyW(
      IntPtr DeviceInfoSet,
      [In] ref SP_DEVINFO_DATA  DeviceInfoData,
      UInt32 Property,
      [Out] out UInt32  PropertyRegDataType,
      IntPtr PropertyBuffer,
      UInt32 PropertyBufferSize,
      [In,Out] ref UInt32 RequiredSize
    );

    static DisableHardware()
    {
        DisableHardware.DEVPKEY_Device_DeviceDesc = new DEVPROPKEY();
        DEVPKEY_Device_DeviceDesc.fmtid = new Guid(
                0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67,
                0xd1, 0x46, 0xa8, 0x50, 0xe0);
        DEVPKEY_Device_DeviceDesc.pid = 2;

        DEVPKEY_Device_HardwareIds = new DEVPROPKEY();
        DEVPKEY_Device_HardwareIds.fmtid = new Guid(
            0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67,
            0xd1, 0x46, 0xa8, 0x50, 0xe0);
        DEVPKEY_Device_HardwareIds.pid = 3;
    }




    public static void DisableDevice(Func<string, bool> filter, bool disable = true)
    {
        IntPtr info = IntPtr.Zero;
        Guid NullGuid = Guid.Empty;
        try
        {
            info = SetupDiGetClassDevsW(
                ref NullGuid,
                null,
                IntPtr.Zero,
                DIGCF_ALLCLASSES);
            CheckError("SetupDiGetClassDevs");

            SP_DEVINFO_DATA devdata = new SP_DEVINFO_DATA();
            devdata.cbSize = (UInt32)Marshal.SizeOf(devdata);

            // Get first device matching device criterion.
            for (uint i = 0; ; i++)
            {
                SetupDiEnumDeviceInfo(info,
                    i,
                    out devdata);
                // if no items match filter, throw
                if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
                    CheckError("No device found matching filter.", 0xcffff);
                CheckError("SetupDiEnumDeviceInfo");

                string devicepath = GetStringPropertyForDevice(info,
                                           devdata, 1); // SPDRP_HARDWAREID

                // Uncomment to print name/path
                //Console.WriteLine(GetStringPropertyForDevice(info,
                //                         devdata, DEVPKEY_Device_DeviceDesc));
                //Console.WriteLine("   {0}", devicepath);
                if (devicepath != null && filter(devicepath)) break;

            }

            SP_CLASSINSTALL_HEADER header = new SP_CLASSINSTALL_HEADER();
            header.cbSize = (UInt32)Marshal.SizeOf(header);
            header.InstallFunction = DIF_PROPERTYCHANGE;

            SP_PROPCHANGE_PARAMS propchangeparams = new SP_PROPCHANGE_PARAMS();
            propchangeparams.ClassInstallHeader = header;
            propchangeparams.StateChange = disable ? DICS_DISABLE : DICS_ENABLE;
            propchangeparams.Scope = DICS_FLAG_GLOBAL;
            propchangeparams.HwProfile = 0;

            SetupDiSetClassInstallParams(info,
                ref devdata,
                ref propchangeparams,
                (UInt32)Marshal.SizeOf(propchangeparams));
            CheckError("SetupDiSetClassInstallParams");

            SetupDiChangeState(
                info,
                ref devdata);
            CheckError("SetupDiChangeState");
        }
        finally
        {
            if (info != IntPtr.Zero)
                SetupDiDestroyDeviceInfoList(info);
        }
    }
    private static void CheckError(string message, int lasterror = -1)
    {

        int code = lasterror == -1 ? Marshal.GetLastWin32Error() : lasterror;
        if (code != 0)
            throw new ApplicationException(
                String.Format("Error disabling hardware device (Code {0}): {1}",
                    code, message));
    }

    private static string GetStringPropertyForDevice(IntPtr info, SP_DEVINFO_DATA devdata,
        uint propId)
    {
        uint proptype, outsize;
        IntPtr buffer = IntPtr.Zero;
        try
        {
            uint buflen = 512;
            buffer = Marshal.AllocHGlobal((int)buflen);
            outsize=0;
            // CHANGE #2 - Use this instead of SetupDiGetDeviceProperty 
            SetupDiGetDeviceRegistryPropertyW(
                info,
                ref devdata,
                propId,
                out proptype,
                buffer,
                buflen,
                ref outsize);
            byte[] lbuffer = new byte[outsize];
            Marshal.Copy(buffer, lbuffer, 0, (int)outsize);
            int errcode = Marshal.GetLastWin32Error();
            if (errcode == ERROR_INVALID_DATA) return null;
            CheckError("SetupDiGetDeviceProperty", errcode);
            return Encoding.Unicode.GetString(lbuffer);
        }
        finally
        {
            if (buffer != IntPtr.Zero)
                Marshal.FreeHGlobal(buffer);
        }
    }

}

http://msdn.microsoft.com/en-us/library/windows/desktop/ms648383%28v=vs.85%29.aspx http://www.pinvoke.net/default.aspx/user32/ClipCursor.html

【讨论】:

  • 感谢您的建议,但我想避免剪裁。谢谢。
  • @ChronoFish 我的其他建议呢:只需以编程方式禁用设备?
  • 我不想禁用第二个鼠标。我的应用程序需要知道第二个鼠标何时被“点击”——但我不希望其他应用程序知道第二个鼠标何时被点击。
猜你喜欢
  • 1970-01-01
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-13
  • 1970-01-01
  • 2014-06-10
  • 1970-01-01
相关资源
最近更新 更多