2

フォームでフォーカス (outlook スタイル) を使用せずにマウスの位置でコントロールをスクロールするロジックを作成しています。IMessageFilter を使用してこの動作を実現できます。ただし、「SHIFT」キーを押すと、水平スクロールを適用するのが難しくなります。

using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;


public partial class UI : Form
{
    MouseWheelMessageFilter mouseFilter = null;
    public UI()
    {
        InitializeComponent();
        mouseFilter = new MouseWheelMessageFilter();
        Application.AddMessageFilter(mouseFilter);
        this.FormClosed += (o, e) => Application.RemoveMessageFilter(mouseFilter);
    }
}

public class MouseWheelMessageFilter : IMessageFilter
{
    [DllImport("user32.dll")]
    public static extern IntPtr WindowFromPoint(Point pt);

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);


    public const int MK_CONTROL = 0x0008;
    public const int MK_SHIFT = 0x0004;

    public const int WM_MOUSEWHEEL = 0x020A;
    public const int WM_MOUSEHWHEEL = 0x020E;


    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_MOUSEWHEEL)
        {
            var shiftKeyDown = (char)((Keys)m.WParam) == MK_SHIFT;

            //apply the scroll to the control at mouse location
            Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
            IntPtr hWnd = WindowFromPoint(pos);

            if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null)
            {
                if (shiftKeyDown)
                    //TODO: Horizontal scroll - Not working WM_MOUSEHWHEEL (0x020E)
                    //SendMessage(hWnd, WM_MOUSEHWHEEL, m.WParam, m.LParam);
                else
                    //Vertical Scroll - working
                    SendMessage(hWnd, WM_MOUSEWHEEL, m.WParam, m.LParam);
                return true;
            }
        }           
        return false;
    }
}

水平スクロールを機能させるには、//TODO セクションで何をする必要がありますか?

4

1 に答える 1

2

これは単なる推測であり、自分でテストすることはできませんが、次のもののみをフィルタリングしていることに気付きました。

if (m.Msg == WM_MOUSEWHEEL)

WM_MOUSEHWHEEL を個別にフィルタリングする必要がありますか:

if (m.Msg == WM_MOUSEHWHEEL)

それでは、おそらくシフトキーをテストする必要はありませんか?

編集:これは私が考えていたことです:

public bool PreFilterMessage(ref Message m)
{
    if (m.Msg == WM_MOUSEWHEEL || m.Msg == WM_MOUSEHWHEEL)
    {
        //apply the scroll to the control at mouse location
        Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
        IntPtr hWnd = WindowFromPoint(pos);
        if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null)
        {
            SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
            return true;
        }
    }
    return false;
}

これが機能しない場合は申し訳ありませんが、これをコンパイルしてテストすることはできません。ユーザーが SHIFT を押したままにしている場合は WM_MOUSEWHEEL を取得できないと推測されます (代わりに WM_MOUSEHWHEEL を取得します)。

于 2013-10-14T10:47:39.880 に答える