ControlClick() - 09/23/22 Issue 1 (possible related ControlGetPos() issue).

Issue #88 closed
Winter Laite created an issue

This will be difficult to fix, possibly. The AHK documentation is not entirely helpful. It appears ControlClick() was not intended to work on controls within the same GUI, although I’m not sure about that. At any rate, it doesn’t appear to work in AHK. In Keysharp I can click on a control by specifying the text, but trying with “POS” throws an error.

************** Exception Text **************
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.

Unfortunately there will be lots of test code with this/these issue(s).

The target AHK code works. I don’t know whether either “CoordMode” is required. It works without them.

CoordMode("Mouse", "Client")
MyGui := Gui(, "Some Window Title")
BtnOkay := MyGui.Add("Button", "x10 y+10", "Okay").OnEvent("Click", OkayClicked)
MyEdit := MyGui.Add("Edit", "x10 y+10 w350 h350", "Test now")
MyGui.Show("w400 h400")

OkayClicked(*) {
    CoordMode("Mouse", "Client")
    ControlGetPos(&X, &Y, &Width, &Height, "Button1", "Some Window Title")
    ControlSetText(X " " Y, MyEdit)
    Sleep(1000)
    ControlSetText("Test now", MyEdit.Hwnd)
    MyGui.Submit(False)
}

The test AHK code works reliably, as long as SetControlDelay(-1) is specified.

MyGui2 := Gui(, "Some Other Window Title")

Btn1 := MyGui2.Add("Button", "x10 y10", "Control Click Text")
Btn1.OnEvent("Click", ClickIt)
; ┌───────────────────────────────────────┐
;   Click control - find using its text  
; └───────────────────────────────────────┘
Btn2 := MyGui2.Add("Button", "x10 y+10", "Control Click Pos")
Btn2.OnEvent("Click", ClickPos)


MyGui2.Show("w400 h400")

ClickIt(*) {
    WinActivate("Some Window Title")
    Sleep(10)
    ControlClick("Okay", "Some Window Title",,,, "NA")
}

ClickPos(*) {
    WinActivate("Some Window Title")
    Sleep(10)
    SetControlDelay(-1)
    ControlClick("x10 y10", "Some Window Title",,,, "POS")
}

I will edit this Issue with test Keysharp code modified from that above.

