I'm currently designing a function that searches a subpicture on a picture of a window. If the search was successful, it clicks on the center of this subpicture. Strangely, it always clicks a below the expected position.
The search algorithm works correct - I still checked it. The provided coordinates for the function are correct. But the function ClientToScreen works strange. For example:
My subpicture was found at x = 352, y = 70 - the coordinates are relative to the left upper corner of the window. The left upper corner of my window is at x = 91, y = 303 relative to the screen. So, I expected for the coordinates to click on, relative to the screen as follows:
X_Click = Window.Left + X_Click_rel2Wnd = 352 + 91= 443;
Y_Click = Window.Top + Y_Click_rel2Wnd = 70 + 303 = 373;
The function returns: 447 / 396
It looks like this picture shows:
Anybody has an idea, whats wrong?
Below the code:
public static class ClickOnPointTool{
private const uint MOUSEEVENTF_LEFTDOWN = 0x02;
private const uint MOUSEEVENTF_LEFTUP = 0x04;
private const uint MOUSEEVENTF_RIGHTDOWN = 0x08;
private const uint MOUSEEVENTF_RIGHTUP = 0x10;
private const uint MOUSEEVENTF_MIDDLEDOWN = 0x00000020;
private const uint MOUSEEVENTF_MIDDLEUP = 0x00000040;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TPoint{
public int X;
public int Y;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool ClientToScreen(System. IntPtr hWnd, ref TPoint lpPoint);
#pragma warning disable 649
internal struct INPUT{
public System.UInt32 Type;
public MOUSEKEYBDHARDWAREINPUT Data;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPArray), System.Runtime.InteropServices.In] INPUT[] pInputs, int cbSize);
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
internal struct MOUSEKEYBDHARDWAREINPUT{
[System.Runtime.InteropServices.FieldOffset(0)]
public MOUSEINPUT Mouse;
}
internal struct MOUSEINPUT{
public System.Int32 X;
public System.Int32 Y;
public System.UInt32 MouseData;
public System.UInt32 Flags;
public System.UInt32 Time;
public System.IntPtr ExtraInfo;
}
#pragma warning restore 649
public static void ClickOnPoint(System.IntPtr wndHandle, int x, int y, bool KeepCursor = false, bool RightButton = false, bool DoubleClick = false, System.Data.DataTable WndBoundings = null){
int nTimes = 0;
TPoint clientPoint;
clientPoint.X = x;
clientPoint.Y = y;
System.Drawing.Point oldPos = System.Windows.Forms.Cursor.Position;
//System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");
if(DoubleClick){nTimes = 2;}else{nTimes = 1;}
/// get screen coordinates
if(WndBoundings == null){
ClientToScreen(wndHandle, ref clientPoint);
}else{
clientPoint.X += (int)WndBoundings.Rows[0]["Left"];
clientPoint.Y += (int)WndBoundings.Rows[0]["Top"];
}
//System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");
/// set cursor on coords, and press mouse
System.Windows.Forms.Cursor.Position = new System.Drawing.Point(clientPoint.X, clientPoint.Y);
INPUT inputMouseDown = new INPUT();
inputMouseDown.Type = 0; /// input type mouse
if(RightButton){
inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_RIGHTDOWN; ///right button down
}else{
inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_LEFTDOWN; /// left button down
}
INPUT inputMouseUp = new INPUT();
inputMouseUp.Type = 0; /// input type mouse
if(RightButton){
inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_RIGHTUP; /// right button up
}else{
inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_LEFTUP; /// left button up
}
var inputs = new INPUT[] { inputMouseDown, inputMouseUp };
for(int i=0;i<nTimes;i++){
SendInput((uint)inputs.Length, inputs, System.Runtime.InteropServices.Marshal.SizeOf(typeof(INPUT)));
}
/// return mouse
if(!KeepCursor){System.Windows.Forms.Cursor.Position = oldPos;}
}
}
Thank you all. This runs well:
private static System.Drawing.Point GetWindowCornerLU(System.IntPtr hWnd){
if(hWnd == System.IntPtr.Zero){throw new System.Exception("ERROR: Window handle is not referenced!");}
WindowHandle.User32.Rect rect = new WindowHandle.User32.Rect();
WindowHandle.User32.GetWindowRect(hWnd, ref rect);
return new System.Drawing.Point(rect.left, rect.top);
}
#pragma warning restore 649
public static void ClickOnPoint(System.IntPtr wndHandle, int x, int y, bool KeepCursor = false, bool RightButton = false, bool DoubleClick = false){
int nTimes = 0;
TPoint clientPoint;
clientPoint.X = x;
clientPoint.Y = y;
System.Drawing.Point oldPos = System.Windows.Forms.Cursor.Position;
//System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");
if(DoubleClick){nTimes = 2;}else{nTimes = 1;}
/// get screen coordinates
//ClientToScreen(wndHandle, ref clientPoint);
System.Drawing.Point prtLU = GetWindowCornerLU(wndHandle);
clientPoint.X += prtLU.X;
clientPoint.Y += prtLU.Y;
//System.Windows.Forms.MessageBox.Show("Click to " + clientPoint.X + " / " + clientPoint.Y + "");
/// set cursor on coords, and press mouse
System.Windows.Forms.Cursor.Position = new System.Drawing.Point(clientPoint.X, clientPoint.Y);
INPUT inputMouseDown = new INPUT();
inputMouseDown.Type = 0; /// input type mouse
if(RightButton){
inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_RIGHTDOWN; ///right button down
}else{
inputMouseDown.Data.Mouse.Flags = MOUSEEVENTF_LEFTDOWN; /// left button down
}
INPUT inputMouseUp = new INPUT();
inputMouseUp.Type = 0; /// input type mouse
if(RightButton){
inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_RIGHTUP; /// right button up
}else{
inputMouseUp.Data.Mouse.Flags = MOUSEEVENTF_LEFTUP; /// left button up
}
var inputs = new INPUT[] { inputMouseDown, inputMouseUp };
for(int i=0;i<nTimes;i++){
SendInput((uint)inputs.Length, inputs, System.Runtime.InteropServices.Marshal.SizeOf(typeof(INPUT)));
}
/// return mouse
if(!KeepCursor){System.Windows.Forms.Cursor.Position = oldPos;}
}
}
User contributions licensed under CC BY-SA 3.0