Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Total Commander, Set Title to Active Path


  • Please log in to reply
No replies to this topic
Crash&Burn
  • Members
  • 228 posts
  • Last active: Jul 16 2014 10:10 PM
  • Joined: 02 Aug 2009
Script: TC_ST2A.ahk

Usage: Automatically Set Total Commander's Title to ActivePath + Version# + RegisteredName

Customization of Title output can be easily done in the FormatTitle function.

Many thanks to fine examples by Lexikos and Skan.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	File:	TC_ST2A.ahk 	(TC_SetTitleToActive)
;; 
;;	Version: 3.40	Date: Oct.2010	 
;; AHK_L compatible, removed DOT concatenation of strings.
;;	 
;;	Requires: Autohotkey: 1.0.48 - February 25, 2009
;; 
;;	Author: Balderstrom, aka Crash&Burn
;;
;;
;;	From AHK Boards: http://www.autohotkey.com/forum/viewtopic.php?t=61979
;;	:: 
;;	:: Modified RegisterCallBack Example by Lexikos, and SKAN's ShellMessages.
;;	::
;;	:: Included: SKAN's ProcessCreationTime() to fix sorting of TC Windows.
;;	::
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:
;;	To Customize title output: See the TC_ST2A__FormatTitle function below.
;;	:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	Version 3 Notes::
;;		Script utilizes NO HotKeys AND NO Timers. 
;;		Due to the addition of RegisterCallBack(), the minimum AHK version has been increased.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	Version 2 Notes::
;;		There is an unreleased v2, which fixed almost all previous issues (uses the HotKey method).
;;			If theres any interest/need will clean up the code for posting.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	#SingleInstance, Force
	#Persistent
	#NoEnv
SetBatchLInes, -1
SetTitleMatchMode 2
DetectHiddenWindows, ON
OnExit, DeRegisterHooks

WinGet, TC_ST2A__hWnd, ID, %A_ScriptFullPath%
DllCall( "RegisterShellHookWindow", "UInt",TC_ST2A__hWnd ) 
TC_ST2A__MsgNum := DllCall( "RegisterWindowMessage", "Str","SHELLHOOK" ) 
OnMessage( TC_ST2A__MsgNum, "TC_ST2A__ShellMessages" ) 

TC_COUNT := 0
;;
;;	Total Commander Global newLine delimited Strings (PseudoArrays)
;;
T_TC_hwnd		:= ""	; TC hwnd's
T_TC_InSysTray	:= ""	; TC hwnd's in the SystemTray
T_TC_csID		:= ""	; TC hwnd's of TMyPanel3 (Command Prompt|Status)
T_TC_RCB		:= ""	; TC RegisterCallBack pointers	(So we can FREE Them)
T_TC_hHook		:= ""	; TC EventHook IDs				(So we can FREE Them)
T_TC_ownName	:= ""
T_TC_version	:= ""
T_TC_wincmd		:= ""
T_TC_BBMinWidthChange := 1139
T_TC_BBChanged  := FALSE

TC_ST2A__HShellMsgName()
TC_ST2A__INIT( TRUE )	;;	TC_FindALLInstances()
;__ADDEventHook__ObjectCreate()
return


TC_ST2A__FormatTitle( tInstance, tPath, tOwnName, tVersion )
{
	global TC_COUNT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Change this to the string to be appended to TitleBar's SourcePath
;;;	i.e. "     ::     Total Commander "
;;;
	titleTCName := "   -::-   TC "
;;;
;; For the first Running Instance of TC
;; 0 : Do Not Show TC Instance Number
;; 1 : Always Show TC Instance Number
;; 2 :  Only  Show TC Instance Number if more than 1 Copy of TC is Running.
;;;
	showTCNum1 := 2
;;;
	upperCaseDriveLetter := TRUE
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	tcNum := "[" tInstance "]  "
	if( tInstance == 1 && (!showTCNum1 || (showTCNum1 && TC_COUNT < showTCNum1)) )
		tcNum := ""
	
	tPath := ( upperCaseDriveLetter ? UpperChar(tPath, 1) SubStr(tPath, 2, -1) : tPath )
	
return ( tcNum tPath titleTCName tVersion " - " tOwnName )
}



