C# SendInput will not move correctly when using it in a loop

77 views Asked by At

Situation:

Today I am trying to optimize my remote control, and I need to use SendInput, which is in the class library, to move the mouse from one place to another continuously. However, I found that if you use SendInput in a loop in C#, the behavior becomes unexpected (what originally moved to the right will move upward, and the moving distance is also random).

What I have tried:

  • I tried to use my Simulate class without looping, but there is nothing wrong if I just use it to move my mouse to a target place.
  • I tried to trace the code but I can not find anything wrong.

Envirement:

  • Windows 11 family
  • VS2022 community
  • .NET Framework class library (4.8)

Code:

Normal case:

int CursorX = Cursor.Position.X;
int CursorY = Cursor.Position.Y;

for (int i = 0; i < 100; i++)
{

    Simulator.MouseSimulator.MoveMouse((ushort)(CursorX + i), (ushort)(CursorY ), SCREENWIDTH, SCREENHEIGHT);
    Thread.Sleep(2);
}

In this case, it will work.

Unexpected case:

for (int i = 0; i < 100; i++)
{
    int CursorX = Cursor.Position.X;
    int CursorY = Cursor.Position.Y;
    Simulator.MouseSimulator.MoveMouse((ushort)(CursorX + MOVESPACE), (ushort)(CursorY ), SCREENWIDTH, SCREENHEIGHT);
    Thread.Sleep(2);
}

In this case, the mouse will move top and move less than 100px on my computer.

Class code (just library to call SendInput API):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static System.Collections.Specialized.BitVector32;

namespace Simulator
{
    public static class MouseSimulator
    {
        [DllImport("user32.dll", SetLastError = true)]
        public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
        private const double LEN = 65536;
        public static uint MoveMouse(ushort x, ushort y, int screenWidth, int screenHeight, uint recordTime = 0, IntPtr additionalInfo = default(IntPtr))
        {
            MOUSEINPUT mouseInput = new MOUSEINPUT();

            mouseInput.dx = (int)(x * (LEN / screenWidth));
            mouseInput.dy = (int)(y * (LEN / screenHeight));
            mouseInput.dwFlags = (uint)(MouseEventFlags.ABSOLUTE | MouseEventFlags.MOVE);
            mouseInput.time = recordTime;
            mouseInput.dwExtraInfo = additionalInfo;

            InputUnion union = new InputUnion();
            union.mi = mouseInput;

            INPUT[] input = new INPUT[1];
            input[0].type = (uint)InputTypes.MOUSE;
            input[0].U = union;
            return SendInput(1, input, Marshal.SizeOf(typeof(INPUT)));
        }
        public static uint SimulateMouse(MouseEventFlags action, uint mouseData = 0, uint recordTime = 0, IntPtr additionalInfo = default(IntPtr))
        {

            MOUSEINPUT mouseInput = new MOUSEINPUT();

            //if (x != -1) mouseInput.dx = (int)(x * (65535F / screenWidth));
            //if (y != -1) mouseInput.dy = (int)(y * (65535F / screenHeight));
            mouseInput.mouseData = mouseData;
            mouseInput.dwFlags = (uint)(MouseEventFlags.ABSOLUTE | action);
            mouseInput.time = recordTime;
            mouseInput.dwExtraInfo = additionalInfo;

            InputUnion union = new InputUnion();
            union.mi = mouseInput;

            INPUT[] input = new INPUT[1];
            input[0].type = (uint)InputTypes.MOUSE;
            input[0].U = union;
            return SendInput(1, input, Marshal.SizeOf(typeof(INPUT)));
        }

    }

    public enum InputTypes : uint
    {
        MOUSE = 0,
        KEYBOARD = 1,
        HARDWARE = 2
    }
    public enum MouseEventFlags : uint
    {
        ABSOLUTE = 0x8000,
        LEFTDOWN = 0x0002,
        LEFTUP = 0x0004,
        MIDDLEDOWN = 0x0020,
        MIDDLEUP = 0x0040,
        MOVE = 0x0001,
        RIGHTDOWN = 0x0008, 
        RIGHTUP = 0x0010,
        WHEEL = 0x0800,
        XDOWN = 0x0080,
        XUP = 0x0100, 
        HWHEEL = 0x01000 
    }
    public enum KeyEventFlags : ushort
    {
        KEYDOWN = 0x0000,
        EXTENDEDKEY = 0x0001,
        KEYUP = 0x0002,
        UNICODE = 0x0004,
        SCANCODE = 0x0008 
    }


    [StructLayout(LayoutKind.Sequential)]
    public struct INPUT
    {
        public uint type;
        public InputUnion U;
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct InputUnion
    {
        [FieldOffset(0)]
        public MOUSEINPUT mi;
        [FieldOffset(0)]
        public KEYBDINPUT ki;
        [FieldOffset(0)]
        public HARDWAREINPUT hi;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MOUSEINPUT
    {
        public int dx;
        public int dy;
        public uint mouseData;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct KEYBDINPUT
    {
        public ushort wVk;
        public ushort wScan;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct HARDWAREINPUT
    {
        public uint uMsg;
        public ushort wParamL;
        public ushort wParamH;
    }

}

What I want:

I want to know why this situation will happen and how to solve it.

0

There are 0 answers