#SingleInstance Force #Include options.ahk ;INIT MENU Menu, NavMenu, Add ;(RE)LOAD CONFIG Gosub, ReloadConfig ;INIT HOTKEY Hotkey, #n, DisplayNavMenu ;GENERATE ADDRESS CALLBACK k_address := RegisterCallback("ReloadConfigCallback") IniWrite, %k_address%, %k_config%, System, Address ;MONITOR CONFIG FileRead, k_monitor, %k_config% SetTimer, MonitorConfig, 1000 return MonitorConfig: FileRead, k_monitor_temp, %k_config% if (k_monitor_temp != k_monitor) { k_monitor := k_monitor_temp GoSub, ReloadConfig TrayTip, Navigator, Config Reloaded } return ReloadConfigCallback() { GoSub, ReloadConfig TrayTip, Navigator, Config Reloaded } ReloadConfig: Gosub, GenerateNavMenu Gosub, GenerateTrayMenu return GenerateTrayMenu: Menu, TRAY, DeleteAll Menu, TRAY, Tip, Navigator Menu, TRAY, NoStandard Menu, TRAY, Add, Navigator v%k_version%, Help Menu, TRAY, Default, Navigator v%k_version% Menu, TRAY, Add Menu, TRAY, Add, &Navigator, :NavMenu fn := Func("ExploreTo").Bind(k_config, true) Menu, SystemMenu, Add, Lock Menus, Lock If k_lock Menu, SystemMenu, Check, Lock Menus Menu, SystemMenu, Add, Edit Config, %fn% ;Menu, SystemMenu, Add, Reload Config, ReloadConfig Menu, SystemMenu, Add, Close, Close Menu, TRAY, Add, &System, :SystemMenu return Lock: If k_lock { k_lock := false } else { k_lock := true } Menu, SystemMenu, ToggleCheck, Lock Menus GoSub, GenerateNavMenu return GenerateNavMenu: Gui, Menu Menu, NavMenu, DeleteAll CreateMenu("NavMenu") return CreateMenu(menu_name) { global k_config, k_lock, k_ext_pattern IniRead, k_nav_config, %k_config%, %menu_name% If (k_nav_config == "") { MsgBox,, %menu_name%, No paths found for this sub-menu, please add some to the config. } StringSplit, k_nav, k_nav_config, `n Loop, %k_nav0% { StringSplit, k_nav_array, k_nav%A_Index%, `, If (k_nav_array0 > 1) { ; We have a path to work with fn := Func("ExploreTo").Bind(k_nav_array2) k_pos := RegExMatch(k_nav_array2, k_ext_pattern) If (k_pos > 0) { Menu, %menu_name%, Add, %k_nav_array1%, %fn%, +Radio Menu, %menu_name%, Check, %k_nav_array1% } else { Menu, %menu_name%, Add, %k_nav_array1%, %fn% } } else { ; No path, so this is a new menu Menu, %k_nav_array1%, Add Menu, %k_nav_array1%, DeleteAll k_menu_name := k_nav_array1 k_menu_ini := k_nav_array1 StringSplit, k_menu_array, k_menu_name, | If (k_menu_array0 > 1) { k_menu_name := k_menu_array2 k_menu_ini := k_menu_array1 } CreateMenu(k_menu_ini) Menu, %menu_name%, Add, %k_menu_name%, :%k_menu_ini% } } If not k_lock { Menu, %menu_name%, Add fn := Func("AddMenuItem").Bind(menu_name) Menu, %menu_name%, Add, Add, %fn% } } DisplayNavMenu: WinGet, k_window_id, ID, A WinGetClass, k_class, ahk_id %k_window_id% ControlGetFocus, k_control, ahk_id %k_window_id% if k_class in ExploreWClass,CabinetWClass { ; Try to activate the edit, this sometimes fixes weird issues SendInput, {AltDown}d{AltUp}{Esc} ControlGetPos, k_Edit1Pos,,,, Edit1, ahk_id %k_window_id% } else if k_class in #32770 { ControlGetPos, k_Edit2Pos,,,, Edit2, ahk_id %k_window_id% } if k_class in #32770,ExploreWClass,CabinetWClass ; Dialog or Explorer. { if k_Edit1Pos = ; The control doesn't exist { WinActivate, ahk_id %k_window_id% if k_class in ExploreWClass,CabinetWClass ControlGetPos, k_Edit1Pos,,,, Edit1, ahk_id %k_window_id% else if k_class in #32770 ControlGetPos, k_Edit2Pos,,,, Edit2, ahk_id %k_window_id% } } Menu, NavMenu, Show return AddMenuItem(menu_name) { global InputBox, k_label, Navigator, %menu_name%`nPlease enter the name of the new menu item InputBox, k_path, Navigator, %menu_name%`nPlease enter the path to the new menu item`nIf this is a new sub-menu`, leave this blank If (k_path == "") IniWrite, %k_label%, %k_config%, %menu_name% Else IniWrite, %k_label%`,%k_path%, %k_config%, %menu_name% GoSub, ReloadConfig } ExploreTo(location) { global RegExMatch(location, k_branch_pattern, k_match) if k_match <> { InputBox, k_replacement, Navigator, %k_match2% if k_replacement <> { location := StrReplace(location, k_match1, k_replacement) } else { return } } if k_class = #32770 ; It's a dialog. { if k_Edit2Pos <> ; And it has an Edit2 control. { ; Activate the window so that if the user is middle-clicking ; outside the dialog, subsequent clicks will also work: WinActivate ahk_id %k_window_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, k_text, Edit1, ahk_id %k_window_id% ControlSetText, Edit2, %location%, ahk_id %k_window_id% ControlSend, Edit2, {Enter}, ahk_id %k_window_id% Sleep, 100 ; It needs extra time on some dialogs or in some cases. ControlSetText, Edit1, %k_text%, ahk_id %k_window_id% GoSub, Cleanup return } ; else fall through to the bottom of the subroutine to take standard action. } else if k_class in ExploreWClass,CabinetWClass ; In Explorer, switch folders. { if k_Edit1Pos <> ; And it has an Edit1 control. { ControlSetText, Edit1, %location%, ahk_id %k_window_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 %k_window_id% GoSub, Cleanup return } ; else fall through to the bottom of the subroutine to take standard action. } else if k_class in ConsoleWindowClass,TMobaXTermForm,mintty ; In a console window, CD to that directory { WinActivate, ahk_id %k_window_id% ; Because sometimes the mclick deactivates it. SetKeyDelay, 0 ; This will be in effect only for the duration of this thread. IfInString, k_path, : ; It contains a drive letter { StringLeft, k_path_drive, location, 1 Send %k_path_drive%:{enter} } Send, cd "%location%"{Enter} GoSub, Cleanup return } else if InStr(k_control, "Edit") == 1 ; If Navigator is called from an edit control, modify it { ControlSetText, %k_control%, %location%, ahk_id %k_window_id% ControlSend, %k_control%, {Right}{Enter}, ahk_id %k_window_id% GoSub, Cleanup return } GoSub, Cleanup Run, Explorer %location% } Cleanup: k_window_id= k_class= k_control= return Help: RegRead, k_reg, HKCR, Directory\shell\Navigator_Add k_reg_help= if k_reg <> { k_reg_help = `n`nRegistry Extension:`n- New context menu options to add a file/folder to Navigator`n- New context menu options to copy a file/folder's path to the clipboard } MsgBox, 32, Navigator, Navigator v%k_version%`nThis program was created to aid in quickly navigating to common directories/files.`n`nFeatures:`n- Infinite sub-menus`; Organize your navigations as much as you want.`n- Simple naming`; To rename a folder, simple add a pipe (|) followed by the preferred name`n- Window detection`; In File Explorer`, switch to the directory. In command prompt`, cd to the directory. `n- Hotkey support`; Press the windows key + N to bring up the navigator menu.`n- If the path is a file instead of a directory, Navigator will open the file.*`n`n* File paths will be denoted by a radio mark next to their entry.%k_reg_help% return ;This is the only way to actually close the application Close: MsgBox, 52, Navigator, Are you sure you want to close the Navigator? IfMsgBox, YES ExitApp return