2011-11-05 51 views
22

除非移动光标,否则SendInput不会执行单击鼠标按钮。除非移动光标,否则SendInput不会执行单击鼠标按钮

我会很感激这一个帮助,因为我似乎无法把我的头围绕它。

我有一个程序,在前台窗口上执行鼠标点击,其中我使用SendInput来模拟鼠标左键单击。 问题是,如果我移动光标到点击位置比SendInput将点击,但是如果我不移动光标比没有点击甚至槽发生,我将x和y点传递给MouseInputData。我想在没有实际移动光标的情况下执行鼠标左键单击。

贝娄是类我有(它相当简单,挺直向前)

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); 
     }  
    } 
    } 

相同ClickLeftMouseButton功能不会,如果我删除越来越像光标位置点击。

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()));    
     } 

在此先感谢您。

+0

目前还不清楚你从哪里得到x和y坐标,以及它们的确切含义。缺少的MOUSEEVENTF_ABSOLUTE标志确实看起来像是一个问题。 –

回答

24

使用SendInput函数时,应该考虑几件事情。

如果您未指定MOUSEEVENTF_ABSOLUTE标志,则dxdy(MouseInputData结构)是当前鼠标位置的相对坐标。如果您指定MOUSEEVENTF_ABSOLUTE然后dxdy是0和65535所以,如果你的X和Y坐标是屏幕坐标,你应该使用下面的函数来计算dxdy之间的绝对坐标:

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); 
} 

您发送前进一步通过SendInput的MOUSEDOWN和MouseUp事件,你必须将鼠标移动到要点击控制:

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()));    
} 

上面的代码假定xy是屏幕像素坐标。您可以通过使用下面的代码计算在一个winform的按钮(目标)的坐标:

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

希望,这会有所帮助。

+2

非常感谢您的帮助,它实际上解释了我一直在想的一些事情。 – Dmitris

+1

谢谢。但是,如果不将鼠标移动到该坐标上,你知道该怎么做吗? (我想创建双鼠标)。 – Jet

+0

如何在不移动光标位置的情况下模拟鼠标点击?喜欢在问题中提到。 – tcboy88