3

I was trying to simulate (global) mouse click using SendInput() from user32 dll in C# .NET. I have already tried SendInput() for keyboard input and it works fine. But for some reasons it doesn't work for mouse input.

here is my code,

For simplicity, I have not put the definition for KEYBDINPUT and HARDWAREINPUT (struct). as MOUSEINPUT is only relevant here.

    [DllImport("user32.dll")]
    internal static extern uint SendInput(uint nInputs,  [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);

    //main calling method
    public static void CLICK()
    {
        INPUT []i = new INPUT[1];

        i[0].type = 0;
        i[0].U.mi.time = 0;
        i[0].U.mi.dwFlags = MOUSEEVENTF.LEFTDOWN | MOUSEEVENTF.ABSOLUTE;
        i[0].U.mi.dwExtraInfo = UIntPtr.Zero;
        i[0].U.mi.dx = 1;
        i[0].U.mi.dy = 1;

        SendInput(1, i, INPUT.Size);
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct INPUT
    {
        internal uint type;
        internal InputUnion U;
        internal static int Size
        {
            get { return Marshal.SizeOf(typeof(INPUT)); }
        }
    }

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

    [StructLayout(LayoutKind.Sequential)]
    internal struct MOUSEINPUT
    {
        internal long dx;
        internal long dy;
        internal int mouseData;
        internal MOUSEEVENTF dwFlags;
        internal uint time;
        internal UIntPtr dwExtraInfo;
    }

    [Flags]
    internal enum MOUSEEVENTF : uint
    {
        ABSOLUTE = 0x8000,
        HWHEEL = 0x01000,
        MOVE = 0x0001,
        MOVE_NOCOALESCE = 0x2000,
        LEFTDOWN = 0x0002,
        LEFTUP = 0x0004,
        RIGHTDOWN = 0x0008,
        RIGHTUP = 0x0010,
        MIDDLEDOWN = 0x0020,
        MIDDLEUP = 0x0040,
        VIRTUALDESK = 0x4000,
        WHEEL = 0x0800,
        XDOWN = 0x0080,
        XUP = 0x0100
    }

Also, I have tried different points for x,y. and other dwFlags as well, (such as LEFTUP, MOVE..) but nothing worked so far.

Fahim Mahbub
  • 41
  • 1
  • 3

1 Answers1

2

For internal long dx; and dy, I have int type in my struct MOUSEINPUT.

As per MOUSEINPUT documentation dx and dy are LONG.

But LONG in C++ is "at least" 32 bit and long in C# is 64 bit. Thus it matches C# int. (details)

[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
    internal int dx;
    internal int dy;
    internal int mouseData;
    internal MOUSEEVENTF dwFlags;
    internal uint time;
    internal UIntPtr dwExtraInfo;
}
aepot
  • 4,558
  • 2
  • 12
  • 24
  • That worked but do you have any idea why **MOUSEINPUT.time** / **KEYBDINPUT.time** doesn't work? According to the [documentation](https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput) , The **MOUSEINPUT.time** is used for the time stamp of the event. I am considering this as a time delay before each input is being processed. or does it mean anything else? – Fahim Mahbub Jul 18 '20 at 06:42
  • @FahimMahbub I did not test that. I know that for keyboard it has embedded delay when I send bulk input e.g. modified keystroke with single `SendInput` call. Maybe that delay time relative and works only if you send more than one Input item in the `INPUT[]` array. – aepot Jul 18 '20 at 07:14
  • @aepot you can't use the `time` field to cause actually delays. That is not what it is meant for. You need to put actual delays in between your `SendInput` calls instead – Remy Lebeau Jul 18 '20 at 20:53
  • @RemyLebeau Thanks for correction. That was a guess, I didn't try it. – aepot Jul 18 '20 at 20:55
  • 3
    [When you synthesize input with SendInput, you are also synthesizing the timestamp](https://devblogs.microsoft.com/oldnewthing/20121101-00/?p=6193). – IInspectable Jul 19 '20 at 16:32