TC_ST2A__TitleReset( wID="", cID="", idx="", path="", ownName="", version="" )
{
	global T_TC_hwnd, T_TC_ownName, T_TC_version
	
	wID := WinExist( !wID ? "A" : "ahk_id " wID )
	
	idx := (idx ? idx : ParseStringN( T_TC_hwnd, wID ))
	idx := (idx ? idx : ParseStringN( T_TC_hwnd, cID ))
	if( !idx )
		MsgBox, % A_ThisFunc " :: No IDX!!"
	ownName := ( ownName ? ownName : ParseStringN( T_TC_ownName, "", idx ))
	version := ( version ? version : ParseStringN( T_TC_version, "", idx ))
	if( !path )
		ControlGetText, path, TMyPanel3, ahk_id %wID%
	title := TC_ST2A__FormatTitle( idx, path, ownName, version )
	WinSetTitle, ahk_id %wID%,, %title%
return
}

UpperChar( cStr, cPos )
{
	cStr := SubStr(cStr, cPos, 1)
	StringUpper, cStr, cStr
return cStr
}


;;
;;	ParseStringN()
;;	::	Parse a newline delimited String ( AHK/Pseudo Array )
;;	::	
;;	::	Returns the index position of the string, 0 if not Found.
;;	OR	Returns the string @ index position "idx"
;;	::
;;	::	NOTE:: idx var overides sFind for what matching is performed.
;;	::
ParseStringN( T_stringN, sFind="", idx=0, removeFound=FALSE )
{
	retVal := ( idx ? 0 : "" )
	sLen:=0
	if( idx )
	{
		Loop, Parse, T_stringN, `n
		{
			sLen += 1 + strlen(A_LoopField)
			if( idx == A_Index && retVal:=A_LoopField && rvLen:=strlen(A_LoopField) )
				break
		}
	}
	else
	{
		Loop, Parse, T_stringN, `n
		{
			sLen += 1 + strlen(A_LoopField)
			if( sFind == A_LoopField && retVal:=A_Index && rvLen:=strlen(A_LoopField) )
				break
		}
	}

	if( removeFound )
		T_stringN:=substr(T_stringN, 1, sLen - rvLen - 1) substr(T_stringN, sLen + 1)
return retVal
}


TC_ST2A__GETTitlePart( wID, byRef ownName, byRef version )
{
	pass := 0
	if( !WinActive( "ahk_id " wID ) )
		WinActivate, ahk_id %wID%
	ST2A__GetTitlePart:
	WinGetTitle, aTitle, ahk_id %wID%
	RegExMatch( aTitle, "(\[(\d+)\] )?(.* - )?Total Commander (.*) - (.*)$", titleTC )
	ownName	:= titleTC5
	version := titleTC4

	if( !ownName || !version )
	{
		if( pass <> 0 )
		{
			MsgBox, Error cannot get Total Commander's Title
			Exit
		}
		++pass	
		WinMinimize, ahk_id %wID%
		WinActivate, ahk_id %wID%
		Sleep, 100
		goto, ST2A__GetTitlePart
	}
return
}


TC_ST2A__CreateStruct( wID, index=0 )
{
static
	global TC_COUNT, T_TC_ownName, T_TC_version, TC_TCINI
	global T_TC_hwnd, T_TC_csID, T_TC_hHook, T_TC_RCB, T_TC_xWyH
	local cID, ownName, version, wincmd
	static init:=0

	if( !init && init:=1 )
	{
		local globalVars, gVar
		
		globalVars:="T_TC_ownName,T_TC_version,T_TC_hwnd,T_TC_csID,T_TC_hHook,T_TC_RCB"
		Loop, Parse, globalVars, `,
			gVar := A_LoopField, %gVar% := ""
		TC_COUNT:=0
	}

	ControlGet, cID, Hwnd,, TMyPanel3, ahk_id %wID%
	wID += 0	; Make sure Decimal format
	cID += 0	; Make sure Decimal format

	if( !ParseStringN(T_TC_hwnd, wID) && ++TC_COUNT )
	{	; New Instance of TC Started
	
		T_TC_hwnd .= wID "`n"		; Update TotalCMDR hwnd's
		T_TC_csID .= cID "`n"		; Update TMyPanel3 hwnd's

		TC_ST2A__GETTitlePart( wID, ownName, version )
		T_TC_ownName .= ownName "`n"
		T_TC_version .= version "`n"
/*
		if( !wincmd%version% )	; STATIC Variable
		{
			TC_EMC( "em_CMDSTART cmd.exe /c START ""em_RUN_TC_ST2A"" /MIN setenv.exe -v TC_" wID "_wincmd "`"%%COMMANDER_INI%%`", "", "ahk_id " wID ) 
			WinWaitClose, em_RUN_TC_ST2A ahk_class ConsoleWindowClass
			RegRead, wincmd, HKEY_CURRENT_USER, Volatile Environment, TC_%wID%_wincmd
			wincmd%version% := wincmd
		}
*/
		TC_ST2A__ADDEventHook( wID, R_hHook, R_tcRCB )
		T_TC_hHook	.= R_hHook "`n"	; Update hHook
		T_TC_RCB 	.= R_tcRCB "`n"	; Update RegisterCallBack pointer LIST
		TC_ST2A__TitleReset( wID, "", TC_COUNT, "", ownName, version )
		
	}
	else
	{
		MsgBox, %A_ThisFunc% :: Error, Attempting to Add the same TC Instance again.
		Exit
	}
return
}


TC_ST2A__DeleteStruct( wID="", DX=0 )
{
	global TC_COUNT, T_TC_ownName, T_TC_version
	global T_TC_hwnd, T_TC_csID, T_TC_hHook, T_TC_RCB

	index := (DX ? DX : ParseStringN( T_TC_hwnd, wID, 0, TRUE ))
	ParseStringN( T_TC_csID,    "", index, TRUE )	; Version 3.2 Fix
	ParseStringN( T_TC_ownName, "", index, TRUE )	; Remove index-Position from Array
	ParseStringN( T_TC_version, "", index, TRUE )	; Remove index-Position from Array
	i := index - 1
	Loop, % TC_COUNT - index
		TC_ST2A__TitleReset(ParseStringN( T_TC_hwnd, "", A_Index + i ))

	hHook := ParseStringN( T_TC_hHook, "", index, TRUE )	; RemoveFound=TRUE, ReturnField=TRUE
	tcRCB := ParseStringN( T_TC_RCB,   "", index, TRUE )	; RemoveFound=TRUE, ReturnField=TRUE
	TC_ST2A__UnHookEvent( hHook, tcRCB )
	
	--TC_COUNT
return
}


TC_ST2A__INIT( preINIT=TRUE )	;TC_FindALLInstances( EnumerateSysTray=FALSE )
{
	global T_TC_InSysTray, TC_TCINI
	T_TC_InSysTray := ""
	WinGet, wIDTray, list, , , ahk_class Shell_TrayWnd
	Loop, %wIDTray% 
	{ 
		thisID := wIDTray%A_Index%
		WinGetClass, thisClass, ahk_id %thisID%
		if( thisClass <> "TTOTAL_CMD" ) 
			continue
		WinGetTitle, aTitle, ahk_id %thisID%
		WinGet, tcPID, PID, ahk_id %thisID%
		tc_CTList .= ProcessCreationTime( tcPID ) "," thisID "`n"
	}

	Sort, tc_CTList, N

	Loop, Parse, tc_CTList, `n
	{
		if( !A_LoopField )
			break
		Loop, Parse, A_LoopField, `,
			thisID := ( A_Index == 2 ? A_LoopField : "" )
		if( preINIT )
			TC_ST2A__CreateStruct( thisID + 0, A_Index )
		DetectHiddenWindows, OFF
		T_TC_InSysTray .= ( WinExist("ahk_id " thisID) ? "" : thisID + 0 "`n" )
		DetectHiddenWindows, ON
	}
return
}


