|
#Requires AutoHotkey v2.0.3+ |
|
|
|
; # Goto openened folders |
|
|
|
; A better "Recent Places" |
|
|
|
#HotIf ShouldDisplayMenu() |
|
~MButton::DisplayMenu() |
|
; Ctrl + G like Listary |
|
^g::DisplayMenu() |
|
#HotIf |
|
|
|
; "Namespaced" global variables |
|
global GTOF := { |
|
WinId : 0, ; Window ID under the mouse |
|
Class : "", ; Class under the mouse |
|
Menu : Menu() |
|
} |
|
|
|
ShouldDisplayMenu() { |
|
MouseGetPos( , , &WinIdUnderMouse) |
|
GTOF.WinId := WinIdUnderMouse |
|
GTOF.Class := WinGetClass("ahk_id " . WinIdUnderMouse) |
|
return GTOF.Class ~= "#32770|ExploreWClass|CabinetWClass|ConsoleWindowClass" |
|
} |
|
|
|
DestroyMenu() { |
|
DllCall("KillTimer", "Ptr", A_ScriptHwnd, "Ptr", id := 1) |
|
if not WinExist("ahk_id " GTOF.WinId) { |
|
GTOF.Menu.Delete() |
|
} |
|
} |
|
|
|
DisplayMenu() { |
|
; Fresh menu, width adapts to path length every time |
|
GTOF.Menu := Menu() |
|
FolderMenu := GTOF.Menu |
|
; Get current paths and build menu with them |
|
for window in ComObject("Shell.Application").Windows { |
|
; Exclude special locations |
|
; Computer, Recycle Bin, Search Results, Internet Explorer pages |
|
if InStr(window.FullName, "explorer.exe") && InStr(window.LocationURL, "file://") { |
|
MenuItemName := window.Document.Folder.Self.Path |
|
; Get paths of currently opened Explorer windows |
|
FolderMenu.Add(MenuItemName, NavigateToFolder.Bind(MenuItemName)) |
|
; Same default folder icon for all |
|
; Too difficult getting the actual icons, on the off chance they're not default |
|
FolderMenu.SetIcon(MenuItemName, A_WinDir "\system32\imageres.dll", 4) ; imageres.dll,4 = Folder icon |
|
} |
|
} |
|
; If no windows are open |
|
OpenedWindowsCount := DllCall("GetMenuItemCount", "ptr", FolderMenu.Handle) |
|
if not OpenedWindowsCount { |
|
FolderMenu.Add("No folders open...", (*) => {}) |
|
FolderMenu.Disable("No folders open...") |
|
} |
|
; Add User profile / $HOME directory entry |
|
FolderMenu.Add("Home", NavigateToFolder.Bind("%USERPROFILE%")) |
|
FolderMenu.SetIcon("Home", A_WinDir "\system32\imageres.dll", 118) ; imageress.dll,118 = User folder icon |
|
|
|
; Add Desktop entry at the end of the menu |
|
FolderMenu.Add("Desktop", NavigateToFolder.Bind(A_Desktop)) |
|
FolderMenu.SetIcon("Desktop", A_WinDir "\system32\imageres.dll", 106) ; imageress.dll,106 = Desktop icon |
|
|
|
; From a separate thread destroy the menu if the target Open with dialog is gone |
|
; See thread "Script execution is stopped when menu is open" |
|
; https://www.autohotkey.com/boards/viewtopic.php?style=17&p=478539 |
|
DllCall("SetTimer", "Ptr", A_ScriptHwnd, "Ptr", id := 1, "UInt", 1000, "Ptr", CallbackCreate(DestroyMenu, "Fast")) |
|
; Present the menu |
|
FolderMenu.Show() |
|
; Destroy the menu so it doesn't remember previously opened windows |
|
FolderMenu.Delete() |
|
} |
|
|
|
NavigateToFolder(ItemName, *) { |
|
; Fetch the array element that corresponds to the selected menu item: |
|
path := ItemName |
|
if path = "" |
|
return |
|
; Activate the window so that if the user is middle-clicking |
|
; outside the dialog, subsequent clicks will also work: |
|
WinActivate "ahk_id " GTOF.WinId |
|
; It's a dialog. |
|
if GTOF.Class = "#32770" { |
|
; Lexikos solution https://stackoverflow.com/a/25718181/5266640 |
|
; {F4} is slower because it drops down the menu of past paths |
|
SendInput "!{d}{Raw}" path "`n" |
|
return |
|
} |
|
; In Explorer, switch folders. |
|
else if GTOF.Class ~= "(Cabinet|Explore)WClass" { |
|
ControlClick "ToolbarWindow323", GTOF.WinId,,,, "NA x1 y1" |
|
ControlFocus "Edit1", GTOF.WinId |
|
ControlSetText path, "Edit1", GTOF.WinId |
|
; 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 "{Right}{Enter}", "Edit1", GTOF.WinId |
|
return |
|
} |
|
; In a console window, navigate to that directory |
|
else if GTOF.Class = "ConsoleWindowClass" { |
|
WinActivate GTOF.WinId ; Because sometimes the mclick deactivates it. |
|
SetKeyDelay 0 ; This will be in effect only for the duration of this thread. |
|
Send "pushd " path "{Enter}" |
|
return |
|
} |
|
; Since the above didn't return, one of the following is true: |
|
; 1) It's an unsupported window type but g_AlwaysShowMenu is true. |
|
Run "explorer " path ; Might work on more systems without double quotes. |
|
} |
@Gaxve
The code is simple enough for the standard Common Item Dialog. Unfortunately there are many exceptions: the old kind of dialog used by RegEdit for example, and of course custom dialogs used by various software suites (LibreOffice, Blender). These edge cases are difficult to address, especially while keeping the code simple. I haven't felt the burning need to do so, and it would take me a long time because I'm not a professional programmer.
I do use this script daily. Where it is supported it really helps. If you want to make heavy use of this functionality in a program where this doesn't work you could try the pro alternatives mentioned above, or just make do with "abusing" a clipboard manager to copy-paste paths (as long as there is an address bar).