Jump to content

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

Most Recently Opened Folders Popup Menu


  • Please log in to reply
1 reply to this topic
ChrisM
  • Members
  • 58 posts
  • Last active: Oct 25 2006 05:56 PM
  • Joined: 28 Nov 2004
Here is another script based on FavoritesFolders.

This one is meant to keep track of all the folders visited by one specified program. The popup menu then shows the full paths, in the order of most recent to least recent.

It still uses the .ini file method. This could be changed to the new link file method ( see http://www.autohotke...opic.php?t=1427 ) But since it's meant to be a temporary and ever changing list of folders I think the .ini file may be good enough.

The program your keeping track of has to have the full path displayed in it's window title. Is there a way around this restriction?

Without the (~) in the hotkey definition the menu can be used outside of the specified program, but it may need work here to refine it. I don't use it like that.

Enjoy.

; Most Recently Opened Folders -- by ChrisM
; 
; Based on: Easy Access to Favorite Folders -- by Savage
; http://www.autohotkey.com
; Tested with ver 1.0.24 on WinXP

; All variables to start with rf_
;
; Keeps track of Most Recently Opened Folders for a particular application.
; The application must display a valid path in it's window title for this script 
; to work.

; When you click the middle mouse button while a standard file-open or file-save
; dialog is open this script displays a menu of the most recently opened 
; folders for the specified application.  
; Upon selecting a menu item, the script will instantly switch to that folder
; within the standard file-open or file-save dialog.


; CONFIG: THE EXECUTABLE NAME
; The name of the executable that starts the target application. Do not supply 
; the path to the executable.
rf_Executable = PSPad.exe


; CONFIG: CHOOSE YOUR HOTKEY
; If your mouse has more than 3 buttons, you could try using
; XButton1 (the 4th) or XButton2 (the 5th) instead of MButton.
; You could also use a modified mouse button (such as ^MButton) or
; a keyboard hotkey.  In the case of MButton, the tilde (~) prefix
; is used so that MButton's normal functionality is not lost when
; you click in other window types, such as a browser. The presence
; of a tilde tells the script to avoid showing the menu for
; unsupported window types.  In other words, if there is no tilde,
; the hotkey will always display the menu; and upon selecting a
; menu item while an unsupported window type is active, a new
; Explorer window will be opened to display the contents of that
; folder.
; If this script is meant to be dedicated to only one application 
; you should always have the tilde (~) prefix.
rf_Hotkey = ~MButton


; END OF CONFIGURATION SECTION
; Do not make changes below this point unless you want to change
; the basic functionality of the script.

#SingleInstance force ; Needed since the hotkey is dynamically created.

Hotkey, %rf_Hotkey%, rf_DisplayMenu

StringLeft, rf_HotkeyFirstChar, rf_Hotkey, 1
if rf_HotkeyFirstChar = ~  ; Show menu only for certain window types.
	rf_AlwaysShowMenu = n
else
	rf_AlwaysShowMenu = y

;----Read the configuration file.
rf_MenuItemCount = 20

; Initialize all menu array elements, leave blank
rf_index = 0
Loop, %rf_MenuItemCount%
{
	rf_index++
	rf_path%rf_index% = 
}

; Flag to stop an attemp at showing an empty menu
rf_menuExist = 0

; Read in any paths saved in 'rf_iniFile'
SplitPath, A_ScriptName, , , , rf_iniFile
rf_iniFile = %rf_iniFile%.ini
rf_index = 0
Loop, Read, %rf_iniFile%
{
	rf_line = %A_LoopReadLine% ; Trim leading and trailing spaces.
	if rf_line <>  ; Blank lines are not loaded.
	{
		rf_index++
		; Resolve any references to variables, and
		; create a new array element containing the path of this recent folder:
		Transform, rf_path%rf_index%, deref, %rf_line%
		Menu, rf_RecentFolders, Add, %rf_line%, rf_OpenRecentFolder
		rf_menuExist = 1
	}
}

; Get path from main window titles.
SetTimer, rf_FindPath, 10000

OnExit, ExitSub

return  ;----End of auto-execute section.


;----Display the menu
rf_DisplayMenu:
	; These first few variables are set here and used by rf_OpenRecentFolder:
	WinGet, rf_active_id, ID, A
	WinGetClass, rf_class, ahk_id %rf_active_id%
	if rf_class in #32770,ExploreWClass,CabinetWClass  ; Dialog or Explorer.
		ControlGetPos, rf_Edit1Pos,,,, Edit1, ahk_id %rf_active_id%
	if rf_AlwaysShowMenu = n  ; The menu should be shown only selectively.
	{
		; Only display menu over rf_Executable file dialog boxes.
		WinGet, rf_process, ProcessName, ahk_id %rf_active_id%
		if rf_process <> %rf_Executable% 
			return
		if rf_class = #32770  ; Dialog 
		{
			if rf_Edit1Pos =  ; The control doesn't exist, so don't display the menu
			return
		}
		else 
		{
			return ; Since it's some other window type, don't display menu.
		}
	}
	; Otherwise, the menu should be presented for this type of window:
	if rf_menuExist = 1
		Menu, rf_RecentFolders, show
return


;----Open the selected recent folder
rf_OpenRecentFolder:
	; Fetch the array element that corresponds to the selected menu item:
	StringTrimLeft, rf_path, rf_path%A_ThisMenuItemPos%, 0
	if rf_class = #32770    ; It's a dialog.
	{
		if rf_Edit1Pos <>   ; And it has an Edit1 control.
		{
			; Activate the window so that if the user is middle-clicking
			; outside the dialog, subsequent clicks will also work:
			WinActivate ahk_id %rf_active_id%
			; Retrieve any filename that might already be in the field so
			; that it can be restored after the switch to the new folder:
			ControlGetText, rf_text, Edit1, ahk_id %rf_active_id%
			; Insert directory to switch to.
			ControlSetText, Edit1, %rf_path%, ahk_id %rf_active_id%
			ControlSend, Edit1, {Enter}, ahk_id %rf_active_id%
			Sleep, 100  ; It needs extra time on some dialogs or in some cases.
			ControlSetText, Edit1, %rf_text%, ahk_id %rf_active_id%
			return
		}
	; else fall through to the bottom of the subroutine to take standard action.
	}
	else if rf_class in ExploreWClass,CabinetWClass  ; In Explorer, switch folders
	{
		if rf_Edit1Pos <>   ; And it has an Edit1 control.
		{
			ControlSetText, Edit1, %rf_path%, ahk_id %rf_active_id%
			; Tekl reported the following: "If I want to change to Folder L:\folder
			; then the addressbar shows http://www.L:\folder.com. To solve this,
			; I added a {right} before {Enter}":
			ControlSend, Edit1, {Right}{Enter}, ahk_id %rf_active_id%
			return
		}
	; else fall through to the bottom of the subroutine to take standard action.
	}
	; In a console window, CD to that directory
	else if rf_class = ConsoleWindowClass 
	{
    ; Reactivate window because sometimes the mclick deactivates it.
		WinActivate, ahk_id %rf_active_id% 
		; This will be in effect only for the duration of this thread.
		SetKeyDelay, 0  
		IfInString, rf_path, :  ; It contains a drive letter
		{
			StringLeft, rf_path_drive, rf_path, 1
			Send %rf_path_drive%:{enter}
		}
		Send, cd %rf_path%{Enter}
		return
	}
	; Since the above didn't return, one of the following is true:
	; 1) It's an unsupported window type but rf_AlwaysShowMenu is y (yes).
	; 2) It's a supported type but it lacks an Edit1 control to facilitate the 
  ;    custom action, so instead do the default action below.
	Run, Explorer %rf_path%  ; Might work on more systems without double quotes.