ProcessCreationTime( PID ) {                        ; Requires AutoHotkey v1.0.46.03+ 

 VarSetCapacity(PrCT,16)  ,  VarSetCapacity(Dummy,16)  ,  VarSetCapacity(SysT,16) 

 AccessRights := 1040       ; PROCESS_QUERY_INFORMATION = 1024,  PROCESS_VM_READ = 16 
 hPr:=DllCall( "OpenProcess", Int,AccessRights, Int,0, Int,PID ) 
 DllCall( "GetProcessTimes" , Int,hPr, Int,&PrCT, Int,&Dummy, Int,&Dummy, Int,&Dummy) 
 DllCall("CloseHandle"      , Int,hPr) 

 DllCall( "FileTimeToLocalFileTime" , Int,&PrCT, Int,&PrCT )  ; PrCT is Creation time 
 DllCall( "FileTimeToSystemTime"    , Int,&PrCt, Int,&SysT )  ; SysT is System Time 

 Loop 16   {       ; Extracting and concatenating 8 words from a SYSTEMTIME structure 
  Word := Mod(A_Index-1,2) ? "" :  *( &SysT +A_Index-1 ) + ( *(&SysT +A_Index) << 8 ) 
  Time .= StrLen(Word) = 1 ? ( "0" Word ) : Word  ; Prefixing "0" for single digits 
           } 
Return SubStr(Time,1,6) SubStr(Time,9) ; YYYYMMDD24MISS 
}


TC_ST2A__ADDEventHook( wID, byRef hHook, byRef tcRCB )
{
	WinGet, tcPID, PID, ahk_id %wID%

	hHook := DllCall("SetWinEventHook", "uint", 0x800B, "uint", 0x800C 
				, "uint", 0
				, "uint", tcRCB := RegisterCallback("TC_ST2A__ObjectChange") 
				, "uint", tcPID		; idProcess (0=all) 
				, "uint", 0
				, "uint", 0 )
return
}

TC_ST2A__BBIconSize()
{
	TC_BBICONSIZE := 5 + (( (tcWidth - 8) == A_ScreenWidth && (tcHeight - 8) == A_ScreenHeight ) ? 24 : 32 )
return
}

TC_ST2A__ObjectChange( hWinEventHook, event, hwnd, idObject, idChild, thread, time ) 
{
static
	global T_TC_csID, T_TC_hwnd, T_TC_BBMinWidthChange, T_TC_BBChanged
	local idx
	local EVENT_OBJECT_LOCATIONCHANGE := 0x0000800B
	local EVENT_OBJECT_NAMECHANGE     := 0x0000800C
	local tcWidth
	

	if( event == EVENT_OBJECT_LOCATIONCHANGE && T_TC_BBMinWidthChange )
	{
		if( !ParseStringN( T_TC_hwnd, hwnd ) )
			return
		WinGetPos,,, tcWidth,,, ahk_id %hwnd%
		if( tcWidth < T_TC_BBMinWidthChange )
			TC_ST2A__BBIconSize()
	return
	}

	if( idx := ParseStringN( T_TC_csID, hwnd ))
	{
		ControlGetText, cText%hwnd%,, ahk_id %hwnd%
		if( cText%hwnd% == cTextLast%hwnd% )
			return
		cTextLast%hwnd% := cText%hwnd%
		TC_ST2A__TitleReset( "", hwnd, idx, cText%hwnd% )
	}
	else
	if( idx := ParseStringN( T_TC_hwnd, hwnd ))
		TC_ST2A__TitleReset( hwnd, "", idx, cTextLast%hwnd% )
return
}


TC_ST2A__ShellMessages( wP,lP ) 
{
	global T_TC_InSysTray

	routine := TC_ST2A__HShellMsgName( wP )
	
	WinGetClass, aClass, ahk_id %lP%
	
	if( aClass <> "TTOTAL_CMD" )
		return
	
	if( routine == "HSHELL_WINDOWCREATED" ) 
	{
		if( ParseStringN( T_TC_InSysTray, lP, 0, TRUE ) )
			return
		else
			TC_ST2A__CreateStruct( lP + 0 )
	}
	else
	if( routine == "HSHELL_WINDOWDESTROYED" )
	{
		Sleep, 100
		TC_ST2A__INIT( FALSE )	; Update T_TC_InSysTray
		if(!inStr( T_TC_InSysTray, lP "`n" )) 
			TC_ST2A__DeleteStruct( lP + 0 )
	}
return
}


