Как обрабатывать WM_MOUSEHWHEEL так, как это делает Проводник?

У меня мышь Logitech M705 с колесиком прокрутки, позволяющим прокручивать по горизонтали. Я успешно реализовал обработчик для этого события кнопки в своей программе C# (реализован как описано здесь), но пока я могу заставить его прокручиваться только один раз. В проводнике, когда я нажимаю колесико вправо, оно непрерывно прокручивается вправо, пока я не отпущу колесико. В моей программе он прокручивает только один шаг. Сообщение WM_MOUSEHWHEEL не видно пока не отпущу и снова не нажму на руль!

Вопрос. Как реализовать непрерывную горизонтальную прокрутку для сообщения WM_MOUSEHWHEEL?


person l33t    schedule 28.06.2012    source источник
comment
stackoverflow.com/questions/10999659 /, решение — VB.NET, но его легко перевести на C#.   -  person Viezevingertjes    schedule 28.06.2012
comment
Спасибо. Это почти то, что я уже реализовал. Проблема не в том, чтобы обработать сообщение. Проблема в том, что сообщение отправляется только один раз. Это также верно для Explorer.exe, поэтому я действительно не понимаю, как им удается получить непрерывную прокрутку. Я не вижу лишних сообщений в Spy++...   -  person l33t    schedule 28.06.2012


Ответы (2)


Добавьте это ко всем элементам управления (форма, дети и т. д.):

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);
    }
}

Суть в том, чтобы вернуть ненулевое значение для всех элементов управления, которые могут обработать сообщение!

person l33t    schedule 11.07.2012

Использовать 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);

Это подберет все сообщения Windows (хотя здесь захвачено только колесико мыши) - используя положение мыши, чтобы найти элемент управления, вы можете затем заставить окна отправлять сообщение этому элементу управления, даже если он не имеет фокуса.

ПРИМЕЧАНИЕ. Я использовал WindowsMessages.MOUSEWHEEL из класса, который перечисляет сообщения, просто замените

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

с комментарием в конце

if (m.Msg == 0x20a)

person Wolf5370    schedule 11.07.2012