-
-
Save nod5/73d7ea232ede7ab6762833d5442fef5d to your computer and use it in GitHub Desktop.
First attempt at hotkey tool to quickly change path in file dialogue windows (Save As, Open, ...) to that of existing Explorer windows
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#NoEnv | |
SendMode Input | |
SetWorkingDir %A_ScriptDir% | |
#SingleInstance force | |
ListLines, Off | |
SetBatchLines, -1 | |
SetWinDelay, -1 | |
SetControlDelay, -1 | |
; string anywhere in title | |
SetTitleMatchMode, 2 | |
; SaveAsPathHelper.ahk | |
; by nod5 | |
; 2020-03-10 | |
; ------------------------------------------------- | |
; Ctrl+G in a standard file dialogue window ("Save As", "Save File", "Open"): | |
; Cycle save path to that of existing Explorer window paths | |
; ------------------------------------------------- | |
; Ctrl+G in File Explorer: | |
; update most recent file dialogue window with Explorer path | |
; ------------------------------------------------- | |
; Ctrl+O in File Explorer: | |
; update most recent "Open" file dialogue window with | |
; folder path and filename to first selected file in Explorer | |
; ------------------------------------------------- | |
; Alt+Tab from file dialogue window to Explorer window and back within 5 seconds: | |
; update file dialogue window with Explorer path | |
; ------------------------------------------------- | |
; note: add/remove window title strings in the window group as needed | |
; See https://www.autohotkey.com/docs/commands/GroupAdd.htm | |
; note: change vOpenWindow if needed in non-english locale | |
; ------------------------------------------------- | |
GroupAdd, vSaveAsWindow, Save File ahk_class #32770 | |
GroupAdd, vSaveAsWindow, Save As ahk_class #32770 | |
GroupAdd, vSaveAsWindow, Save ahk_class #32770 | |
GroupAdd, vSaveAsWindow, Open ahk_class #32770 | |
vOpenWindow := "Open" | |
Hotkey, IfWinActive, ahk_group vSaveAsWindow | |
Hotkey, ^g, cycle_existing_explorer_win_paths, On | |
Hotkey, ~!Tab, file_dialogue_alt_tab, On | |
Hotkey, IfWinActive, ahk_class CabinetWClass | |
Hotkey, ^g, active_explorer_path_to_file_dialogue, On | |
Hotkey, ^o, first_selected_explorer_file_to_open_file_dialogue, On | |
Hotkey, IfWinActive | |
Return | |
;Esc:: ExitApp | |
; ------------------------------------------------- | |
; Notes on Interacting with File Dialogue Windows in Win 10 | |
; ------------------------------------------------- | |
; File Dialogue windows have tricky path controls | |
; | |
; When not yet clicked/edited the control is | |
; ToolbarWindow324 (save) or ToolbarWindow323 (open) | |
; that control has clickable path crumbs: (C:\) > Windows > System32 | |
; When clicked/edited the control becomes Edit2 | |
; that control is a regular text edit control | |
; We can always read path from ToolbarWindow324 (or ToolbarWindow323) | |
; - ControlGetText, vPath, ToolbarWindow324, A | |
; -> "Adress: C:\some folder" | |
; We can never set path to ToolbarWindow324 (or ToolbarWindow323) | |
; - no effect: ControlSetText, ToolbarWindow324, C:\, A | |
; - no effect: ControlSetText, ToolbarWindow324, Adress: C:\, A | |
; We can read/write Edit2 *if* control was clicked/activated once since window creation | |
; - do one of: | |
; ControlClick, ToolbarWindow324, A (better, since no blue selection flicker) | |
; Send ^l | |
; - after that this works: | |
; ControlSetText, Edit2, C:\new path\somewhere, A | |
; ControlSend, Edit2, {Enter}, A | |
; ------------------------------------------------- | |
cycle_existing_explorer_win_paths: | |
; get current path, example: "Address: C:\some folder" | |
vControlName := WinActive(vOpenWindow) ? "ToolbarWindow323" : "ToolbarWindow324" | |
ControlGetText, vPath, % vControlName, A | |
; remove prefix "Address: " | |
If (SubStr(vPath, 1, 9) = "Address: ") | |
vPath := SubStr(vPath, 10) | |
; get paths for all open File Explorer windows | |
aArray := ExplorerWindowsPaths() | |
; get last used used path | |
vIndex := 1 | |
For Key, Val in aArray | |
{ | |
If (Val != vPath) or !InStr(FileExist(vPath), "D") | |
continue | |
vIndex := A_Index | |
break | |
} | |
; cycle to the next path (wraps around) | |
vNewIndex := vIndex + 1 > aArray.Length() ? 1 : vIndex + 1 | |
vNewPath := aArray[vNewIndex] | |
If InStr(FileExist(vNewPath), "D") | |
SetSaveAsPath(vNewPath, vOpenWindow) | |
Return | |
active_explorer_path_to_file_dialogue: | |
vNewPath := ActiveExplorerPath() | |
; activate most recently used file dialogue window and set new path | |
WinActivate, ahk_group vSaveAsWindow | |
If WinActive("ahk_group vSaveAsWindow") | |
SetSaveAsPath(vNewPath, vOpenWindow) | |
Return | |
first_selected_explorer_file_to_open_file_dialogue: | |
vFileSelected := ExplorerGetFirstSelectedFilepath() | |
if !FileExist(vFileSelected) | |
Return | |
; activate most recently used file dialogue window and set new path | |
WinActivate, ahk_group vSaveAsWindow | |
If WinActive(vOpenWindow " ahk_group vSaveAsWindow") | |
{ | |
SplitPath, vFileSelected, vFileName, vFolder | |
SetSaveAsPath(vFolder, vOpenWindow) | |
ControlSetText, Edit1, % vFileName, A | |
} | |
Return | |
file_dialogue_alt_tab: | |
vThisFileDialogue := WinExist("A") | |
t := A_TickCount | |
vAltTabPath := "" | |
SetTimer, alt_tab_timer, 50 | |
sleep 5 | |
Return | |
alt_tab_timer: | |
If (A_TickCount > t + 5000) or !WinExist("ahk_id " vThisFileDialogue) | |
SetTimer, alt_tab_timer, off | |
Else If WinActive("ahk_class CabinetWClass") | |
vAltTabPath := ActiveExplorerPath() | |
Else If vAltTabPath and WinActive("ahk_id " vThisFileDialogue) | |
{ | |
SetTimer, alt_tab_timer, off | |
SetSaveAsPath(vAltTabPath, vOpenWindow) | |
} | |
Return | |
; function: set new path in active Save As window and focus filename input control | |
SetSaveAsPath(vNewPath, vOpenWindow := "Open") { | |
; string anywhere in title | |
SetTitleMatchMode, 2 | |
vControlName := WinActive(vOpenWindow) ? "ToolbarWindow323" : "ToolbarWindow324" | |
; note: We can read/write Edit2 *if* prior clicked/edited once since window creation | |
ControlGetText, vEdit2Text, Edit2, A | |
if !vEdit2Text | |
{ | |
; Click control ToolbarWindow323/324 to activate Edit2 | |
; note: "NA may improve reliability" | |
; note: click x0 y0 (control top left) because default click in control center | |
; and that fails if ">" path divider there | |
; https://www.autohotkey.com/docs/commands/ControlClick.htm | |
ControlClick, % vControlName, A, , , , NA x0 y0 | |
; small sleep required | |
sleep 5 | |
} | |
ControlGetText, vEdit2Text, Edit2, A | |
if !vEdit2Text | |
Return | |
ControlFocus, % vControlName, A | |
sleep 5 | |
; set new path | |
ControlSetText, Edit2, % vNewPath, A | |
ControlSend, Edit2, {Enter}, A | |
ControlFocus, Edit1, A | |
sleep 5 | |
} | |
; function: return array with folder paths to all existing Explorer windows | |
; ref https://docs.microsoft.com/en-us/windows/win32/shell/folderitem-path | |
ExplorerWindowsPaths() { | |
aExplorerPaths := [] | |
for window in ComObjCreate("Shell.Application").Windows | |
{ | |
path := window.Document.Folder.Self.Path | |
; skip if start with "::" (for example Control Panel window) | |
if (SubStr(path, 1, 2) != "::") | |
aExplorerPaths.Push(path) | |
} | |
Return aExplorerPaths | |
} | |
; function: get active window Explorer folder path | |
; based on https://www.autohotkey.com/boards/viewtopic.php?p=301644 | |
; ref https://docs.microsoft.com/en-us/windows/win32/shell/folderitem-path | |
ActiveExplorerPath() { | |
explorerHwnd := WinActive("ahk_class CabinetWClass") | |
if (explorerHwnd) | |
for window in ComObjCreate("Shell.Application").Windows | |
if (window.hwnd == explorerHwnd) | |
{ | |
path := window.Document.Folder.Self.Path | |
;if start with "::" (for example Control Panel window) then return nothing | |
return SubStr(path, 1, 2) = "::" ? "" : path | |
} | |
} | |
; function: ExplorerGetFirstSelectedFilepath(win_id := "") | |
; return file path of first selected file in win_id (or active) Explorer window | |
; note: gets items in alphanum ascending sort order | |
ExplorerGetFirstSelectedFilepath(win_id := "") { | |
win_id := win_id ? win_id : WinActive("A") | |
if !WinExist("ahk_class CabinetWClass ahk_id " win_id) | |
return | |
for window in ComObjCreate("Shell.Application").Windows | |
{ | |
if (window.HWND != win_id ) | |
continue | |
sfv := window.Document | |
; note: gets items in alphanum ascending sort order | |
; ref https://docs.microsoft.com/en-us/windows/desktop/shell/shellfolderview-selecteditems | |
items := sfv.SelectedItems | |
for item in items | |
{ | |
file := item.Path | |
break | |
} | |
item := "" | |
items := "" | |
sfv := "" | |
break | |
} | |
window := "" | |
return file | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment