2017-12-01 1 views
0

Ich entwarfe gerade eine Funktion, die ein Unterbild auf einem Bild eines Fensters sucht. War die Suche erfolgreich, klickt sie auf die Mitte dieses Unterbildes. Seltsamerweise klickt es immer unterhalb der erwarteten Position.ClientToScreen API Funktionen gibt nicht den erwarteten Punkt zurück

Der Suchalgorithmus funktioniert korrekt - ich habe es noch überprüft. Die angegebenen Koordinaten für die Funktion sind korrekt. Aber die Funktion ClientToScreen funktioniert seltsam. Zum Beispiel:

Mein Unterbild wurde gefunden bei x = 352, y = 70 - die Koordinaten sind relativ zur linken oberen Ecke des Fensters. Die linke obere Ecke meines Fensters ist bei x = 91, y = 303 relativ zum Bildschirm. Also, ich für die Koordinaten zu erwarten klicken Sie auf, in Bezug auf den Bildschirm wie folgt:

X_Click = Window.Left + X_Click_rel2Wnd = 352 + 91= 443; 
Y_Click = Window.Top + Y_Click_rel2Wnd = 70 + 303 = 373; 

Die Funktion gibt: 447/396

Es, wie dieses Bild aussieht zeigt: enter image description here

Jeder hat eine Idee, was ist los?

Unter dem 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;} 
} 

}

+0

scheint über die Höhe des Fenstertitels zu sein off .... neugierig .. wenn ich Sie wäre, würde ich das untersuchen ... –

+0

Was das übergeordnete Ziel ist hier, ? Für * die meisten * Probleme in diesem Bereich gibt es bessere Ansätze als das Simulieren von Eingabeereignissen. Z.B. Es gibt eine ganze Menge an APIs, die für Zugänglichkeitszwecke erstellt wurden. –

+0

* die Koordinaten sind relativ zur linken oberen Ecke des Fensters * Sieht so aus, als seien die Koordinaten, die Sie an den 'ClientToScreen' übergeben, keine" Client "-Koordinaten, wie der' ClientToScreen' erwartet. Die Client-Koordinaten sind relativ zum Client-Rechteck des Fensters, das den Titel und den Rahmen ausschließt. –

Antwort

1

Vielen Dank. Das läuft gut:

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

}

Verwandte Themen