Is ControlClick dependent on a certain Window Class?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
DavidP
Posts: 225
Joined: 10 Aug 2014, 07:31

Is ControlClick dependent on a certain Window Class?

11 Oct 2014, 06:28

I am asking because I can't get Controlclick to function in a certain program that does not use standard Windows classes and controls. The program is called PDF-XChange Editor and looks something like this:

Image

Clicking works with Click (interestingly without comma):

Code: Select all

Click, 1031 41
...but not with ControlClick (does nothing):

Code: Select all

ControlClick, X1031 Y41, PDF-XChange Editor
What could be wrong here?
Last edited by DavidP on 14 Oct 2014, 08:34, edited 1 time in total.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is Controlclick dependent on a certain Window Class?

11 Oct 2014, 18:42

ControlClick sends a click message to the window you specify. That menu is probably not in the window you specify, but a popup window which appears in front of it.
User avatar
DavidP
Posts: 225
Joined: 10 Aug 2014, 07:31

Re: Is Controlclick dependent on a certain Window Class?

12 Oct 2014, 14:05

Sorry I was not clear enough. Actually I am trying to click on a dropdown triangle besides a toolbar button of the main program window, toolbar button and triangle being visible all the time:

Image

Do I have to specify anything else than the click location and the window title in order to make Controlclick work?

Code: Select all

ControlClick, X1031 Y41, PDF-XChange Editor
Thanks again,
Regards David.P
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is Controlclick dependent on a certain Window Class?

12 Oct 2014, 17:15

No. However, make sure you have used SetTitleMatchMode 2, since the window title does not start with "PDF-XChange Editor".
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Re: Is Controlclick dependent on a certain Window Class?

13 Oct 2014, 06:41

lexikos, is it not true that the control-functions of autohotkey only work with standard windows-controls?
judging from PDF-XChange-Reader, I assume that also the editor uses custom controls.
if I am right then ControlClick will never work with PDF-XChange-Reader/Editor as long as it is employing custom controls.

Click on the other hand, DavidP, is a very general function that simply sends a click to the specified coordinates (really simulating a normal mouse click), not worrying about the target, therefore it works but is less reliable regarding changes of the active window.

BTW, welcome to the forum, DavidP.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is Controlclick dependent on a certain Window Class?

13 Oct 2014, 19:35

