【问题标题】:WndProc in my WPF app not 'handling' WM_INPUT event我的 WPF 应用程序中的 WndProc 没有“处理”WM_INPUT 事件
【发布时间】:2012-07-06 23:30:51
【问题描述】:

[编辑] 这是我迄今为止收集到的关于鼠标输入处理的内容。请注意,我是通过大量不同的来源和实验了解到这一点的,所以不要把它当作福音: 1) 鼠标事件源于鼠标移动 2) SetWindowsHookEx(WH_MOUSE_LL) 处理程序 LowLevelMouseProc 首先看到事件 3) 操作系统/应用程序框架在某个较高级别处理鼠标事件(鼠标光标移动) 4) WM_INPUT 事件被app 事件队列拾取并由WndProc 处理(虽然此时处理不会阻止鼠标光标在步骤3 中移动)。 5) 消息通过 ComponentDispatcher 分派 6) PreviewMouseMove 和 MouseMove 事件被触发并且可能由应用处理。

基于此,我认为确保鼠标光标不移动的唯一方法是通过WH_MOUSE_LL进行过滤。当然,正如我在本文前面提到的,此时没有足够的信息来知道这个鼠标事件来自哪个设备,所以它是全有或全无过滤,这不符合我的要求。


[编辑] 我已经验证我能够通过挂钩 WH_MOUSE_LL 并从处理程序返回大于 0 的值来删除事件。现在我只需要弄清楚如何将在 WH_MOUSE_LL 级别生成的鼠标事件与来自我的设备的事件相匹配...

我确实尝试从 WndProc 返回一个大于 0 的值。我的应用仍在处理该事件。


我正在尝试集成基于机械 USB 鼠标 Y 轴的旋转输入设备。我希望此设备仅作为原始输入设备运行,并希望删除设备生成的正常鼠标移动事件(至少在我的应用程序的上下文中)。

到目前为止,我已经能够使用 WindowIteropHandler 和 AddHook 将 WndProc 挂接到我的 WPF 应用程序 MainWindow 中。我能够从我的特定 USB VID/PID 设备接收 WM_INPUT 事件并过滤鼠标事件(足以满足我的需要)。

我希望将消息标记为已处理并返回 0 会导致消息不会传播到 WPF 窗口的其余部分,但事实并非如此......当我移动我的设备。这是我的代码(简化为删除处理 WM_INPUT 消息,但仍然出现相同的问题):

 public partial class MainWindow : Window
{
    private const int WM_INPUT = 0x00FF;

    public MainWindow()
    {
        InitializeComponent();
    }

    public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_INPUT)
        {
            // TODO - figure out why this doesn't halt further processing of this handled event
            handled = true;
        }
        return IntPtr.Zero;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWINPUTDEVICE
    {
        [MarshalAs(UnmanagedType.U2)]
        public ushort usUsagePage;
        [MarshalAs(UnmanagedType.U2)]
        public ushort usUsage;
        [MarshalAs(UnmanagedType.U4)]
        public int dwFlags;
        public IntPtr hwndTarget;
    }

    private const int RIDEV_INPUTSINK = 0x00000100;

    [DllImport("User32.dll")]
    extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);

    private void Window_SourceInitialized(object sender, EventArgs e)
    {
        WindowInteropHelper helper = new WindowInteropHelper(this);
        HwndSource source = HwndSource.FromHwnd(helper.Handle);
        RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];

        rid[0].usUsagePage  = 0x01;
        rid[0].usUsage      = 0x02;
        rid[0].dwFlags      = RIDEV_INPUTSINK; 
        rid[0].hwndTarget   = source.Handle;
        RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));

        source.AddHook(WndProc);
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        e.Handled = true;
    }

    private void button1_MouseMove(object sender, MouseEventArgs e)
    {
        e.Handled = true;
    }
}

任何人都知道如何使我在 WndProc 中处理的鼠标事件出列或阻止鼠标事件传播到 MainWindow?

TIA!

-马特

【问题讨论】:

  • 在MainWindow上使用PreviewMouseMove并设置e.Handled = true怎么样?
  • 谢谢。我认为处理 PreviewMouseMove 事件会过滤所有鼠标事件。我仍然想处理普通的鼠标事件,但要过滤来自我的特定鼠标设备的事件。
  • 啊是的,这是有道理的。前段时间我为多只鼠标使用 RawInputDevice 做了一些工作。看看我能不能再把它挖出来
  • 我对哪些工作正常,哪些不工作感到有些困惑。可以总结一下吗?
  • 我能够从辅助鼠标设备接收原始事件,但我无法导致这些事件被丢弃。尽管我为这些事件设置了handled=true,但来自我的原始设备的鼠标事件仍然会移动光标事件。我可以使用 LLMouseHook 删除鼠标事件,但此事件中没有足够的信息来确定鼠标事件来自哪个设备...

标签: c# wpf wndproc


【解决方案1】:

经过长时间的谷歌搜索,看起来其他人已经描述并解决了我使用 UMDF 尝试做的事情:http://oblita.com/Interception

我希望我不必去那里,但看起来这是实际拦截来自特定设备的事件的唯一方法。

【讨论】:

  • 几个月来我一直在努力解决这个问题,遇到了和你一样的障碍。我试图对事件进行排队以匹配它们,但我很高兴我阅读了这个线程,因为很明显这不起作用。我希望您提供的链接将是我正在寻找的答案 - 当然是迄今为止最接近的东西。
【解决方案2】:

我也遇到了这个问题,我通过运行我的应用程序以管理员权限解决了这个问题。

似乎WM_INPUT 消息受UIPI(用户界面特权隔离)的约束。在此处查看参考:

SendMessage, PostMessage, and Related Functions

虽然DefWindowProc() 方法会传递消息,但它不会将其处理到下一个应用程序。但是如果有以管理员身份运行的应用程序,如Task ManagerWindow Device Manager等,则权限较低的应用程序无法接收到上述应用程序传递的一些窗口消息。这个问题不仅是WN_IPUT,还有Hook

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 2015-02-02
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多