SendInput doesn't perform click mouse button unless I move cursor

21,460

There are a few things you should consider when using the SendInput function.

If you do not specify the MOUSEEVENTF_ABSOLUTE flag then dx and dy (MouseInputData structure) are relative coordinates to the current mouse position. If you do specify MOUSEEVENTF_ABSOLUTE then dx and dy are absolute coordinates between 0 and 65535. So if your x and y coordinates are screen coordinates you should use the following function to calculate dx and dy:

enum SystemMetric
{
  SM_CXSCREEN = 0,
  SM_CYSCREEN = 1,
}

[DllImport("user32.dll")]
static extern int GetSystemMetrics(SystemMetric smIndex);

int CalculateAbsoluteCoordinateX(int x)
{
  return (x * 65536) / GetSystemMetrics(SystemMetric.SM_CXSCREEN);
}

int CalculateAbsoluteCoordinateY(int y)
{
  return (y * 65536) / GetSystemMetrics(SystemMetric.SM_CYSCREEN);
}

Furthermore before you send the MOUSEDOWN and MOUSEUP events to via SendInput you have to move the mouse to the control you want to click on:

public static void ClickLeftMouseButton(int x, int y)
{
  INPUT mouseInput = new INPUT();
  mouseInput.type = SendInputEventType.InputMouse;
  mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x);
  mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y);
  mouseInput.mkhi.mi.mouseData = 0;                     


  mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE |MouseEventFlags.MOUSEEVENTF_ABSOLUTE;
  SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));

  mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
  SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));

  mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
  SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));            
} 

The above code assumes that x and y are screen pixel coordinates. You can calculate those coordinates for a button (the target) on a winform by using the following code:

 Point screenCoordsCentre=
button1.PointToScreen(new Point(button1.Width/2, button1.Height/2));

Hope, this helps.

Share:
21,460

Related videos on Youtube

Dmitris
Author by

Dmitris

Updated on December 01, 2020

Comments

  • Dmitris
    Dmitris over 3 years

    SendInput doesn't perform click mouse button unless I move cursor.

    I would appreciate a help on this one, as I seems cannot wrap my head around it.

    I have a program that perform mouse click on foreground window, in which I am using SendInput to emulate left mouse click. The issue is, that if I move cursor to clicking position than SendInput will make the click, however if I don't move cursor than no click happens even trough I do pass x and y points to the MouseInputData. I would like to perform left mouse click without the need of actually moving the cursor at all.

    Bellow is the class I have (it fairly simple and stright forward)

    namespace StackSolution.Classes
    {
        public static class SendInputClass
        {
    
            [DllImport("user32.dll", SetLastError = true)]
            static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
    
            [DllImport("user32.dll")]
            static extern bool SetCursorPos(int X, int Y);
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool GetCursorPos(out Point lpPoint);
    
    
    
            [StructLayout(LayoutKind.Sequential)]
            struct INPUT
            {
                public SendInputEventType type;
                public MouseKeybdhardwareInputUnion mkhi;
            }
            [StructLayout(LayoutKind.Explicit)]
            struct MouseKeybdhardwareInputUnion
            {
                [FieldOffset(0)]
                public MouseInputData mi;
    
                [FieldOffset(0)]
                public KEYBDINPUT ki;
    
                [FieldOffset(0)]
                public HARDWAREINPUT hi;
            }
            [StructLayout(LayoutKind.Sequential)]
            struct KEYBDINPUT
            {
                public ushort wVk;
                public ushort wScan;
                public uint dwFlags;
                public uint time;
                public IntPtr dwExtraInfo;
            }
            [StructLayout(LayoutKind.Sequential)]
            struct HARDWAREINPUT
            {         
                public int uMsg;
                public short wParamL;
                public short wParamH;
            }
            struct MouseInputData
            {
                public int dx;
                public int dy;
                public uint mouseData;
                public MouseEventFlags dwFlags;
                public uint time;
                public IntPtr dwExtraInfo;
            }
            [Flags]
            enum MouseEventFlags : uint
            {
                MOUSEEVENTF_MOVE = 0x0001,
                MOUSEEVENTF_LEFTDOWN = 0x0002,
                MOUSEEVENTF_LEFTUP = 0x0004,
                MOUSEEVENTF_RIGHTDOWN = 0x0008,
                MOUSEEVENTF_RIGHTUP = 0x0010,
                MOUSEEVENTF_MIDDLEDOWN = 0x0020,
                MOUSEEVENTF_MIDDLEUP = 0x0040,
                MOUSEEVENTF_XDOWN = 0x0080,
                MOUSEEVENTF_XUP = 0x0100,
                MOUSEEVENTF_WHEEL = 0x0800,
                MOUSEEVENTF_VIRTUALDESK = 0x4000,
                MOUSEEVENTF_ABSOLUTE = 0x8000
            }
            enum SendInputEventType : int
            {
                InputMouse,
                InputKeyboard,
                InputHardware
            }
    
            public static void ClickLeftMouseButton(int x, int y)
            {
                INPUT mouseInput = new INPUT();
                mouseInput.type = SendInputEventType.InputMouse;
                mouseInput.mkhi.mi.dx = x;
                mouseInput.mkhi.mi.dy = y;
                mouseInput.mkhi.mi.mouseData = 0;
    
                //getting current cursor location
                Point p;
                if (GetCursorPos(out p))
                    SetCursorPos(x, y);
    
    
                mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
                SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
    
                mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
                SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
    
                //returning cursor to previous position
                SetCursorPos(p.X, p.Y);
            }    
        }
      }
    

    Same ClickLeftMouseButton function will not click if I remove getting cursor position like that.

       public static void ClickLeftMouseButton(int x, int y)
            {
                INPUT mouseInput = new INPUT();
                mouseInput.type = SendInputEventType.InputMouse;
                mouseInput.mkhi.mi.dx = x;
                mouseInput.mkhi.mi.dy = y;
                mouseInput.mkhi.mi.mouseData = 0;                     
    
    
                mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
                SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
    
                mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
                SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));            
            }   
    

    Thank you in advance.

    • user1703401
      user1703401 over 12 years
      It isn't clear where you are getting the x and y coordinates from and what they exactly mean. The missing MOUSEEVENTF_ABSOLUTE flag does look like a problem.
  • Dmitris
    Dmitris over 12 years
    Thanks a lot for the help, it actually explains few things I have been wondering about.
  • Jet
    Jet almost 11 years
    Thanks. But do you know how to do it without moving the mouse to that cordinate? (I want to create double-mouse).
  • tcboy88
    tcboy88 almost 10 years
    how to simulate mouse click without moving the cursor position first? liked mentioned in the question.
  • tcboy88
    tcboy88 almost 10 years
    simulate mouse clicks without moving the cursor position first. The cursor position should remain in where it was.
  • Hans
    Hans almost 10 years
    @tcboy88: The only way I can think of is using Windows messages such as WM_LBUTTONDOWN and the Win32 API SendMessage.