Send mouse wheel click properly (SendInput MouseEventFlag MiddleDown/ Up)

youki 1,021 Reputation points
2021-02-02T12:17:37.347+00:00

Hello,
I tested it a few hours but i can't figure it out and i couldn't find something on the internet.
https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput

The problem is that when I test it, it has a variety of misbehavior; until I have to restart my PC because I can no longer click the left mouse button properly.

Do i have to use the MiddleDown and MiddleUp separated depending on the keystate or something like that?

For i.e.: Clicking the browser the 1st time (MiddleDown - if keystate up) to get this weird arrow (i don't know the name for this control) and a 2nd click (MiddleUp - if keystate down) to remove the arrow.

Sorry, can't post the code, i'm getting the following error:
WAF v2 has determined your request exceeded the normal web request and has blocked your request.

63008-mousemiddlebutton.png

I forgot to say: If i'm using the code above, it starts laging when i use it multiple times in a row and causes the misbehaviour.

Regards

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,908 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,117 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Castorix31 86,316 Reputation points
    2021-02-02T16:35:36.467+00:00

    This test with MS Edge seems to work fine for me (I get the mouse wheel cursor, if the current page can be scrolled) =>

    IntPtr hWndEdge = IntPtr.Zero;
    Process[] procsEdge = Process.GetProcessesByName("msedge");
    if (procsEdge.Length <= 0)
    {
        Console.WriteLine("MS Edge is not running");
    }
    else
    {
        foreach (Process proc in procsEdge)
        {
            if (proc.MainWindowHandle == IntPtr.Zero)
            {
                continue;
            }
            else
            {
                hWndEdge = proc.MainWindowHandle;
                break;
            }
        }
    }
    if (hWndEdge != IntPtr.Zero)
    {
        SwitchToThisWindow(hWndEdge, true);
    
        RECT rc = new RECT();
        GetWindowRect(hWndEdge, out rc);
    
        int nScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
        int nScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
        int nScreenLeft = GetSystemMetrics(SM_XVIRTUALSCREEN);
        int nScreenTop = GetSystemMetrics(SM_YVIRTUALSCREEN);
    
        int nXMove = rc.left + (rc.right - rc.left) / 2;
        int nYMove = rc.top + (rc.bottom - rc.top) / 2;
        int nX = (int)((((double)(nXMove) - nScreenLeft) * 65536) / nScreenWidth + 65536 / (nScreenWidth));
        int nY = (int)((((double)(nYMove) - nScreenTop) * 65536) / nScreenHeight + 65536 / (nScreenHeight));
    
        INPUT[] mi = new INPUT[3];
        mi[0].type = INPUT_MOUSE;
        mi[0].inputUnion.mi.dx = nX;
        mi[0].inputUnion.mi.dy = nY;
        mi[0].inputUnion.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
        //mi[1].inputUnion.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN;
        //mi[2].inputUnion.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP;
        mi[1].inputUnion.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MIDDLEDOWN;
        mi[2].inputUnion.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MIDDLEUP;                    
    
        SendInput(3, mi, Marshal.SizeOf(mi[0]));
    }
    

    Declarations :

    [DllImport("User32.dll", SetLastError = true)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
        public RECT(int Left, int Top, int Right, int Bottom)
        {
            left = Left;
            top = Top;
            right = Right;
            bottom = Bottom;
        }
    }
    
    [DllImport("User32.dll", SetLastError = true)]
    public static extern bool SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
    
    [DllImport("User32.dll", SetLastError = false)]
    public static extern IntPtr GetDesktopWindow();
    
    public const int INPUT_MOUSE = 0;
    public const int INPUT_KEYBOARD = 1;
    public const int INPUT_HARDWARE = 2;
    
    public const int MOUSEEVENTF_MOVE = 0x0001; /* mouse move */
    public const int MOUSEEVENTF_LEFTDOWN = 0x0002; /* left button down */
    public const int MOUSEEVENTF_LEFTUP = 0x0004; /* left button up */
    public const int MOUSEEVENTF_RIGHTDOWN = 0x0008; /* right button down */
    public const int MOUSEEVENTF_RIGHTUP = 0x0010; /* right button up */
    public const int MOUSEEVENTF_MIDDLEDOWN = 0x0020; /* middle button down */
    public const int MOUSEEVENTF_MIDDLEUP = 0x0040; /* middle button up */
    public const int MOUSEEVENTF_XDOWN = 0x0080; /* x button down */
    public const int MOUSEEVENTF_XUP = 0x0100; /* x button down */
    public const int MOUSEEVENTF_WHEEL = 0x0800; /* wheel button rolled */
    public const int MOUSEEVENTF_HWHEEL = 0x01000; /* hwheel button rolled */
    public const int MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000; /* do not coalesce mouse moves */
    public const int MOUSEEVENTF_VIRTUALDESK = 0x4000; /* map to entire virtual desktop */
    public const int MOUSEEVENTF_ABSOLUTE = 0x8000; /* absolute move */
    
    [DllImport("User32.dll", SetLastError = true)]
    public static extern int GetSystemMetrics(int nIndex);
    
    public const int SM_XVIRTUALSCREEN = 76;
    public const int SM_YVIRTUALSCREEN = 77;
    public const int SM_CXVIRTUALSCREEN = 78;
    public const int SM_CYVIRTUALSCREEN = 79;
    
    public const int KEYEVENTF_EXTENDEDKEY = 0x0001;
    public const int KEYEVENTF_KEYUP = 0x0002;
    public const int KEYEVENTF_UNICODE = 0x0004;
    public const int KEYEVENTF_SCANCODE = 0x0008;
    
    [StructLayout(LayoutKind.Sequential)]
    public struct MOUSEINPUT
    {
        public int dx;
        public int dy;
        public int mouseData;
        public int dwFlags;
        public int time;
        public IntPtr dwExtraInfo;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct KEYBDINPUT
    {
        public short wVk;
        public short wScan;
        public int dwFlags;
        public int time;
        public IntPtr dwExtraInfo;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct HARDWAREINPUT
    {
        public int uMsg;
        public short wParamL;
        public short wParamH;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct INPUT
    {
        public int type;
        public INPUTUNION inputUnion;
    }
    
    [StructLayout(LayoutKind.Explicit)]
    public struct INPUTUNION
    {
        [FieldOffset(0)]
        public MOUSEINPUT mi;
        [FieldOffset(0)]
        public KEYBDINPUT ki;
        [FieldOffset(0)]
        public HARDWAREINPUT hi;
    }
    
    [DllImport("User32.dll", SetLastError = true)]
    public static extern int SendInput(int nInputs, [MarshalAs(UnmanagedType.LPArray)] INPUT[] pInput, int cbSize);
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.