TC_ST2A__HShellMsgName( msgNum="" )
{
	static
	static init := 0
	local msgName
	
	if( !init && init := 1 )
	{
		local hMsgNames := " 
			(LTrim Join,  
				HSHELL_WINDOWCREATED
				HSHELL_WINDOWDESTROYED 
				HSHELL_ACTIVATESHELLWINDOW 
				HSHELL_WINDOWACTIVATED 
				HSHELL_GETMINRECT 
				HSHELL_REDRAW 
				HSHELL_TASKMAN 
				HSHELL_LANGUAGE 
				HSHELL_SYSMENU 
				HSHELL_ENDTASK 
				HSHELL_ACCESSIBILITYSTATE 
				HSHELL_APPCOMMAND 
				HSHELL_WINDOWREPLACED 
				HSHELL_WINDOWREPLACING 
				HSHELL_HIGHBIT 
				HSHELL_FLASH 
				HSHELL_RUDEAPPACTIVATED 
			)"
			
		Loop, Parse, hMsgNames, `,
		{
			HSHELL__MSG%A_Index% := A_LoopField
		}
		if( msgNum == "" )
			return
	}
return ( msgName := (HSHELL__MSG%msgNum% ? HSHELL__MSG%msgNum% : "UNKNOWN") )
}


TC_ST2A__UnHookEvent( hHook, tcRCB )
{
Critical 
	if( hHook )	
		DllCall("UnhookWinEvent", "Uint", hHook)
	if( tcRCB )
		DllCall("GlobalFree", UInt, &tcRCB )
return
}

DeRegisterHooks:
{
Critical
	MsgBox,,DeRegisterHooks, Deregistering Hooks...,1

	DllCall( "UnhookWinEvent", Uint,hWinEventHook ) 
	DllCall( "GlobalFree", UInt,&HookProcAdr ) ; free up allocated memory for RegisterCallback 

	DllCall( "DeregisterShellHookWindow", "UInt", TC_ST2A__hWnd )
	Loop, %TC_COUNT%
		TC_ST2A__DeleteStruct( "", A_Index )	; This includes, Unhooking Events.
	ExitApp
}	 


TC_ST2A__ExitScript()
{
	MsgBox,4,%A_ScriptName%::%A_ThisFunc%(),Do you wish to Exit %A_ScriptName%?,4
	ifMsgBox, YES
		ExitApp
	else
	ifMsgBox, TimeOut
		return
return
}

/*	NOTE::
 *	If you disable the SystemTray icon above, then
 *	you should enable a Hotkey to exit the script.
 */
;#ifWinActive, ahk_class TTOTAL_CMD
;{
;	;; ^#!4::TC_ST2A__ExitScript()
;return
;}

v3.1:
* Small Fix, readded Beta versions ProcessCreationTime to properly Sort TC instanceNumbers by time created.

v3.0:
* Complete Rewrite. Requires more recent version of AutoHotKey.
* Fixed all outstanding issues.
* Handles Multiple running Total Commander instances.
* Easier customization of Title output in the FormatTitle function.

v2.0:
*Unreleased.
* Fixed all outstanding issues, except for (1)one:
(1) If a new instance of the script was started,
---- i.e. with a shortcut to launch both - that straggler issue was resolved.

v1.9:
* Fix for multiple instances of TC running (show instance #).
* Removed static variables. Some Formatting fixes/changes. Code Clean-up.

v1.8:
* Removed a Panel-Detection code: no longer needed since path is retrieved from the Command-Prompt/Status.
* Moved the Context-Menu detection to the end of the script.
* Removed Timed CallOUT for Left Click -- back to previous implementation: With the other changes Double-Click is not impeded any longer.

v1.7:
* Changed almost all triggers to "key up", improved efficiency.
* Changed LButton significantly; noticed an oddity with DoubleClick --Rename-in-place was getting triggered for slightly-slower-DoubleClicks.

v1.6:
* Removed WIN+Ctrl+Alt+T, not needed as noted by MVV.
* Added, Ctrl+R trigger, Commented ;F2

v1.5: Implemented MVV suggestion, get Title from Left of Command-Line.

v1.4: Removed While, replaced with if

v1.3: Fix for ContextMenus: which blocked retrieving title with cm_CopySrcPathToClip

v1.2: Fix for changing path via the BreadCrumb, or Editing the Path.

v1.1: Slight Change for TAB, Since Ctrl+Tab, Shift+Ctrl+Tab cycles through FileTABs.


Originally posted on Total Commander Forums.