TC8.0ß1x64 - scripting name of window controls

The behaviour described in the bug report is either by design, or would be far too complex/time-consuming to be changed

Moderators: Hacker, petermad, Stefan2, white

Post Reply
User avatar
Samuel
Power Member
Power Member
Posts: 1930
Joined: 2003-08-29, 15:44 UTC
Location: Germany, Brandenburg an der Havel
Contact:

TC8.0ß1x64 - scripting name of window controls

Post by *Samuel »

When I tried to get my ButtonBar eXtended to work, I mentioned that the controls of the window are named differently.

In my case I need to catch clicks upon the buttonbar:

Code: Select all

 if(WinActive("ahk_class TTOTAL_CMD")){
  MouseGetPos,,,,Control
  
  ; currently the buttonbar is named Window6 in the 64-bit version
  if(Control=="TButtonBar1" || Control=="Window6"){
   return 1
  }
 }
 return 0
Its called "Window6" instead of "TButtonBar1" in the 64-bit version.
Also very important controls like the file controls differ:

Code: Select all

TMyListBox2 => LCLListBox2
TMyListBox1 => LCLListBox1
As there are too many changes I will not list them all. (you can list them with AU3_Spy.exe bundled with AHK)

Would be nice if you could provide an identical namespace.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50386
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Unfortunately Lazarus names most of its controls "Window", and seems to rely on that for certain functions. I manage to give at least the main forms other class names, but not for the controls. :(
Author of Total Commander
https://www.ghisler.com
User avatar
Samuel
Power Member
Power Member
Posts: 1930
Joined: 2003-08-29, 15:44 UTC
Location: Germany, Brandenburg an der Havel
Contact:

Post by *Samuel »

I would appreciate a workaround or fix, but for now I use the Workaround above.
Hope there is only one "Window6" at a time. (And lets hope the names doesn't change randomly.)
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50386
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

The numbering is done by autohotkey when it encounters multiple controls with the same class name. So yes, there will be only one Window6.
Author of Total Commander
https://www.ghisler.com
User avatar
Balderstrom
Power Member
Power Member
Posts: 2148
Joined: 2005-10-11, 10:10 UTC

Post by *Balderstrom »

Actually, Samuel - it's not safe to assume even under TC 7.56 - that the listboxes will be TMyListBox1 and TMyListBox2 --- when you display the various Tree's (or FTP is active if I recall) - the main fileList listboxes will change number (higher) - but they will always be the last ListBoxes.

This is how I safely get the TMyListBox control numbers:

/*
** Basically, it finds all of the controls that are TMyListBox#
** and the File ListBoxes will be the last 2.
*/

Code: Select all

LB_QueryActiveWinID( aWin="A", winText="", notTitle="", notText="" )
{
	return WinActive(aWin+0 ? "ahk_id " aWin : aWin, winText, notTitle, notText)
}

LB_QueryFocusedCtrlID( byRef aControl, byRef aWin="", winText="", notTitle="", notText="" )
{
	LB_QueryActiveWinID( aWin, winText, notTitle, notText )
	if( !aControl )
		ControlGetFocus, aControl, ahk_id %aWin%, %winText%, %notTitle%, %notText%
;MsgBox, QFC: %aControl%`naWin:%aWin%
	ControlGet, aControl, HWND,, %aControl%, ahk_id %aWin%
return aControl
}

;;
;; Returns the active FilePanel's controlID, and both FileList controlID's byRef.
;;
LB_QueryPanelIDsOnly(byRef cID2="", byRef cID1="", aWin="A", byRef activeLR=1)
{
	cID3:=0x1, dx:=0, aLR:=activeLR ;absolute:=(activeLR <> "S")
	if( aWin=="" && !winID:=WinActive("ahk_class TTOTAL_CMD"))
		return LB_QueryFocusedCtrlID( cID2, winID:="A" )
		
	onErrorExit(!winID:=WinExistA(aWin), "ERROR: Cannot Find Window [ " aWin " ]", A_ThisFunc)
	
	while( (cID2:=cID3) && LB_ControlGetID(cID3, "TMyListBox" (++dx), winID) && cID1:=cID2 )
			continue
	ControlGetFocus, cFocus, ahk_id %winID%
	LB_ControlGetID( cID3, cFocus, winID )
return (inStr(cID1 "," cID2, cID3) == 1 ? cID1 : cID2)
;; The return value used to be inStr(cID1 "," cID2, cID3)
;; --- I don't recall why I did that, I changed it to the above for this post. 
;; --- but it could very likely just be:
;; -----> return ( cID1 == cID3 ? cID1 : cID2 )
}



onErrorExit( checkEval, errMsg="", fn="", delay=3 )
{
	if( !checkEval )
		return 0
	if((!ErrorLevel || ErrorLevel:=1) && !errMsg)
		Exit
	RegExMatch(fn, "^([^:]+)(::([^ ].*))?$", rTmp )
	msg := ( rTmp1 ? rTmp1 "(" rTmp3 "): " : "" ) errMsg
	MsgBox,, % A_ScriptName " :: " rTmp1, % msg, % delay
Exit
}
How to use, with TC7, as my whole TC.ahk library will need to be changed for TC8. And at this point I don't know if I can make my TC.ahk and LB.ahk libraries compatible with TC8 x64 or not.
TC_HWND:=WinActive("ahk_class TTOTAL_CMD")
aPanel:=LB_QueryPanelIDsOnly(TC_HWND, cPanelA:="", cPanelB:="")
Then there's this one, which was the original function, it can determine which FilePanel is "active" even when TC is minimized or not the active window.

Code: Select all

/*
**	TC_QueryPanelID()
**
**	Return: HWND (ID) of the Active FileList Panel (TMyListBox#)
**
**	Input Parameters:			Output Parameters:
1&	cID2: ""					ID of L.Panel (if input activeLR<>1), else Source
2&	cID1: ""					ID of R.Panel (if input activeLR<>1), else Target
3	aWin: "WinTitle" or HWND	-
4&	activeLR: 0,1 (Boolean)		"Left" or "Right" (active Panel)
**
*/
LB_QueryPanelID(byRef cID2="", byRef cID1="", aWin="A", byRef activeLR=1)
{
	cID3:=0x1, dx:=0, aLR:=activeLR ;absolute:=(activeLR <> "S")
	if( aWin=="" && !winID:=WinActive("ahk_class TTOTAL_CMD"))
		return LB_QueryFocusedCtrlID( cID2, winID:="A" )
		
	onErrorExit(!winID:=WinExistA(aWin), "ERROR: Cannot Find Window [ " aWin " ]", A_ThisFunc)
	
	while( (cID2:=cID3) && LB_ControlGetID(cID3, "TMyListBox" (++dx), winID) && cID1:=cID2 )
			continue
	if( !ErrorLevel:=!(WinActive("A") == winID) )
	{
;		MsgBox, sending ESC...
;		Send, {ESC}
		ControlGetFocus, activeLR, ahk_id %winID%
	}
	else
	{
		TC_CMD("cm_ShowQuickSearch", winID)
		WinWait, QUICKSEARCH ahk_class TQUICKSEARCH 
		WinGetPos,  tpX,,,, % "ahk_id " LB_ControlGetID( tp1, "TPanel1", winID )
		WinGetPos,  qsX,,,, % "ahk_id " qikS:=WinExist("QUICKSEARCH ahk_class TQUICKSEARCH")
		ControlSend,, {ESC}, ahk_id %qikS%
		activeLR:="TMyListBox" (qsX > tpX ? dx-2 : dx-1) ; ? "Right" : "Left")-
	}
		
	LB_ControlGetID( cID3, activeLR, winID )
	activePanel:=activeLR
	if((activeLR:=(cID3 == cID1 ? "Right" : "Left")) && aLR && cID3 == cID1)
		LB_Swap(cID1, cID2)
;MsgBox, winID: %winID%`nActivePanel: %cID3% (%activePanel%) [%activeLR%]`nReturnValue: %cID2%`nOtherPanel:: %cID1%
return (cID2)
}


LB_Swap( byRef v1, byRef v2, dx="" )
{
	v3:=v1,v1:=v2,v2:=v3
return (dx=="" ? TRUE : v%dx%)
}


LB_ControlGetID( byRef cID, cName, wID="" )
{
;;	LB_QueryActiveWinID( winID )
	ControlGet, cID, HWND,, %cName%, ahk_id %wID%
return cID
}
Replace TC_CMD() with the relevant command# for activating quickSearch --- as that is a lot more code that more heavily relies on my TC.ahk LIB and self-defined functions in AHK_F.ahk
Last edited by Balderstrom on 2011-09-27, 16:49 UTC, edited 3 times in total.
User avatar
Balderstrom
Power Member
Power Member
Posts: 2148
Joined: 2005-10-11, 10:10 UTC

Post by *Balderstrom »

And is it safe to assume Window6 for the buttonBar? I haven't tested the various control#'s with TC8 yet. But you would need to enable/disable all of the various GUI elements, FTP, driveBar, etc - and see if the ButtonBar's Window# changes at all.

I know I used to assume a specific TMyPanel for the current path (left of the command-line)... but again I found that depending on what GUI elements were active in the window it's id# would change.

Code: Select all

TC_QueryPathA(wID, byRef pathID="") {
	return SubStr(ControlGetText(cText, pathID ? pathID : pathID:=TC_QueryPathID(wID)), 1, -1)
}


TC_QueryPathID(wID) {
	Loop, 3
		if(">" == SubStr(ControlGetText(cText, "TMyPanel" (A_Index + 2), wID), 0))
			return ControlGet("TMyPanel" (A_Index + 2), pathID:="HWND",  "",  wID)
return (pathID)
}
Quick Example to call function from ButtonBar:

Code: Select all

path:=TC_QueryPathA( WinActive("ahk_class TTOTAL_CMD"), pathID:="")
MsgBox, pathID: %pathID%`npath: %path%
return
Obviously you would want to find TC's HWND without needing to call it from a buttonBar, but I have TC 7 and 8 running atm, and want quick examples that work :-)

Function Naming Note:
I use functionA() when defining existing commands (or new commands) that can accept either 1) a HWND, 2) "A", or
3) full normal or partial string, e.g. "Some Title ahk_class FOO" or "ahk_class BAR".

Example:

Code: Select all

WinExistA( aWin="", winText="", notTitle="", notText="" )
{
	return WinExist( (aWin+0 ? "ahk_id " aWin : aWin), winText, notTitle, notText )
}
Although, in the case above, TC_QueryPathA --- it only accepts a HWND, probably should be named: TC_QueryPathH... heh.
I find it easier to just pass around HWND's for the most part - since you only need to get that once.
Last edited by Balderstrom on 2011-09-27, 17:05 UTC, edited 1 time in total.
User avatar
Balderstrom
Power Member
Power Member
Posts: 2148
Joined: 2005-10-11, 10:10 UTC

Post by *Balderstrom »

@Samuel,

Here's a way to get the application path
Useful, since both TC x64 and TC 8 x32 and TC7 all have the same ahk_class of TTOTAL_CMD

I Modified the original to work with AHK_L x64 and x32 instead of only AHK standard (which hasn't been updated in 2+ years --- I think Chris may of unofficially passed the reigns to Lexikos).

Code: Select all

GetFullPath(pid)        ; Return X:\dir\sub\my.exe 
{ 
    ;; http://www.autohotkey.com/forum/viewtopic.php?t=19873 
    ;; Open process with: PROCESS_VM_READ (0x0010) | PROCESS_QUERY_INFORMATION (0x0400): 
    hProcess := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", pid) 
    size := VarSetCapacity(filename, 250 * (A_IsUnicode ? 2 : 1)) ; max. length of filename 
    DllCall("Psapi.dll\GetModuleFileNameEx", "UInt", hProcess, "Int", 0, "Str", filename, "Int", size) 
    DllCall("CloseHandle", "UInt", hProcess) 
return %filename% 
}
Example:

Code: Select all

	WinGet, pID, PID, A 
	pPath := GetFullPath(pID) 
	listBox:=inStr(pPath, "\TOTALCMD64.EXE") ? "LCLListBox" : "TMyListBox"
Post Reply