2

当我按下修饰键(shift 或 control)单击时,我的 WndProc 没有看到鼠标向上通知。我看到它们没有修饰键,我看到带有修饰键的鼠标按下通知。

我正在尝试跟踪我没有编写的组件中的用户操作,因此我使用 Windows 窗体 NativeWindow 包装器(包装组件)从 WndProc() 方法获取 Windows 消息。

我尝试跟踪收到的通知,我看到的唯一线索是 WM_CAPTURECHANGED。当我收到 WM_LBUTTONDOWN 消息时,我尝试调用 SetCapture,但它没有帮助。

没有修饰符(跳过油漆、计时器和 NCHITTEST 消息):

WM_PARENTNOTIFY
WM_MOUSEACTIVATE
WM_MOUSEACTIVATE
WM_SETCURSOR
WM_LBUTTONDOWN
WM_SETCURSOR
WM_MOUSEMOVE
WM_SETCURSOR
WM_LBUTTONUP

使用修饰符(跳过油漆、计时器和 NCHITTEST 消息):

WM_KEYDOWN
WM_PARENTNOTIFY
WM_MOUSEACTIVATE
WM_MOUSEACTIVATE
WM_SETCURSOR
WM_LBUTTONDOWN
WM_SETCURSOR (repeats)
WM_KEYDOWN (repeats)
WM_KEYUP

如果我长时间按住鼠标按钮,我通常可以收到 WM_LBUTTONUP 通知,但应该可以使其更具响应性..

编辑:在释放鼠标按钮之前,我尝试在感兴趣的组件外部进行控制单击并将光标移动到其中,然后我确实收到了 WM_LBUTTONUP 通知,所以看起来组件在鼠标按下时正在捕获鼠标. 当另一个窗口捕获鼠标时,有什么方法可以接收该通知?

谢谢。

4

5 回答 5

2

通常,当鼠标在(本机)Windows 控件上单击时,会进入某种模态跟踪循环来管理“拖动”操作。在模态循环期间,消息直接从消息队列中提取并处理 - 鼠标向上通知将是模态循环的终止条件之一,因此通常在不被调度的情况下被消耗。

您可以单击桌面上的其他位置,将鼠标移到窗口上并释放并看到单击吗?这表明鼠标按下消息触发了某种模式代码。


我可以想到四种方法可以解决这个问题。

  • 找出控件支持的拖动操作类型 - 并禁用它。希望如果内置的 WindowProc 知道不允许模态拖动,它不会进入模态循环。
  • 防止 WindowProc 发现模态拖动:即拦截并且不要将任何 WM_LBUTTONDOWN 消息传递给链中的下一个 Windowproc。
  • 使用 SetWindowsHookEx 安装消息挂钩。

所有这些解决方案都是非常 Windows API。不知道它们在托管环境中是如何翻译的。

于 2010-05-26T05:33:36.550 回答
0

在您的处理程序中,您需要在收到 WM_LBUTTONUP 消息时检查 WPARAM 键。

http://msdn.microsoft.com/en-us/library/ms645608%28VS.85%29.aspx

于 2010-05-25T18:44:06.533 回答
0

如果组件捕获鼠标消息,则 WM_LBUTTONUP 消息可能会绕过您的包装器并直接转到组件。

于 2010-05-25T21:59:34.983 回答
0

默认情况下,修饰符和导航键保留供操作系统内部使用。默认键盘处理程序解释它们并根据需要根据它们生成适当的消息。如果控件想要直接对它们进行操作,它需要处理WM_GETDLGCODE消息,可选地使用包含适当DLGC_WANT...标志的结果,例如DLGC_WANTALLKEYSDLGC_WANTARROWS,因此键作为普通消息传递到消息队列(例如,DLGC_WANTALLKEYS将生成WM_KEYDOWN/UP消息)。

于 2010-05-26T20:48:46.580 回答
0

使用Application.AddMessageFilter将处理程序添加到本机消息泵。像这样的东西:

[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
private class ZoomGestureHandler : IMessageFilter
{
    private const UInt32 WM_MOUSEWHEEL = 0x20A;
    private const UInt32 MK_CONTROL = 0x08;

    private readonly ImageListView _target;

    public ZoomGestureHandler(ImageListView target)
    {
        _target = target;
    }

    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg != WM_MOUSEWHEEL)
        {
            // Not a mouse wheel message
            return false;
        }

        int wheelDelta = HiWord(m.WParam.ToInt32());
        int keyState = LoWord(m.WParam.ToInt32());

        // Mouse wheel scrolled while the Control key was down
        if ((wheelDelta != 0) && (MK_CONTROL == keyState))
        {
            // Hit test the mouse location
            int xPos = LoWord(m.LParam.ToInt32());
            int yPos = HiWord(m.LParam.ToInt32());

            Point controlLocation = _target.Parent.PointToScreen(_target.Location);
            if ((xPos >= controlLocation.X) && (xPos < (controlLocation.X + _target.Width))
                && (yPos >= controlLocation.Y) && (yPos < (controlLocation.Y + _target.Height)))
            {
                // Determine whether to zoom in or out
                if (wheelDelta > 0)
                {
                    _target.ViewModel.TryZoomIn();
                }
                if (wheelDelta < 0)
                {
                    _target.ViewModel.TryZoomOut();
                }
            }
        }
        return false;
    }

    private static int HiWord(int number)
    {
        if ((number & 0x80000000) == 0x80000000)
            return (number >> 16);
        return (number >> 16) & 0xffff;
    }

    private static int LoWord(int number)
    {
        return number & 0xffff;
    }
}

该示例并非特定于您的特定目标,但您可以对其进行修改以适应。刚好是我最近写的一篇。

于 2010-05-26T22:02:12.400 回答