【问题标题】:SendInput doesn't perform click mouse button unless I move cursor除非我移动光标,否则 SendInput 不会执行单击鼠标按钮
【发布时间】:2011-12-22 17:52:53
【问题描述】:

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

我会很感激这方面的帮助,因为我似乎无法理解它。

我有一个在前景窗口上执行鼠标单击的程序,在该程序中我使用 SendInput 来模拟鼠标左键单击。 问题是,如果我将光标移动到单击位置,则 SendInput 将进行单击,但是如果我不移动光标,则即使通过 x 和 y 指向 MouseInputData 也不会发生单击。我想在根本不需要实际移动光标的情况下执行鼠标左键。

Bellow 是我的课程(相当简单直接)

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

提前谢谢你。

【问题讨论】:

  • 不清楚您从哪里获得 x 和 y 坐标以及它们的确切含义。缺少 MOUSEEVENTF_ABSOLUTE 标志看起来确实是个问题。

标签: c# winforms winapi mouse mouseevent


【解决方案1】:

在使用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));

希望,这会有所帮助。

【讨论】:

  • 非常感谢您的帮助,它实际上解释了我一直想知道的一些事情。
  • 谢谢。但是您知道如何在不将鼠标移动到该坐标的情况下做到这一点吗? (我想创建双鼠标)。
  • 如何在不先移动光标位置的情况下模拟鼠标点击?喜欢问题中提到的。
  • 模拟鼠标点击而不首先移动光标位置。光标位置应保持在原来的位置。
  • @tcboy88:我能想到的唯一方法是使用 Windows 消息,例如 WM_LBUTTONDOWN 和 Win32 API SendMessage。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 2016-10-15
  • 1970-01-01
  • 2015-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多