【问题标题】:How to handle WM_MOUSEHWHEEL the way Explorer does it?如何以 Explorer 的方式处理 WM_MOUSEHWHEEL?
【发布时间】:2012-07-11 23:06:27
【问题描述】:

我有带滚轮的罗技 M705 鼠标,允许水平滚动。我已经在我的 C# 程序中成功地为这个按钮事件实现了一个处理程序(按照here 的描述实现),但到目前为止我只能让它滚动一次。在资源管理器中,当我向右按下滚轮时,它会连续向右滚动,直到我松开滚轮。在我的程序中,它只滚动一步。 WM_MOUSEHWHEEL 消息直到我松开并再次按下滚轮后才会看到!

问:您如何为WM_MOUSEHWHEEL 消息实现连续水平滚动?

【问题讨论】:

  • stackoverflow.com/questions/10999659/…,解决方案是 VB.NET,但很容易翻译成 C#。
  • 谢谢。这几乎就是我已经实现的。问题不在于处理消息。问题是消息只发送一次。 Explorer.exe 也是如此,所以我真的不明白他们如何设法获得连续滚动。我在 Spy++ 中看不到任何额外的消息...

标签: c# scroll mousewheel


【解决方案1】:

将此添加到所有控件(表单、子控件等):

protected override void WndProc(ref System.Windows.Forms.Message m)
{
    base.WndProc(ref m);

    const int WM_MOUSEHWHEEL = 0x020E;
    if (m.Msg == WM_MOUSEHWHEEL)
    {
        m.Result = new IntPtr(HIWORD(m.WParam) / WHEEL_DELTA);
    }
}

关键是为所有可能处理消息的控件返回一个非零值!

【讨论】:

    【解决方案2】:

    使用 IMessageFilter

        public partial class MyForm: Form, IMessageFilter
    ...
     public ImageForm(Image initialImage)
            {
                InitializeComponent();            
                Application.AddMessageFilter(this);
            }
    
    /// <summary>
            /// Filters out a message before it is dispatched.
            /// </summary>
            /// <returns>
            /// true to filter the message and stop it from being dispatched; false to allow the message to continue to the next filter or control.
            /// </returns>
            /// <param name="m">The message to be dispatched. You cannot modify this message. </param><filterpriority>1</filterpriority>
            public bool PreFilterMessage( ref Message m )
            {
                if (m.Msg.IsWindowMessage(WindowsMessages.MOUSEWHEEL))  //if (m.Msg == 0x20a)
                {   // WM_MOUSEWHEEL, find the control at screen position m.LParam      
                    var pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
                    var hWnd = WindowFromPoint(pos);
                    if (hWnd != IntPtr.Zero && hWnd != m.HWnd && FromHandle(hWnd) != null)
                    {
                        SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
                        return true;
                    }
                }
    
                return false;
            }
    
    
            [DllImport("user32.dll")]
            private static extern IntPtr WindowFromPoint(Point pt);
    
            [DllImport("user32.dll")]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    

    也在表格结束时添加:

    Application.RemoveMessageFilter(this);
    

    这将获取所有窗口消息(尽管此处仅捕获鼠标滚轮)-通过使用鼠标位置找到控件,然后您可以强制窗口将消息发送到该控件,即使它没有焦点。

    注意:我使用了 WindowsMessages.MOUSEWHEEL,它来自一个枚举消息的类,只需替换

    if (m.Msg.IsWindowMessage(WindowsMessages.MOUSEWHEEL))
    

    最后加上注释

    if (m.Msg == 0x20a)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-21
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      相关资源
      最近更新 更多