Search code examples
c#.netwinformswinapipostmessage

Set Delta in a WM_MOUSEWHEEL message to send with PostMessage


How can I set the Delta parameter of the WM_MOUSEWHEEL message and send the message to a Windows using PostMessage?

My code:

[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

const uint WM_MOUSEWHEEL = 0x020A;

private int MAKELPARAM(int p, int p_2)
{
    return ((p_2 << 16) | (p & 0xFFFF));
}

Now I'm using it like this:

IntPtr hwnd1;
hwnd1 = FindWindow(null, "NoxPlayer");
Point location = new Point(1205,411);
PostMessage(hwnd1, WM_MOUSEWHEEL, 0, MAKELPARAM(location.X, location.Y));

When I do it like that I have:

enter image description here

The Windows doesn't scroll because delta is 0.


Solution

  • The WHEEL_DELTA is the default value of a mouse wheel increment (for mouse controllers with no freely-rotating wheel). This value is returned by SystemInformation.MouseWheelScrollDelta.
    It's usually set to 120, but it can be a different value.
    When the Delta value is positive, it indicates that the mouse wheel is rotated forward, causing a Window to scroll upwards, the opposite when Delta is negative.
    In the code sample, directionUp and directionDown determine this direction.

    The Delta can be set to a fraction or a multiple of the base increment (can be used to fine-tune the scrolling). See the Docs about WM_MOUSEWHEEL for more information.

    In the example, the wheel increment is divided in half (the float multiplier argument of the MAKEWPARAM macro is set to .5f).

    The Window identified by [Handle] doesn't need to be activated (it doesn't need to be the Foreground Window).

    The Cursor position represents Screen coordinates. The application should be DpiAware to handle Cursor positions and Screen coordinates correctly.
    See the notes about the VirtualScreen and how DpiAwareness is involved here:

    Using SetWindowPos with multiple monitors.

    int directionUp = 1;
    int directionDown = -1;
    
    // Scrolls [Handle] down by 1/2 wheel rotation with Left Button pressed
    IntPtr wParam = MAKEWPARAM(directionDown, .5f, WinMsgMouseKey.MK_LBUTTON);
    IntPtr lParam = MAKELPARAM(Cursor.Position.X, Cursor.Position.Y);
    
    PostMessage([Handle], WM_MOUSEWHEEL, wParam, lParam);
    

    internal const uint WM_MOUSEWHEEL = 0x020A;
    
    [Flags]
    public enum WinMsgMouseKey : int
    {
        MK_NONE = 0x0000,
        MK_LBUTTON = 0x0001,
        MK_RBUTTON = 0x0002,
        MK_SHIFT = 0x0004,
        MK_CONTROL = 0x0008,
        MK_MBUTTON = 0x0010,
        MK_XBUTTON1 = 0x0020,
        MK_XBUTTON2 = 0x0040
    }
    
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    internal static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    
    internal static IntPtr MAKEWPARAM(int direction, float multiplier, WinMsgMouseKey button)
    {
        int delta = (int)(SystemInformation.MouseWheelScrollDelta * multiplier);
        return (IntPtr)(((delta << 16) * Math.Sign(direction) | (ushort)button));
    }
    
    internal static IntPtr MAKELPARAM(int low, int high)
    {
        return (IntPtr)((high << 16) | (low & 0xFFFF));
    }