Comments (8)

  1. Winter Laite reporter

    Here is some failing Keysharp code. Script 1 does work reliably, but reports the wrong position for ‘Btn1’.

    MyGui := Gui(, "Some Window Title")
    BtnOkay := MyGui.Add("Button", "x10 y+10 +AltSubmit", "Okay").OnEvent("Click", "OkayClicked")
    MyEdit := MyGui.Add("Edit", "x10 y+10 w350 h350", "Test now")
    MyGui.Show("w400 h400")
    
    OkayClicked(*) {
        if (WinExist("Some Window Title")) {
            ;pos := ControlGetPos(MyGui.BtnOkay.Hwnd)
            pos := ControlGetPos("Okay", "Some Window Title")
            ControlSetText("'Okay' button is at " pos["X"] " " pos["Y"] " in Window'" MyGui.Title "'", MyEdit)
            Sleep(1000)
            ControlSetText("Test now", MyEdit.Hwnd)
            MyGui.Submit(False)
        }
    }
    

    The control will never be found with reported coords, which are x=0 and y=0.

    This Keysharp code runs provided Notepad is running, but again only reports x=0 and y=0 (though that may actually be correct since AHK reports that also with similar code).

    if (WinExist("Untitled - Notepad"))
    {
        sop := ControlGetPos("Edit1") ; Use the window found by WinExist.
        MsgBox("Edit1 is at X: " sop["X"] ", Y: " sop["Y"] "`n Width: " sop["Width"] ", Height " sop["Height"])
    }
    

    Now for the KS script to try clicking in the first script:

    MyGui2 := Gui(, "Some Other Window Title")
    
    Btn1 := MyGui2.Add("Button", "x10 y10", "Control Click Text")
    Btn1.OnEvent("Click", "ClickIt")
    ; ┌───────────────────────────────────────┐
    ;   Click control - find using its text  
    ; └───────────────────────────────────────┘
    Btn2 := MyGui2.Add("Button", "x10 y+10", "Control Click Pos")
    Btn2.OnEvent("Click", "ClickPos")
    
    
    MyGui2.Show("w400 h400")
    
    ClickIt() {
        WinActivate("Some Window Title")
        Sleep(10)
        ControlClick("Okay", "Some Window Title",,,, "NA")
    }
    
    ClickPos() {
        CoordMode("Mouse", "Screen")
        WinActivate("Some Window Title")
        Sleep(10)
        SetControlDelay(-1)
        ControlClick("x815 y390", "Some Window Title",,,, "POS")
    }
    

    This error message is thrown regardless of what coords I use of ‘ControlClick’:

    ************** Exception Text **************
    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
     ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
       at Keysharp.Core.Windows.ControlManager.ControlClick(Object ctrlorpos, Object title, String text, String whichButton, Int32 clickCount, String options, String excludeTitle, String excludeText) in C:\Users\testuser\Documents\repos\keysharp\Keysharp.Core\Windows\ControlManager.cs:line 228
    

  2. Winter Laite reporter

    Comment on 9/26/22:

    Retesting with these scripts following latest commit.

    issue_88_1.ahk:

    MyGui := Gui(, "Some Window Title")
    BtnOkay := MyGui.Add("Button", "x10 y+10 +AltSubmit", "Okay").OnEvent("Click", "OkayClicked")
    MyEdit := MyGui.Add("Edit", "x10 y+10 w350 h100", "Test now")
    MyGui.Show("w400 h220")
    
    OkayClicked() {
        if (WinExist("Some Window Title")) {
            ;pos := ControlGetPos(MyGui.BtnOkay.Hwnd)
            pos := ControlGetPos("Okay", "Some Window Title")
            ControlSetText("'Okay' button is at " pos["X"] " " pos["Y"] " in Window'" MyGui.Title "'", MyEdit)
            Sleep(1000)
            ControlSetText("Test now", MyEdit.Hwnd)
            MyGui.Submit(False)
        }
    }
    

    I leave this script running, and run the following.

    issue_88_2.ahk:

    MyGui2 := Gui(, "Some Other Window Title")
    
    Btn1 := MyGui2.Add("Button", "x10 y10", "Control Click Text")
    Btn1.OnEvent("Click", "ClickIt")
    Btn2 := MyGui2.Add("Button", "x10 y+10", "Control Click Pos")
    Btn2.OnEvent("Click", "ClickPos")
    
    
    MyGui2.Show("w400 h200")
    
    ClickIt() {
        WinActivate("Some Window Title")
        Sleep(10)
        ControlClick("Okay", "Some Window Title",,,, "NA")
    }
    
    ClickPos() {
        ;CoordMode("Mouse", "Screen")
        pos := ControlGetPos("Okay", "Some Window Title")
        WinActivate("Some Window Title")
        Sleep(10)
        SetControlDelay(-1)
        posString := "x" pos["X"]+2 " y" pos["Y"]+2
        MsgBox(posString)
        ControlClick(posString, "Some Window Title",,,, "POS")
    }
    

    I still get the index-out-of-bounds error. I looked at the code for ControlManager.cs - possible parsing error?

    I will try to narrow this issue down further, I have too many moving parts in the tests above.

  3. Winter Laite reporter

    This simpler test also fails with index-out-of-bounds for clicking by position instead of text:

    MyGui := Gui(, "Some Random Window Title")
    
    BtnVictim := MyGui.Add("Button", "x10 y10", "Target")
    BtnVictim.OnEvent("Click", "TargetMessage")
    
    Btn1 := MyGui.Add("Button", "x10 y+10", "Control Click Text")
    Btn1.OnEvent("Click", "ClickIt")
    Btn2 := MyGui.Add("Button", "x10 y+10", "Control Click Pos")
    Btn2.OnEvent("Click", "ClickPos")
    
    
    MyGui.Show("w400 h200")
    
    ClickIt() {
        Sleep(10)
        ControlClick("Target", "Some Random Window Title",,,, "NA")
    }
    
    ClickPos() {
        ;CoordMode("Mouse", "Screen")
        pos := ControlGetPos("Target", "Some Random Window Title")
        Sleep(10)
        SetControlDelay(-1)
        posString := "x" pos["X"]+2 " y" pos["Y"]+2
        MsgBox(posString)
        ControlClick(posString, "Some Random Window Title",,,, "POS")
    }
    
    TargetMessage() {
        MsgBox("Victim button clicked")
    }
    

  4. Matt Feemster repo owner

    This was the result of two bugs inside of SetControlDelay(). I’ve committed a fix, please test.

    Also, SetControlDelay() is not needed when I test. Please confirm that you can remove it and it works fine on your end.

  5. Winter Laite reporter

    Following latest commits, this works:

    MyGui := Gui(, "Some Window Title")
    BtnOkay := MyGui.Add("Button", "x10 y+10 +AltSubmit", "Okay").OnEvent("Click", "OkayClicked")
    MyEdit := MyGui.Add("Edit", "x10 y+10 w350 h350", "Test now")
    MyGui.Show("w400 h400")
    
    OkayClicked() {
        if (WinExist("Some Window Title")) {
            ;pos := ControlGetPos(MyGui.BtnOkay.Hwnd)
            pos := ControlGetPos("Okay", "Some Window Title")
            ControlSetText("'Okay' button is at " pos["X"] " " pos["Y"] " in Window'" MyGui.Title "'", MyEdit)
            Sleep(1000)
            ControlSetText("Test now", MyEdit.Hwnd)
            MyGui.Submit(False)
        }
    }
    

    Script 2:

    MyGui2 := Gui(, "Some Other Window Title")
    
    Btn1 := MyGui2.Add("Button", "x10 y10", "Control Click Text")
    Btn1.OnEvent("Click", "ClickIt")
    ; ┌───────────────────────────────────────┐
    ;   Click control - find using its text  
    ; └───────────────────────────────────────┘
    Btn2 := MyGui2.Add("Button", "x10 y+10", "Control Click Pos")
    Btn2.OnEvent("Click", "ClickPos")
    
    
    MyGui2.Show("w400 h400")
    
    ClickIt() {
        WinActivate("Some Window Title")
        Sleep(10)
        ControlClick("Okay", "Some Window Title",,,, "NA")
    }
    
    ClickPos() {
        WinActivate("Some Window Title")
        Sleep(10)
        ;SetControlDelay(-1)
        ControlClick("x10 y10", "Some Window Title",,,, "POS")
    }
    

    Run the first script, then test it with the second. This works fine without ‘SetControlDelay(-1)’.

    Thank you! I’m marking this ‘resolved’ and closing.

  6. Log in to comment