Programmatically Mouse Click in Another Window

programmatically mouse click in another window

You can't do that by sending messages, instead use SendInput Windows API.

Call method ClickOnPoint, this is an example from form click event, so this.handle is form handle, note that these are client coordinates on window witch handle is send, you can easily change this and send screen coordinates, and in that case you don't need handle or ClientToScreen call below.

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

UPDATE: using SendInput now, tnx Tom.

btw. I used only declarations needed for this sample, for anything more there is a nice library : 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;
}

}

Perform a mouse Click event on another Application using C#

Maybe this could help you

Code

The task

  • Getting the mouse's current position
  • Sending the mouse event

Windows forms

...
using System.Runtime.InteropServices;

namespace yournamespace
{

public partial class yourclassname
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);

private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;

int X = Cursor.Position.X;
int Y = Cursor.Position.Y;
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}
}

WPF

Things are a bit harder in WPF

double mousePointX;
double mousePointY;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out POINT lpPoint);

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;

public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}

private void WritePoint(object sender, RoutedEventArgs e)
{
POINT p;
if (GetCursorPos(out p))
{
System.Console.WriteLine(Convert.ToString(p.X) + ";" + Convert.ToString(p.Y));
}
}
[DllImport("User32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);

[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

private Point ConvertPixelsToUnits(int x, int y)
{
// get the system DPI
IntPtr dDC = GetDC(IntPtr.Zero); // Get desktop DC
int dpi = GetDeviceCaps(dDC, 88);
bool rv = ReleaseDC(IntPtr.Zero, dDC);

// WPF's physical unit size is calculated by taking the
// "Device-Independant Unit Size" (always 1/96)
// and scaling it by the system DPI
double physicalUnitSize = (1d / 96d) * (double)dpi;
Point wpfUnits = new Point(physicalUnitSize * (double)x,
physicalUnitSize * (double)y);

return wpfUnits;
}
private void WriteMouseCoordinatesInWPFUnits()
{
POINT p;
if (GetCursorPos(out p))
{
Point wpfPoint = ConvertPixelsToUnits(p.X, p.Y);
System.Console.WriteLine(Convert.ToString(wpfPoint.X) + ";" + Convert.ToString(wpfPoint.Y));

mousePointY = wpfPoint.Y;
mousePointX = wpfPoint.X
}
}

Now the most important part of the code

 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);

private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;

...
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, Convert.ToUInt32(mousePointX), Convert.ToUInt32(mousePointY), 0, 0);
...

Warning

  • The code is tested
  • The code is not a "copy & paste code

Simulating mouse-down event on another window from CGWindowListCreate

Finally got this working after finding an alternative to the deprecated GetPSNForPID function:

NSEvent *customEvent = [NSEvent mouseEventWithType: NSEventTypeLeftMouseDown
location: point
modifierFlags: NSEventModifierFlagCommand
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:[self.windowID intValue]
context: nil
eventNumber: 0
clickCount: 1
pressure: 0];

CGEvent = [customEvent CGEvent];
CGEventPostToPid(PID, CGEvent);

Didn't realise there was a CGEventPostToPid method instead of CGEventPostToPSN. No need for the ProcessSerialNumber struct.

Send mouse clicks to X Y coordinate of another application

You can use the GetWindowInfo API:

    [return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);

[StructLayout(LayoutKind.Sequential)]
struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;

public WINDOWINFO(Boolean? filler)
: this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
{
cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
}

}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left, top, right, bottom;
}

private void button1_Click_1(object sender, EventArgs e)
{
var p = System.Diagnostics.Process.GetProcessesByName("mspaint");

if (p.Length == 0) return;

WINDOWINFO wi = new WINDOWINFO(false);
GetWindowInfo(p[0].MainWindowHandle, ref wi);

SendLeftClick((wi.rcWindow.left + wi.rcWindow.right) / 2, (wi.rcWindow.top + wi.rcWindow.bottom) / 2);
}

How to programmatically click the mouse in another program when this code DOESN'T work

What version of windows are you using?

If you are using Vista+, is the target application running with elevated permissions?

If yes, is your application also running with elevated permissions?

If no, see : UIPI

Newer versions of Windows actively disallow an application with a lower privilege sending messages to an application with higher privilege. There are a few ways around this, either by making your application run with elevated permissions or by including an application manifest that sets uiAccess to true. In the latter case, the application must be authenticode signed and must be executed from a trusted location (ie: Program Files directory, etc.).

Otherwise, there is no way to simulate mouse activity at the low level without introducing a new hardware driver. Hardware drivers run in Ring-0 and to completely simulate real mouse activity (not just 'fake' messages) you would need to do it at this level.



Related Topics



Leave a reply



Submit