No. ControlClick works with any window or control which responds to mouse messages. DavidP was identifying a position on the window, not a control. (Whether it was the right position, I don't know...)

ControlClick is used very heavily with some games, like World of Warcraft, which have no actual controls in the Windows sense, let alone standard ones.
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Re: Is Controlclick dependent on a certain Window Class?

14 Oct 2014, 07:04

lexikos wrote:No. ControlClick works with any window or control which responds to mouse messages. DavidP was identifying a position on the window, not a control. (Whether it was the right position, I don't know...)

ControlClick is used very heavily with some games, like World of Warcraft, which have no actual controls in the Windows sense, let alone standard ones.
ok, thx for the explaination, Lexikos
glad to have learned something
User avatar
DavidP
Posts: 225
Joined: 10 Aug 2014, 07:31

Re: Is Controlclick dependent on a certain Window Class?

14 Oct 2014, 08:25

OK thanks very much guys. I've tried everything I could think of, but it still only works with Click instead of ControlClick.

This is the dropdown and color picker that needs to be clicked on the toolbar:

Image

I shall post my script below:

Code: Select all

;###########################
; Header 
;###########################
 
SetTitleMatchMode, 2 ; A window's title can contain WinTitle anywhere inside it to be a match 
CoordMode, Mouse, Window ; Sets coordinate mode for Mouse to be relative to the active window 

;###########################
; Change Textmarker Color in PDF-XChange Editor -- this works using CLICK
;###########################

#IfWinActive, PDF-XChange Editor 
b:: ; make selected highlight blue -- replace "b" with your favorite hotkey
If (A_Cursor != "IBeam") ; only act when not editing text, e.g. don't act when editing a sticky note
{
	Click, 1031 41 ; replace with your coordinates of the little black triangle besides the "Fill Color" toolbar button, PDF-XChange Editor toolbar called "properties" must be set to visible, use the Autohotkey Window Spy tool to find the coordinates
	Click, 1017 298 ; replace with coordinates of the desired blue color that is shown on the picker when clicking on the "Fill Color" toolbar button
}
Else
	Send, b ; send the actual letter if editing text, e.g. in a sticky note
Return
#IfWinActive

;###########################
; Change Textmarker Color in PDF-XChange Editor -- this doesn't work using ControlClick
;###########################

#IfWinActive, PDF-XChange Editor 
g:: ; make selected highlight green -- replace "g" with your favorite hotkey
If (A_Cursor != "IBeam") ; only act when not editing text, e.g. don't act when editing a sticky note
{
	ControlClick, x1031 y41, PDF-XChange Editor,,,, Pos ; replace with your coordinates of the little black triangle besides the "Fill Color" toolbar button, PDF-XChange Editor toolbar called "properties" must be set to visible, use the Autohotkey Window Spy tool to find the coordinates
	ControlClick, x1047 y298, PDF-XChange Editor,,,, Pos ; replace with coordinates of the desired green color that is shown on the picker when clicking on the "Fill Color" toolbar button
	; ControlClick, x1047 y298 ; this variant also does not work, not even when [#IfWinActive, PDF-XChange Editor/#IfWinActive] is also deleted
}
Else
	Send, g ; send the actual letter if editing text, e.g. in a sticky note
Return
#IfWinActive

;###########################

; repeat the above for more colors
Thanks again for any clues why Click :thumbup: works but ControlClick :thumbdown: doesn't

Cheers
David
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is ControlClick dependent on a certain Window Class?

14 Oct 2014, 19:05

This is the dropdown and color picker that needs to be clicked on the toolbar
So... which window do you need to click? Your latest screenshot shows two more windows which are separate from the main "PDF-XChange Editor" window.
User avatar
DavidP
Posts: 225
Joined: 10 Aug 2014, 07:31

Re: Is ControlClick dependent on a certain Window Class?

15 Oct 2014, 05:59

lexikos wrote:So... which window do you need to click? Your latest screenshot shows two more windows which are separate from the main "PDF-XChange Editor" window.
True, but they are only shown for visualization. The window title and class as reported by Window Spy always stays the same:

Code: Select all

- PDF-XChange Editor 
ahk_class PXE:{C5309AD3-73E4-4707-B1E1-2940D8AF3B9D}
...no matter if the PDF document itself, or the above shown undocked toolbar, or the color picker itself has the focus.

Not even the first click is carried out, the one that is supposed to click on the (here yellow) toolbar button (that opens the color picker), and not even if the toolbar is docked:

Image

:?: :eh: :?:

What could be the reason that the click is not executed?
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is ControlClick dependent on a certain Window Class?

15 Oct 2014, 21:31

I have installed an evaluation version of PDF-XChange Editor and confirmed that it does respond to ControlClick, but the mouse cursor must be over the appropriate button. Basically, when this program receives a click message (WM_LBUTTONDOWN), it ignores the position specified by the message and instead queries for the current mouse position (equivalent to MouseGetPos). If the window is not active (and you prevent activation by using the NA option), it will not display the colour picker, but clicking some of the other buttons will work. This might make sense if you consider that the colour picker is normally hidden automatically if the main window loses focus.

In short, this program will not respond to ControlClick in the way that you intend.
The window title and class as reported by Window Spy always stays the same:
The tool window clearly has a different title, so I presume the main window remains active even after you click the tool window; however, when I activate the tool window, Window Spy shows the title of the tool window.

With standard popup menus, usually some other window has the focus, and keyboard messages are automatically routed to the menu. For instance, AutoHotkey's Menu command focuses the script's hidden main window. Thus, Window Spy will not show the title of the menu itself. The same could be true of custom popups such as this program's colour picker.
guest3456
Posts: 3462
Joined: 09 Oct 2013, 10:31

Re: Is ControlClick dependent on a certain Window Class?

16 Oct 2014, 01:03

lexikos wrote:I have installed an evaluation version of PDF-XChange Editor and confirmed that it does respond to ControlClick, but the mouse cursor must be over the appropriate button. Basically, when this program receives a click message (WM_LBUTTONDOWN), it ignores the position specified by the message and instead queries for the current mouse position (equivalent to MouseGetPos).
If the problem is indeed what Lexikos has found above, then this type of ControlClick bug/issue has been mentioned in the past. A suggested solution is here:
http://www.autohotkey.com/board/topic/9 ... k-improve/

@DavidP, look at that thread. Basically what you can try is to send a WM_MOUSEMOVE message first, and then WM_LBUTTONDOWN (which is what ControlClick already does). I've actually wrapped my own ControlClick function which does just that, similar to whats shown in the thread. Of course, this is if you want to avoid activating/focusing the window first, which I assume thats what you want. Otherwise, you could just use Click

@Lexikos, dunno if it matters but I'd like to repeat my wishlist request from that thread to add a new option to ControlClick, something like "MM" (similar to how there is "NA"), which would send the WM_MOUSEMOVE message in addition.

It could read something like this:
hypothetical ControlClick docs wrote: Options

NA [v1.0.45+]: May improve reliability. See reliability below.
MM [v1.1.17|2.0]: May improve reliability. See reliability below.



Reliability

"NA" avoids marking the target window as active and avoids merging its input processing with that of the script, which may prevent physical movement of the mouse from interfering (but usually only when the target window is not active). However, this method might not work for all types of windows and controls.

"MM" will send a WM_MOUSEMOVE message prior to the WM_[L|R]BUTTONDOWN click message. Some rare applications do not respect the coordinates that are sent in the BUTTONDOWN message and instead use the cursor position. Sending this message will simulate the cursor position and allow the clicks to be recognized in those applications.
;)

lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is ControlClick dependent on a certain Window Class?

16 Oct 2014, 01:32

guest3456 wrote:If the problem is indeed what Lexikos has found above, then this type of ControlClick bug/issue has been mentioned in the past.
No, that's a different issue.

In this case, the program knows where the mouse is even if it was never sent a WM_MOUSEMOVE message - i.e. because there is another window obscuring it. For this reason, I didn't test sending it a WM_MOUSEMOVE message; I don't believe it would make any difference. The mouse doesn't have to be pointing directly at the window; it just has to line up with the button.
User avatar
DavidP
Posts: 225
Joined: 10 Aug 2014, 07:31

Re: Is ControlClick dependent on a certain Window Class?

16 Oct 2014, 07:13

Thanks gentlemen, but *phew* I fear that this goes a little over my head.

So is there something simple that I could add to my lines like

Code: Select all

ControlClick, x1031 y41, PDF-XChange Editor,,,, Pos
...or am I better off to just use "Click" as I do at present?

I'd only prefer ControlClick because it is more elegant and doesn't actually move the pointer.

Regards David.P
guest3456
Posts: 3462
Joined: 09 Oct 2013, 10:31

Re: Is ControlClick dependent on a certain Window Class?

16 Oct 2014, 10:23

DavidP wrote:

Code: Select all

ControlClick, x1031 y41, PDF-XChange Editor,,,, Pos
I'd only prefer ControlClick because it is more elegant and doesn't actually move the pointer.
Yeah that's the main benefit. I suppose if the WM_MOUSEMOVE message won't work like Lexikos said, you could try this wrapper for Click which will quickly move the mouse back:

Code: Select all

WinGet, PDFXhwnd, ID, PDF-XChange Editor
BasicClick(1031, 41, PDFXhwnd)

BasicClick(x, y, id)     ;// input coords relative to a full window (including borders and caption)
{
   CoordMode, Mouse, Screen
   MouseGetPos, oldx, oldy
   WinActivate, ahk_id %id%   
   BlockInput, MouseMove
   CoordMode, Mouse, Relative
   Click %x%, %y%
   CoordMode, Mouse, Screen
   MouseMove, %oldx%, %oldy%, 0
   BlockInput, MouseMoveOff
}

User avatar
DavidP
Posts: 225
Joined: 10 Aug 2014, 07:31

Re: Is ControlClick dependent on a certain Window Class?

18 Oct 2014, 10:43

Sorry but I don't understand where and how I am to put the "WM_MOUSEMOVE" command in connection with the ControlClick command.

Btw., I am already using a similar "wrapper" for "Click".

Regards David.P
guest3456
Posts: 3462
Joined: 09 Oct 2013, 10:31

Re: Is ControlClick dependent on a certain Window Class?

18 Oct 2014, 15:21

DavidP wrote:Sorry but I don't understand where and how I am to put the "WM_MOUSEMOVE" command in connection with the ControlClick command.
try this from the thread linked above, (prob will only work on 32bit ahk)

Code: Select all


ControlClick2(1031, 41, "PDF-XChange Editor")


;// required functions below, add these to the very bottom of your script

ControlClick2(X, Y, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="")  
{  
  hwnd:=ControlFromPoint(X, Y, WinTitle, WinText, cX, cY, ExcludeTitle, ExcludeText)  
  PostMessage, 0x200, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_MOUSEMOVE
  PostMessage, 0x201, 1, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONDOWN  
  PostMessage, 0x202, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONUP  
}


; Retrieves the control at the specified point.
; X         [in]    X-coordinate relative to the top-left of the window.
; Y         [in]    Y-coordinate relative to the top-left of the window.
; WinTitle  [in]    Title of the window whose controls will be searched.
; WinText   [in]
; cX        [out]   X-coordinate relative to the top-left of the control.
; cY        [out]   Y-coordinate relative to the top-left of the control.
; ExcludeTitle [in]
; ExcludeText  [in]
; Return Value:     The hwnd of the control if found, otherwise the hwnd of the window.
ControlFromPoint(X, Y, WinTitle="", WinText="", ByRef cX="", ByRef cY="", ExcludeTitle="", ExcludeText="")
{
    static EnumChildFindPointProc=0
    if !EnumChildFindPointProc
        EnumChildFindPointProc := RegisterCallback("EnumChildFindPoint","Fast")
    
    if !(target_window := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText))
        return false
    
    VarSetCapacity(rect, 16)
    DllCall("GetWindowRect","uint",target_window,"uint",&rect)
    VarSetCapacity(pah, 36, 0)
    NumPut(X + NumGet(rect,0,"int"), pah,0,"int")
    NumPut(Y + NumGet(rect,4,"int"), pah,4,"int")
    DllCall("EnumChildWindows","uint",target_window,"uint",EnumChildFindPointProc,"uint",&pah)
    control_window := NumGet(pah,24) ? NumGet(pah,24) : target_window
    DllCall("ScreenToClient","uint",control_window,"uint",&pah)
    cX:=NumGet(pah,0,"int"), cY:=NumGet(pah,4,"int")
    return control_window
}

; Ported from AutoHotkey::script2.cpp::EnumChildFindPoint()
EnumChildFindPoint(aWnd, lParam)
{
    if !DllCall("IsWindowVisible","uint",aWnd)
        return true
    VarSetCapacity(rect, 16)
    if !DllCall("GetWindowRect","uint",aWnd,"uint",&rect)
        return true
    pt_x:=NumGet(lParam+0,0,"int"), pt_y:=NumGet(lParam+0,4,"int")
    rect_left:=NumGet(rect,0,"int"), rect_right:=NumGet(rect,8,"int")
    rect_top:=NumGet(rect,4,"int"), rect_bottom:=NumGet(rect,12,"int")
    if (pt_x >= rect_left && pt_x <= rect_right && pt_y >= rect_top && pt_y <= rect_bottom)
    {
        center_x := rect_left + (rect_right - rect_left) / 2
        center_y := rect_top + (rect_bottom - rect_top) / 2
        distance := Sqrt((pt_x-center_x)**2 + (pt_y-center_y)**2)
        update_it := !NumGet(lParam+24)
        if (!update_it)
        {
            rect_found_left:=NumGet(lParam+8,0,"int"), rect_found_right:=NumGet(lParam+8,8,"int")
            rect_found_top:=NumGet(lParam+8,4,"int"), rect_found_bottom:=NumGet(lParam+8,12,"int")
            if (rect_left >= rect_found_left && rect_right <= rect_found_right
                && rect_top >= rect_found_top && rect_bottom <= rect_found_bottom)
                update_it := true
            else if (distance < NumGet(lParam+28,0,"double")
                && (rect_found_left < rect_left || rect_found_right > rect_right
                 || rect_found_top < rect_top || rect_found_bottom > rect_bottom))
                 update_it := true
        }
        if (update_it)
        {
            NumPut(aWnd, lParam+24)
            DllCall("RtlMoveMemory","uint",lParam+8,"uint",&rect,"uint",16)
            NumPut(distance, lParam+28, 0, "double")
        }
    }
    return true
}

User avatar
DavidP
Posts: 225
Joined: 10 Aug 2014, 07:31

Re: Is ControlClick dependent on a certain Window Class?

21 Oct 2014, 15:22

Thanks for the code, but in this case :o (this seems to be way over my head) I think I shall simply stick with the "Click" command, which works somewhat clumsy, but works.
BeamN6784
Posts: 6
Joined: 09 Mar 2020, 08:43

Re: Is ControlClick dependent on a certain Window Class?

08 Feb 2021, 08:31

I hate to bump such an old post, but I'm curious as to whether or not this code could be adapted to permit ControlClickDrag?
Looking for a solution to the infamous "draw a picture in MsPaint" problem.
guest3456 wrote:
18 Oct 2014, 15:21
DavidP wrote:Sorry but I don't understand where and how I am to put the "WM_MOUSEMOVE" command in connection with the ControlClick command.
try this from the thread linked above, (prob will only work on 32bit ahk)

Code: Select all


ControlClick2(1031, 41, "PDF-XChange Editor")


;// required functions below, add these to the very bottom of your script

ControlClick2(X, Y, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="")  
{  
  hwnd:=ControlFromPoint(X, Y, WinTitle, WinText, cX, cY, ExcludeTitle, ExcludeText)  
  PostMessage, 0x200, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_MOUSEMOVE
  PostMessage, 0x201, 1, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONDOWN  
  PostMessage, 0x202, 0, cX&0xFFFF | cY<<16,, ahk_id %hwnd% ; WM_LBUTTONUP  
}


; Retrieves the control at the specified point.
; X         [in]    X-coordinate relative to the top-left of the window.
; Y         [in]    Y-coordinate relative to the top-left of the window.
; WinTitle  [in]    Title of the window whose controls will be searched.
; WinText   [in]
; cX        [out]   X-coordinate relative to the top-left of the control.
; cY        [out]   Y-coordinate relative to the top-left of the control.
; ExcludeTitle [in]
; ExcludeText  [in]
; Return Value:     The hwnd of the control if found, otherwise the hwnd of the window.
ControlFromPoint(X, Y, WinTitle="", WinText="", ByRef cX="", ByRef cY="", ExcludeTitle="", ExcludeText="")
{
    static EnumChildFindPointProc=0
    if !EnumChildFindPointProc
        EnumChildFindPointProc := RegisterCallback("EnumChildFindPoint","Fast")
    
    if !(target_window := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText))
        return false
    
    VarSetCapacity(rect, 16)
    DllCall("GetWindowRect","uint",target_window,"uint",&rect)
    VarSetCapacity(pah, 36, 0)
    NumPut(X + NumGet(rect,0,"int"), pah,0,"int")
    NumPut(Y + NumGet(rect,4,"int"), pah,4,"int")
    DllCall("EnumChildWindows","uint",target_window,"uint",EnumChildFindPointProc,"uint",&pah)
    control_window := NumGet(pah,24) ? NumGet(pah,24) : target_window
    DllCall("ScreenToClient","uint",control_window,"uint",&pah)
    cX:=NumGet(pah,0,"int"), cY:=NumGet(pah,4,"int")
    return control_window
}