return


;----Try to find a valid path from a EdgeCAM main window title
rf_FindPath:
	SetTitleMatchMode, 1
	WinGet, rf_process, ProcessName, A
	if rf_process <> %rf_Executable% 
		return
	WinGetTitle, rf_winTitle, A
	
	; Parse the window title for a valid path.
	rf_index = 0
	rf_goodPath = ; Initialize to blank
	; Loop one character at a time. This is like "Loop, Count". It ensures
	; we loop once for every character without having to find the string length.
	Loop, Parse, rf_winTitle
	{
		rf_index++
		; Keep adding characters from the right.
		StringRight, rf_newPath, rf_winTitle, %rf_index%
		; Get rid of everything to the right of the last "\".
		SplitPath, rf_newPath, , rf_OutDir 
		; Only keep a path that is valid.
		IfExist, %rf_OutDir%
		rf_goodPath = %rf_OutDir%	
	}
	IfExist, %rf_goodPath%
	{
		rf_addRecentFolder = %rf_goodPath%
		GoSub, rf_AddToRecentFolders
	}
return


;----Save found valid path to the 'rf_iniFile' file.
rf_AddToRecentFolders:
	StringLower, rf_test, rf_addRecentFolder
	; Loop thru existing menu items to check for duplicates.
	rf_index = 0
	Loop, %rf_MenuItemCount%
	{
		rf_index++
		StringLower, rf_nextMenu, rf_path%rf_index%
		ifEqual rf_nextMenu, %rf_test%
		{
			; This recentFolder is a duplicate, 
			;we will delete the old and add new to top of list
			rf_count = %rf_MenuItemCount%
			rf_count -= %rf_index%
			Loop, %rf_count%
			{
				rf_indexPlus1 = %rf_index%
				rf_indexPlus1++
				StringTrimRight, rf_nextItem, rf_path%rf_indexPlus1%, 0
				rf_path%rf_index% = %rf_nextItem%
				rf_index++
			}
			break
		}
	}

	; Increment menu items one spot down in array, make room for new one at top
	rf_index = %rf_MenuItemCount%
	rf_start = %rf_MenuItemCount%
	rf_start--
	Loop, %rf_start%
	{
		rf_indexLess1 = %rf_index%
		rf_indexLess1--	
		StringTrimRight, rf_nextItem, rf_path%rf_indexLess1%, 0
		rf_path%rf_index% = %rf_nextItem%
		rf_index--
	}
	
	; Here's where we save the menu item to the menu array.
	rf_path1 = %rf_addRecentFolder%
	
	; Trying to delete menu that does not exist throws an error.
	if rf_menuExist <> 0
		Menu, rf_RecentFolders, Delete
	
	; Flag to stop an attemp at showing an empty menu
	rf_menuExist = 0
	
	rf_index = 0
	Loop, %rf_MenuItemCount%
	{	
		rf_index++
		StringTrimRight, rf_line, rf_path%rf_index%, 0
		if rf_line <>  ; Blank lines are not loaded.
		{
			Menu, rf_RecentFolders, Add, %rf_line%, rf_OpenRecentFolder
			rf_menuExist = 1
		}
	}
Return 


ExitSub:
	; Save menu items to rf_RecentFoldersFile on disk
	FileDelete, %rf_iniFile%
	rf_index = 0
	Loop, %rf_MenuItemCount%
	{
		rf_index++
		StringTrimRight, rf_line, rf_path%rf_index%, 0
		FileAppend, %rf_line%`n, %rf_iniFile%
	}
ExitApp

ChrisM

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Looks great; thanks for sharing it.

The program your keeping track of has to have the full path displayed in it's window title. Is there a way around this restriction?

The only things that come to mind are:
1) Search all disks for a matching filename (not practical).
2) Using a utility such as Handle from http://www.sysinternals.com to fetch a list of open files and try to find a match inside there. The problem with this is that most editors to not keep the file open while it is being edited, so the file would not appear in the list of open handles. However, you could instead search the list by application name (via "handle MyApplication"), find which directory is has open, and operate under the assumption that the file came from that directory (using IfExist to verify).