【问题标题】:programmatically mouse click in another window以编程方式在另一个窗口中单击鼠标
【发布时间】:2012-05-08 11:26:06
【问题描述】:

是否可以以编程方式单击另一个窗口中的某个位置,而无需将鼠标移动到该位置,即使该窗口不在顶部?我想向另一个窗口发送一种消息以模拟鼠标单击某个位置。

我尝试使用 PostMessage 来完成此操作:

PostMessage(WindowHandle, 0x201, IntPtr.Zero, CreateLParam(300,300));
PostMessage(WindowHandle, 0x202, IntPtr.Zero, CreateLParam(300,300));

我这样创建了 CreateLParam 函数:

private static IntPtr CreateLParam(int LoWord, int HiWord)
{
     return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
}

问题是窗口被锁定在他的位置。我认为我的应用程序点击了 (1,1) 坐标。有人可以帮我解决这个问题吗?

编辑: 这是 PostMessage:

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr WindowHandle, int Msg, IntPtr wParam, IntPtr lParam);

而0x201和0x202分别是WM_LBUTTONDOWN和WM_LBUTTONUP。

【问题讨论】:

  • 这是您控制的另一个窗口吗?如果不是,这似乎是一个非常奇怪的要求。
  • 你想点击什么程序?一些程序(主要是游戏)有机制来处理你正在尝试做的事情并忽略它。在这种情况下,您最好的机会是使用 WinApi 使游戏成为最顶级,移动鼠标,单击,将鼠标移回,将游戏移回之前的 z 顺序。
  • 另外,在执行&lt;&lt; 16之前尝试将HiWord 转换为uint

标签: c# windows click mouse message


【解决方案1】:

您不能通过发送消息来做到这一点,而是使用 SendInput Windows API。

调用方法ClickOnPoint,这是一个来自表单点击事件的例子,所以this.handle是表单句柄,注意这些是窗口上的客户端坐标,女巫句柄是发送的,你可以很容易地改变这个并发送屏幕坐标,并且在那个如果您不需要下面的句柄或 ClientToScreen 调用。

ClickOnPoint(this.Handle, new Point(375, 340));

更新:现在使用 SendInput,tnx Tom。

顺便说一句。我只使用了此示例所需的声明,还有一个不错的库:Windows Input Simulator (C# SendInput Wrapper - Simulate Keyboard and Mouse)

  public class ClickOnPointTool
  {

    [DllImport("user32.dll")]
    static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);

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

#pragma warning disable 649
    internal struct INPUT
    {
      public UInt32 Type;
      public MOUSEKEYBDHARDWAREINPUT Data;
    }

    [StructLayout(LayoutKind.Explicit)]
    internal struct MOUSEKEYBDHARDWAREINPUT
    {
      [FieldOffset(0)]
      public MOUSEINPUT Mouse;
    }

    internal struct MOUSEINPUT
    {
      public Int32 X;
      public Int32 Y;
      public UInt32 MouseData;
      public UInt32 Flags;
      public UInt32 Time;
      public IntPtr ExtraInfo;
    }

#pragma warning restore 649


    public static void ClickOnPoint(IntPtr wndHandle , Point clientPoint)
    {
      var oldPos = Cursor.Position;

      /// get screen coordinates
      ClientToScreen(wndHandle, ref clientPoint);

      /// set cursor on coords, and press mouse
      Cursor.Position = new Point(clientPoint.X, clientPoint.Y);

      var inputMouseDown = new INPUT();
      inputMouseDown.Type = 0; /// input type mouse
      inputMouseDown.Data.Mouse.Flags = 0x0002; /// left button down

      var inputMouseUp = new INPUT();
      inputMouseUp.Type = 0; /// input type mouse
      inputMouseUp.Data.Mouse.Flags = 0x0004; /// left button up

      var inputs = new INPUT[] { inputMouseDown, inputMouseUp };
      SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));

      /// return mouse 
      Cursor.Position = oldPos;
    }

  }

【讨论】:

  • 谢谢,这很好用。我还补充说,当它被点击时,窗口会变为活动状态。
  • 没有SetCursorPos或者不移动鼠标就没有别的办法了吗???我在搜索的所有地方都看到几乎相同的非答案...
  • 请注意,您可以使用 Cursor.Position 代替 GetCursorPos 和 SetCursorPos。这也消除了对 POINT 结构的需要。
  • 如果目标窗口不在顶部,这将不起作用。因为它点击屏幕而不是窗口。在问题中,明确询问“即使窗口不在顶部”
  • mouse_event 已经被弃用很久了,你现在应该使用 SendInput。