; Ported from AutoHotkey::script2.cpp::EnumChildFindPoint()
EnumChildFindPoint(aWnd, lParam)
{
    if !DllCall("IsWindowVisible","uint",aWnd)
        return true
    VarSetCapacity(rect, 16)
    if !DllCall("GetWindowRect","uint",aWnd,"uint",&rect)
        return true
    pt_x:=NumGet(lParam+0,0,"int"), pt_y:=NumGet(lParam+0,4,"int")
    rect_left:=NumGet(rect,0,"int"), rect_right:=NumGet(rect,8,"int")
    rect_top:=NumGet(rect,4,"int"), rect_bottom:=NumGet(rect,12,"int")
    if (pt_x >= rect_left && pt_x <= rect_right && pt_y >= rect_top && pt_y <= rect_bottom)
    {
        center_x := rect_left + (rect_right - rect_left) / 2
        center_y := rect_top + (rect_bottom - rect_top) / 2
        distance := Sqrt((pt_x-center_x)**2 + (pt_y-center_y)**2)
        update_it := !NumGet(lParam+24)
        if (!update_it)
        {
            rect_found_left:=NumGet(lParam+8,0,"int"), rect_found_right:=NumGet(lParam+8,8,"int")
            rect_found_top:=NumGet(lParam+8,4,"int"), rect_found_bottom:=NumGet(lParam+8,12,"int")
            if (rect_left >= rect_found_left && rect_right <= rect_found_right
                && rect_top >= rect_found_top && rect_bottom <= rect_found_bottom)
                update_it := true
            else if (distance < NumGet(lParam+28,0,"double")
                && (rect_found_left < rect_left || rect_found_right > rect_right
                 || rect_found_top < rect_top || rect_found_bottom > rect_bottom))
                 update_it := true
        }
        if (update_it)
        {
            NumPut(aWnd, lParam+24)
            DllCall("RtlMoveMemory","uint",lParam+8,"uint",&rect,"uint",16)
            NumPut(distance, lParam+28, 0, "double")
        }
    }
    return true
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 247 guests