【解决方案2】:

我在过去发现了一种向 Windows Media Player 发送消息的方法 所以我用它来模拟我想要的应用程序中的点击!

使用this class(下面的代码)找到窗口并发送您想要的消息!

using System;
using System.Runtime.InteropServices;

namespace Mouse_Click_Simulator
{
    /// <summary>
    /// Summary description for Win32.
    /// </summary>
    public class Win32
    {
        // The WM_COMMAND message is sent when the user selects a command item from 
        // a menu, when a control sends a notification message to its parent window, 
        // or when an accelerator keystroke is translated.
        public const int WM_KEYDOWN = 0x100;
        public const int WM_KEYUP = 0x101;
        public const int WM_COMMAND = 0x111;
        public const int WM_LBUTTONDOWN = 0x201;
        public const int WM_LBUTTONUP = 0x202;
        public const int WM_LBUTTONDBLCLK = 0x203;
        public const int WM_RBUTTONDOWN = 0x204;
        public const int WM_RBUTTONUP = 0x205;
        public const int WM_RBUTTONDBLCLK = 0x206;

        // The FindWindow function retrieves a handle to the top-level window whose
        // class name and window name match the specified strings.
        // This function does not search child windows.
        // This function does not perform a case-sensitive search.
        [DllImport("User32.dll")]
        public static extern int FindWindow(string strClassName, string strWindowName);

        // The FindWindowEx function retrieves a handle to a window whose class name 
        // and window name match the specified strings.
        // The function searches child windows, beginning with the one following the
        // specified child window.
        // This function does not perform a case-sensitive search.
        [DllImport("User32.dll")]
        public static extern int FindWindowEx(
            int hwndParent, 
            int hwndChildAfter, 
            string strClassName, 
            string strWindowName);


        // The SendMessage function sends the specified message to a window or windows. 
        // It calls the window procedure for the specified window and does not return
        // until the window procedure has processed the message. 
        [DllImport("User32.dll")]
        public static extern Int32 SendMessage(
            int hWnd,               // handle to destination window
            int Msg,                // message
            int wParam,             // first message parameter
            [MarshalAs(UnmanagedType.LPStr)] string lParam); // second message parameter

        [DllImport("User32.dll")]
        public static extern Int32 SendMessage(
            int hWnd,               // handle to destination window
            int Msg,                // message
            int wParam,             // first message parameter
            int lParam);            // second message parameter
    }
}

例如:

 Win32.SendMessage(iHandle, Win32.WM_LBUTTONDOWN, 0x00000001, 0x1E5025B);

Here's My Application Source Code 我创建用于在特定时间间隔内自动点击“BlueStacks”应用程序!

对于FindWindowwParamlParam等,你可以随时问我怎么做!这不是太难:) ;) 希望它有所帮助! :)

【讨论】:

  • 看起来,鼠标点击是发布的,而不是发送的。 PostMessage 将是一个更好的解决方案。至少 Spy++ 对我声称点击已发布。
  • 来到这里尝试向 BlueStacks 发送点击,并没有失望!
  • 如何为点击提供坐标?我需要点击某个位置,而不仅仅是点击未知位置。
  • @Kosmos 使用这个:var w = (y
【解决方案3】:

我无法添加评论:D

为我工作:

[DllImport("User32.dll")]
    public static extern Int32 SendMessage(
    int hWnd,               
    int Msg,                
    int wParam,            
    IntPtr lParam);

并像这样在 lParam 中组合坐标:

private static IntPtr CreateLParam(int LoWord, int HiWord)
    {
        return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
    }

并使用:

Clicktoapp.SendMessage(0x00040156, Clicktoapp.WM_LBUTTONDOWN, 0x00000001, CreateLParam(150,150));
        Clicktoapp.SendMessage(0x00040156, Clicktoapp.WM_LBUTTONUP, 0x00000000, CreateLParam(150, 150));

0x00040156 - 窗口句柄。

我正在寻找使用 spy ++ 的窗口句柄 每次都是新的,所以最好用FindWindow。

附言

应用程序窗口的屏幕截图,即使窗口不在顶部

https://stackoverflow.com/a/911225/12928587

我使用这个解决方案。工作得很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    • 2014-05-08
    • 1970-01-01
    • 2023-04-01
    相关资源
    最近更新 更多