├── Extra └── DiagnoseDialog.exe ├── QuickSwitch.ahk └── README.md /Extra/DiagnoseDialog.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gepruts/QuickSwitch/fd8212e28ed04b90cab1ff5f94fa7264b16a0260/Extra/DiagnoseDialog.exe -------------------------------------------------------------------------------- /QuickSwitch.ahk: -------------------------------------------------------------------------------- 1 | $ThisVersion := "0.5" 2 | 3 | ;@Ahk2Exe-SetVersion 0.5 4 | ;@Ahk2Exe-SetName QuickSwitch 5 | ;@Ahk2Exe-SetDescription Use opened file manager folders in File dialogs. 6 | ;@Ahk2Exe-SetCopyright NotNull 7 | 8 | /* 9 | By : NotNull 10 | Info : https://www.voidtools.com/forum/viewtopic.php?f=2&t=9881 11 | */ 12 | 13 | ;_____________________________________________________________________________ 14 | ; 15 | ; SETTINGS 16 | ;_____________________________________________________________________________ 17 | ; 18 | 19 | #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. 20 | ; #Warn ; Enable warnings to assist with detecting common errors. 21 | SendMode Input ; Recommended for new scripts due to its superior speed and reliability. 22 | SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. 23 | #singleinstance force 24 | 25 | 26 | ; Total Commander internal codes 27 | global cm_CopySrcPathToClip := 2029 28 | global cm_CopyTrgPathToClip := 2030 29 | 30 | global $DEBUG := 0 31 | 32 | 33 | FunctionShowMenu := Func("ShowMenu") 34 | Hotkey, ^Q, %FunctionShowMenu%, Off 35 | 36 | 37 | 38 | 39 | ; INI file ( .INI) 40 | SplitPath, A_ScriptFullPath,,,, name_no_ext 41 | $INI := name_no_ext . ".ini" 42 | name_no_ext := "" 43 | 44 | 45 | ; Path to tempfilefor Directory Opus 46 | EnvGet, _tempfolder, TEMP 47 | _tempfile := _tempfolder . "\dopusinfo.xml" 48 | FileDelete, %_tempfile% 49 | 50 | 51 | 52 | ;_____________________________________________________________________________ 53 | ; 54 | ; ACTION! 55 | ;_____________________________________________________________________________ 56 | ; 57 | 58 | ; Check if Win7 or higher; if not: exit 59 | 60 | ; If !(RegExMatch(A_OSVersion, "^10\.")) 61 | ;WIN_7,WIN_8,WIN_8.1,WIN_VISTA,WIN_2003,WIN_XP,WIN_2000 62 | 63 | If A_OSVersion in WIN_VISTA,WIN_2003,WIN_XP,WIN_2000 64 | { 65 | MsgBox %A_OSVersion% is not supported. 66 | ExitApp 67 | } 68 | 69 | 70 | 71 | loop 72 | { 73 | 74 | WinWaitActive, ahk_class #32770 75 | 76 | ;_____________________________________________________________________________ 77 | ; 78 | ; DIALOG ACTIVE 79 | ;_____________________________________________________________________________ 80 | ; 81 | 82 | 83 | ; Get ID of dialog box 84 | $WinID := WinExist("A") 85 | 86 | $DialogType := SmellsLikeAFileDialog($WinID) 87 | 88 | If $DialogType ; This is a supported dialog 89 | { 90 | 91 | ; Get Windows title and process.exe of this dialog 92 | WinGet, $ahk_exe, ProcessName, ahk_id %$WinID% 93 | WinGetTitle, $window_title , ahk_id %$WinID% 94 | 95 | $FingerPrint := $ahk_exe . "___" . $window_title 96 | 97 | 98 | ; Check if FingerPrint entry is already in INI, so we know what to do. 99 | IniRead, $DialogAction, %$INI%, Dialogs, %$FingerPrint% 100 | 101 | 102 | If ($DialogAction = 1 ) ; ======= AutoSwitch == 103 | { 104 | $FolderPath := Get_Zfolder($WinID) 105 | 106 | If ( ValidFolder( $FolderPath )) 107 | { 108 | ; FeedDialog($WinID, $FolderPath) 109 | FeedDialog%$DialogType%($WinID, $FolderPath) 110 | } 111 | } 112 | Else If ($DialogAction = 0 ) ; ======= Never here == 113 | { 114 | ; Do nothing 115 | } 116 | Else ; ======= Show Menu == 117 | { 118 | ShowMenu() 119 | } 120 | 121 | 122 | 123 | ; If we end up here, we checked the INI for what to do in this supported dialog and did it 124 | ; We are still in this dialog and can now enable the hotkey for manual menu-activation 125 | ; Activate the CTR-Q hotkey. When pressed, start the ShowMenu routine 126 | 127 | 128 | Hotkey, ^Q, On 129 | } ; End of File Dialog routine 130 | Else ; This is a NOT supported dialog 131 | { 132 | ; Do nothing; Not a supported dialogtype 133 | } 134 | 135 | sleep, 100 136 | 137 | 138 | 139 | 140 | 141 | 142 | WinWaitNotActive 143 | 144 | ;_____________________________________________________________________________ 145 | ; 146 | ; DIALOG NOT ACTIVE 147 | ;_____________________________________________________________________________ 148 | ; 149 | 150 | Hotkey, ^Q, Off 151 | 152 | 153 | ; Clean up 154 | $WinID := "" 155 | $ahk_exe := "" 156 | $window_title := "" 157 | $ahk_exe := "" 158 | $DialogAction := "" 159 | $DialogType := "" 160 | $FolderPath := "" 161 | $DialogType := "" 162 | 163 | 164 | 165 | ;_____________________________________________________________________________ 166 | ; 167 | } ; End of continuous WinWaitActive / WinWaitNotActive loop 168 | ;_____________________________________________________________________________ 169 | 170 | 171 | 172 | 173 | MsgBox We never get here (and that's how it should be) 174 | ExitApp 175 | 176 | 177 | 178 | 179 | 180 | 181 | ;============================================================================= 182 | ;============================================================================= 183 | ;============================================================================= 184 | ; 185 | ; SUBROUTINES AND FUNCTIONS 186 | ; 187 | ;============================================================================= 188 | ;============================================================================= 189 | ;============================================================================= 190 | 191 | 192 | 193 | ;_____________________________________________________________________________ 194 | ; 195 | SmellsLikeAFileDialog(_thisID ) 196 | ;_____________________________________________________________________________ 197 | ; 198 | { 199 | 200 | ; Only consider this dialog a possible file-dialog when: 201 | ; (SysListView321 AND ToolbarWindow321) OR (DirectUIHWND1 AND ToolbarWindow321) controls detected 202 | ; First is for Notepad++; second for all other filedialogs 203 | ; That is our rough detection of a File dialog. Returns 1 or 0 (TRUE/FALSE) 204 | 205 | WinGet, _controlList, ControlList, ahk_id %_thisID% 206 | 207 | Loop, Parse, _controlList, `n 208 | { 209 | If ( A_LoopField = "SysListView321" ) 210 | _SysListView321 := 1 211 | 212 | If ( A_LoopField = "ToolbarWindow321") 213 | _ToolbarWindow321 := 1 214 | 215 | If ( A_LoopField = "DirectUIHWND1" ) 216 | _DirectUIHWND1 := 1 217 | 218 | If ( A_LoopField = "Edit1" ) 219 | _Edit1 := 1 220 | } 221 | 222 | 223 | If ( _DirectUIHWND1 and _ToolbarWindow321 and _Edit1 ) 224 | { 225 | Return "GENERAL" 226 | 227 | } 228 | Else If ( _SysListView321 and _ToolbarWindow321 and _Edit1 ) 229 | { 230 | Return "SYSLISTVIEW" 231 | } 232 | else 233 | { 234 | Return FALSE 235 | } 236 | 237 | } 238 | 239 | 240 | ;_____________________________________________________________________________ 241 | ; 242 | FeedDialogGENERAL( _thisID, _thisFOLDER ) 243 | ;_____________________________________________________________________________ 244 | ; 245 | { 246 | Global $DialogType 247 | 248 | WinActivate, ahk_id %_thisID% 249 | 250 | sleep 50 251 | 252 | ; Focus Edit1 253 | ControlFocus Edit1, ahk_id %_thisID% 254 | 255 | WinGet, ActivecontrolList, ControlList, ahk_id %_thisID% 256 | 257 | 258 | Loop, Parse, ActivecontrolList, `n ; which addressbar and "Enter" controls to use 259 | { 260 | If InStr(A_LoopField, "ToolbarWindow32") 261 | { 262 | ; ControlGetText _thisToolbarText , %A_LoopField%, ahk_id %_thisID% 263 | ControlGet, _ctrlHandle, Hwnd,, %A_LoopField%, ahk_id %_thisID% 264 | 265 | ; Get handle of parent control 266 | _parentHandle := DllCall("GetParent", "Ptr", _ctrlHandle) 267 | 268 | ; Get class of parent control 269 | WinGetClass, _parentClass, ahk_id %_parentHandle% 270 | 271 | If InStr( _parentClass, "Breadcrumb Parent" ) 272 | { 273 | _UseToolbar := A_LoopField 274 | } 275 | 276 | If Instr( _parentClass, "msctls_progress32" ) 277 | { 278 | _EnterToolbar := A_LoopField 279 | } 280 | } 281 | 282 | ; Start next round clean 283 | _ctrlHandle := "" 284 | _parentHandle := "" 285 | _parentClass := "" 286 | 287 | } 288 | 289 | If ( _UseToolbar AND _EnterToolbar ) 290 | { 291 | Loop, 5 292 | { 293 | SendInput ^l 294 | sleep 100 295 | 296 | ; Check and insert folder 297 | ControlGetFocus, _ctrlFocus,A 298 | 299 | If ( InStr( _ctrlFocus, "Edit" ) AND ( _ctrlFocus != "Edit1" ) ) 300 | { 301 | Control, EditPaste, %_thisFOLDER%, %_ctrlFocus%, A 302 | ControlGetText, _editAddress, %_ctrlFocus%, ahk_id %_thisID% 303 | If (_editAddress = _thisFOLDER ) 304 | { 305 | _FolderSet := TRUE 306 | } 307 | } 308 | ; else: Try it in the next round 309 | 310 | ; Start next round clean 311 | _ctrlFocus := "" 312 | _editAddress := "" 313 | 314 | } Until _FolderSet 315 | 316 | 317 | 318 | If (_FolderSet) 319 | { 320 | ; Click control to "execute" new folder 321 | ControlClick, %_EnterToolbar%, ahk_id %_thisID% 322 | 323 | ; Focus file name 324 | Sleep, 15 325 | ControlFocus Edit1, ahk_id %_thisID% 326 | } 327 | Else 328 | { 329 | ; What to do if folder is not set? 330 | } 331 | } 332 | Else ; unsupported dialog. At least one of the needed controls is missing 333 | { 334 | MsgBox This type of dialog can not be handled (yet).`nPlease report it! 335 | } 336 | 337 | 338 | ; Clean up; probably not needed 339 | 340 | _UseToolbar := "" 341 | _EnterToolbar := "" 342 | _editAddress := "" 343 | _FolderSet := "" 344 | _ctrlFocus := "" 345 | 346 | 347 | Return 348 | } 349 | 350 | 351 | 352 | 353 | ;_____________________________________________________________________________ 354 | ; 355 | FeedDialogSYSLISTVIEW( _thisID, _thisFOLDER ) 356 | ;_____________________________________________________________________________ 357 | ; 358 | { 359 | Global $DialogType 360 | 361 | WinActivate, ahk_id %_thisID% 362 | ; Sleep, 50 363 | 364 | 365 | ; Read the current text in the "File Name:" box (= $OldText) 366 | 367 | ControlGetText _oldText, Edit1, ahk_id %_thisID% 368 | Sleep, 20 369 | 370 | 371 | ; Make sure there exactly 1 \ at the end. 372 | 373 | _thisFOLDER := RTrim( _thisFOLDER , "\") 374 | _thisFOLDER := _thisFOLDER . "\" 375 | 376 | Loop, 20 377 | { 378 | Sleep, 10 379 | ControlSetText, Edit1, %_thisFOLDER%, ahk_id %_thisID% 380 | ControlGetText, _Edit1, Edit1, ahk_id %_thisID% 381 | If ( _Edit1 = _thisFOLDER ) 382 | _FolderSet := TRUE 383 | 384 | } Until _FolderSet 385 | 386 | If _FolderSet 387 | { 388 | Sleep, 20 389 | ControlFocus Edit1, ahk_id %_thisID% 390 | ControlSend Edit1, {Enter}, ahk_id %_thisID% 391 | 392 | 393 | 394 | ; Restore original filename / make empty in case of previous folder 395 | 396 | Sleep, 15 397 | 398 | ControlFocus Edit1, ahk_id %_thisID% 399 | Sleep, 20 400 | 401 | Loop, 5 402 | { 403 | ControlSetText, Edit1, %_oldText%, ahk_id %_thisID% ; set 404 | Sleep, 15 405 | ControlGetText, _2thisCONTROLTEXT, Edit1, ahk_id %_thisID% ; check 406 | If ( _2thisCONTROLTEXT = _oldText ) 407 | Break 408 | } 409 | } 410 | Return 411 | } 412 | 413 | 414 | 415 | 416 | 417 | ;_____________________________________________________________________________ 418 | ; 419 | ShowMenu() 420 | ;_____________________________________________________________________________ 421 | ; 422 | { 423 | 424 | Global $DialogType 425 | Global $DialogAction 426 | Global _tempfile 427 | 428 | _showMenu := 0 429 | 430 | ; ---------------[ Title BAr ]-------------------------------------- 431 | Menu ContextMenu, Add, QuickSwitch Menu, Dummy 432 | Menu ContextMenu, Default, QuickSwitch Menu 433 | Menu ContextMenu, disable, QuickSwitch Menu 434 | 435 | 436 | 437 | WinGet, _allWindows, list 438 | Loop, %_allWindows% 439 | { 440 | _thisID := _allWindows%A_Index% 441 | WinGetClass, _thisClass, ahk_id %_thisID% 442 | 443 | ;---------------[ Total Commander Folders]-------------------------------------- 444 | 445 | If ( _thisClass = "TTOTAL_CMD") 446 | { 447 | ; Get Process information for TC icon 448 | WinGet, _thisPID, PID, ahk_id %_thisID% 449 | _TC_exe := GetModuleFileNameEx( _thisPID ) 450 | 451 | ClipSaved := ClipboardAll 452 | Clipboard := "" 453 | 454 | SendMessage 1075, %cm_CopySrcPathToClip%, 0, , ahk_id %_thisID% 455 | 456 | ; Check if valid folder first. Only add it if it is. 457 | If (ErrorLevel = 0) AND ( ValidFolder( clipboard ) ) 458 | { 459 | Menu ContextMenu, Add, %clipboard%, FolderChoice 460 | Menu ContextMenu, Icon, %clipboard%, %_TC_exe%,0, 32 461 | _showMenu := 1 462 | 463 | } 464 | 465 | SendMessage 1075, %cm_CopyTrgPathToClip%, 0, , ahk_id %_thisID% 466 | 467 | If (ErrorLevel = 0) AND ( ValidFolder( clipboard ) ) 468 | { 469 | Menu ContextMenu, Add, %clipboard%, FolderChoice 470 | Menu ContextMenu, Icon, %clipboard%, %_TC_exe%,0,32 471 | _showMenu := 1 472 | } 473 | 474 | 475 | Clipboard := ClipSaved 476 | ClipSaved := "" 477 | } 478 | 479 | 480 | ;---------------[ XYPlorer ]-------------------------------------- 481 | 482 | If ( _thisClass = "ThunderRT6FormDC") 483 | { 484 | ; Get Process information for TC icon 485 | WinGet, _thisPID, PID, ahk_id %_thisID% 486 | _XYPlorer_exe := GetModuleFileNameEx( _thisPID ) 487 | 488 | ClipSaved := ClipboardAll 489 | Clipboard := "" 490 | 491 | Send_XYPlorer_Message(_thisID, "::copytext get('path', a);") 492 | 493 | ; Check if valid folder first. Only add it if it is. 494 | If (ErrorLevel = 0) AND ( ValidFolder( clipboard )) 495 | { 496 | Menu ContextMenu, Add, %clipboard%, FolderChoice 497 | Menu ContextMenu, Icon, %clipboard%, %_XYPlorer_exe%,0, 32 498 | _showMenu := 1 499 | } 500 | 501 | Send_XYPlorer_Message(_thisID, "::copytext get('path', i);") 502 | 503 | If (ErrorLevel = 0) AND ( ValidFolder( clipboard )) 504 | { 505 | Menu ContextMenu, Add, %clipboard%, FolderChoice 506 | Menu ContextMenu, Icon, %clipboard%, %_XYPlorer_exe%,0,32 507 | _showMenu := 1 508 | } 509 | 510 | 511 | Clipboard := ClipSaved 512 | ClipSaved := "" 513 | } 514 | 515 | ;---------------[ Directory Opus ]-------------------------------------- 516 | 517 | If ( _thisClass = "dopus.lister") 518 | { 519 | ; Get Process information for Opus icon 520 | WinGet, _thisPID, PID, ahk_id %_thisID% 521 | _dopus_exe := GetModuleFileNameEx( _thisPID ) 522 | 523 | 524 | If !(OpusInfo) 525 | { 526 | ; Comma needs escaping: `, 527 | Run, "%_dopus_exe%\..\dopusrt.exe" /info "%_tempfile%"`,paths,,, $DUMMY 528 | 529 | Sleep, 100 530 | FileRead, OpusInfo, %_tempfile% 531 | 532 | Sleep, 20 533 | FileDelete, %_tempfile% 534 | 535 | 536 | } 537 | 538 | 539 | ; Get active path of this lister (regex instead of XML library) 540 | RegExMatch(OpusInfo, "mO)^.*lister=\""" . _thisID . "\"".*tab_state=\""1\"".*\>(.*)\<\/path\>$", out) 541 | _thisFolder := out.Value(1) 542 | 543 | ; Check if valid folder first. Only add it if it is. 544 | If ValidFolder( _thisFolder ) 545 | { 546 | Menu ContextMenu, Add, %_thisFolder%, FolderChoice 547 | Menu ContextMenu, Icon, %_thisFolder%, %_dopus_exe%,0, 32 548 | _showMenu := 1 549 | } 550 | _thisFolder := "" 551 | 552 | 553 | ; Get passive path of this lister 554 | RegExMatch(OpusInfo, "mO)^.*lister=\""" . _thisID . "\"".*tab_state=\""2\"".*\>(.*)\<\/path\>$", out) 555 | _thisFolder := out.Value(1) 556 | 557 | ; Check if valid folder first. Only add it if it is. 558 | If ValidFolder( _thisFolder ) 559 | { 560 | Menu ContextMenu, Add, %_thisFolder%, FolderChoice 561 | Menu ContextMenu, Icon, %_thisFolder%, %_dopus_exe%,0, 32 562 | _showMenu := 1 563 | } 564 | _thisFolder := "" 565 | 566 | } 567 | 568 | ;---------------[ File Explorer Folders ]---------------------------------------- 569 | 570 | 571 | If ( _thisClass = "CabinetWClass") 572 | { 573 | For _Exp in ComObjCreate("Shell.Application").Windows 574 | { 575 | try ; Attempts to execute code. 576 | { 577 | _checkID := _Exp.hwnd 578 | } 579 | catch e ; Handles the errors that Opus will generate. 580 | { 581 | ; Do nothing. Just ignore error. 582 | ; Proceed to the next Explorer instance 583 | } 584 | 585 | If ( _thisID = _checkID ) 586 | { 587 | _thisExplorerPath := _Exp.Document.Folder.Self.Path 588 | 589 | ; Check if valid folder first. Don't add it if not. 590 | If ( ValidFolder(_thisExplorerPath)) 591 | { 592 | Menu ContextMenu, Add, %_thisExplorerPath%, FolderChoice 593 | Menu ContextMenu, Icon, %_thisExplorerPath%, shell32.dll, 5,32 594 | _showMenu := 1 595 | } 596 | } 597 | _checkID := "" 598 | } 599 | } 600 | } ; end loop parsing all windows to find file manager folders 601 | 602 | ; All windows have been checked for valid File Manager folders 603 | ; Most recent used filemanager will be shown on top. 604 | ; If no folders found to be shown: no need to show menu ... 605 | 606 | 607 | If ( _showMenu = 1 ) 608 | { 609 | 610 | 611 | ;---------------[ Settings ]---------------------------------------- 612 | 613 | Menu ContextMenu, Add, 614 | Menu ContextMenu, Add, Settings for this dialog, Dummy 615 | Menu ContextMenu, disable, Settings for this dialog 616 | 617 | Menu ContextMenu, Add, Allow AutoSwitch, AutoSwitch, Radio 618 | Menu ContextMenu, Add, Never here, Never, Radio 619 | Menu ContextMenu, Add, Not now, ThisMenu, Radio 620 | 621 | 622 | ; Activate radiobutton for current setting (depends on INI setting) 623 | ; Only show AutoSwitchException if AutoSwitch is activated. 624 | 625 | If ($DialogAction = 1) 626 | { 627 | Menu ContextMenu, Check, Allow AutoSwitch 628 | Menu ContextMenu, Add, AutoSwitch exception, AutoSwitchException 629 | } 630 | Else If ($DialogAction = 0) 631 | { 632 | Menu ContextMenu, Check, Never here 633 | } 634 | Else 635 | { 636 | Menu ContextMenu, Check, Not now 637 | } 638 | 639 | 640 | Menu ContextMenu, Add, Debug this dialog, Debug_Controls 641 | 642 | 643 | ;---------------[ Show ]---------------------------------------- 644 | 645 | ; Menu ContextMenu, Standard 646 | ; BAckup to prevent errors 647 | 648 | Menu ContextMenu, UseErrorLevel 649 | 650 | Menu ContextMenu, Color, C0C59C 651 | 652 | Menu ContextMenu, Show, 100,100 653 | Menu ContextMenu, Delete 654 | 655 | } 656 | else 657 | { 658 | Menu ContextMenu, Delete 659 | } 660 | 661 | ; Delete _tempfile 662 | 663 | 664 | Return 665 | } 666 | 667 | 668 | 669 | ;_____________________________________________________________________________ 670 | ; 671 | FolderChoice: 672 | ;_____________________________________________________________________________ 673 | ; 674 | { 675 | Global $DialogType 676 | If ValidFolder( A_ThisMenuItem ) 677 | { 678 | ; FeedDialog($WinID, $FolderPath) 679 | FeedDialog%$DialogType%($WinID, A_ThisMenuItem) 680 | } 681 | 682 | Return 683 | } 684 | 685 | ;_____________________________________________________________________________ 686 | ; 687 | AutoSwitch: 688 | ;_____________________________________________________________________________ 689 | ; 690 | Global $DialogType 691 | 692 | IniWrite, 1, %$INI%, Dialogs, %$FingerPrint% 693 | 694 | $DialogAction := 1 695 | 696 | $FolderPath := Get_Zfolder($WinID) 697 | 698 | If ( ValidFolder( $FolderPath )) 699 | { 700 | ; FeedDialog($WinID, $FolderPath) 701 | FeedDialog%$DialogType%($WinID, $FolderPath) 702 | } 703 | 704 | $FolderPath := "" 705 | 706 | 707 | Return 708 | 709 | 710 | 711 | ;_____________________________________________________________________________ 712 | ; 713 | Never: 714 | ;_____________________________________________________________________________ 715 | ; 716 | 717 | IniWrite, 0, %$INI%, Dialogs, %$FingerPrint% 718 | 719 | $DialogAction := 0 720 | 721 | Return 722 | 723 | 724 | 725 | ;_____________________________________________________________________________ 726 | ; 727 | ThisMenu: 728 | ;_____________________________________________________________________________ 729 | ; 730 | 731 | IniDelete, %$INI%, Dialogs, %$FingerPrint% 732 | 733 | $DialogAction := "" 734 | 735 | Return 736 | 737 | ;_____________________________________________________________________________ 738 | ; 739 | AutoSwitchException: 740 | ;_____________________________________________________________________________ 741 | ; 742 | Global $DialogType 743 | 744 | 745 | MsgBox, 1, AutoSwitch Exceptions, 746 | ( 747 | 748 | For AutoSwitch to work, typically a file manager is "2 windows away" : 749 | File manager ==> Aapplication ==> Dialog. 750 | AutoSwitch uses that fore deteceting when to switch folders. 751 | 752 | If AutoSwitch doesn't work as expected, the application might have 753 | created extra (possibly even hidden) windows 754 | Example: File manager==> Task Manager ==> Run new task ==> Browse 755 | ==> Dialog . 756 | 757 | 758 | To support these dialogs too: 759 | - Click Cancel in this Dialog 760 | - Alt-Tab to the file manager 761 | - Alt-Tab back to the file dialog 762 | - Press Control-Q 763 | - Select AutoSwitch Exception 764 | - Press OK 765 | 766 | 767 | The correct number of "windows away" will be detected and shown 768 | If these values are accepted, an exception will be added for this dialog. 769 | 770 | - Press OK if all looks OK 771 | (most common exception is 3; default is 2) 772 | 773 | ) 774 | 775 | IfMsgBox OK 776 | { 777 | 778 | ; Header for list 779 | Gui, Add, ListView, r30 w1024, Nr|ID|Window Title|program|Class 780 | 781 | WinGet, id, list 782 | 783 | Loop, %id% 784 | { 785 | this_id := id%A_Index% 786 | 787 | WinGetClass, this_class, ahk_id %this_id% 788 | WinGet, this_exe, ProcessName, ahk_id %this_id% 789 | WinGetTitle, this_title , ahk_id %this_id% 790 | 791 | If ( this_id = $WinID ) 792 | { 793 | $select := "select" 794 | level_1 := A_Index 795 | Z_exe := this_exe 796 | Z_title := this_title 797 | } 798 | 799 | If (NOT level_2) AND ( ( this_class = "TTOTAL_CMD" ) OR ( this_class = "CabinetWClass" ) OR ( this_class = "ThunderRT6FormDC" )) 800 | { 801 | $select := "select" 802 | level_2 := A_Index 803 | } 804 | 805 | LV_Add( $select, A_Index, This_id, this_title, this_exe, this_class ) 806 | $select := "" 807 | } 808 | 809 | 810 | Delta := level_2 - level_1 811 | LV_ModifyCol() ; Auto-size each column to fit its contents. 812 | LV_ModifyCol(1, "Integer") ; For sorting purposes, indicate that column 1 is an integer. 813 | 814 | Gui, Show 815 | 816 | ; Handle case when no file manager found (no Level2) 817 | MsgBox, 1, "File manager found ..", It looks like the filemanager is %Delta% levels away `n(default = 2)`n`nMAke this the new default for this specific dialog window? 818 | 819 | IfMsgBox OK 820 | { 821 | If ( Delta = 2 ) 822 | { 823 | IniDelete, %$INI%, AutoSwitchException, %$FingerPrint% 824 | 825 | } Else 826 | { 827 | IniWrite, %Delta%, %$INI%, AutoSwitchException, %$FingerPrint% 828 | } 829 | 830 | ; After INI was updated: try to AutoSwich straight away .. 831 | 832 | $FolderPath := Get_Zfolder($WinID) 833 | 834 | If ( ValidFolder( $FolderPath )) 835 | { 836 | ; FeedDialog($WinID, $FolderPath) 837 | FeedDialog%$DialogType%($WinID, $FolderPath) 838 | } 839 | } 840 | 841 | 842 | GUI, Destroy 843 | id := "" 844 | this_class := "" 845 | this_exe := "" 846 | this_id := "" 847 | this_title := "" 848 | $select := "" 849 | level_1 := "" 850 | Z_exe := "" 851 | Z_title := "" 852 | level_2 := "" 853 | Delta := "" 854 | $select := "" 855 | 856 | } 857 | 858 | Return 859 | 860 | 861 | 862 | ;_____________________________________________________________________________ 863 | ; 864 | Dummy: 865 | ;_____________________________________________________________________________ 866 | ; 867 | 868 | Return 869 | 870 | 871 | 872 | ;_____________________________________________________________________________ 873 | ; 874 | ValidFolder(_thisPath_) 875 | ;_____________________________________________________________________________ 876 | ; 877 | { 878 | ; Prepared for extra checks 879 | ; If ( _thisPath_ != "") { 880 | If ( _thisPath_ != "" AND (StrLen(_thisPath_) < 259 )) 881 | { 882 | If InStr(FileExist(_thisPath_), "D") 883 | Return TRUE 884 | Else 885 | Return FALSE 886 | } 887 | Else 888 | { 889 | Return FALSE 890 | } 891 | } 892 | 893 | ;_____________________________________________________________________________ 894 | ; 895 | Get_Zfolder( _thisID_ ) 896 | ;_____________________________________________________________________________ 897 | ; 898 | { 899 | ; Get z-order of all applicatiions. 900 | ; When "our" ID is found: save z-order of "the next one" 901 | ; Actualy: The next-next one as the next one is the parent-program that opens the dialog (e.g. notepad ) 902 | ; if the next-next one is a file mananger (Explorer class = CabinetWClass ; TC = TTOTAL_CMD), 903 | ; read the active folder and browse to it in the dialog. 904 | ; Exceptions are in INI section [AutoSwitchException] 905 | 906 | 907 | Global $FingerPrint 908 | Global $INI 909 | Global _tempfile 910 | 911 | ; Read Z-Order for this application (based on $Fingerprint) 912 | ; from INI section [AutoSwitchException] 913 | ; If not found, use default ( = 2) 914 | 915 | IniRead, _zDelta, %$INI%, AutoSwitchException, %$FingerPrint%, 2 916 | 917 | WinGet, id, list 918 | 919 | Loop, %id% 920 | { 921 | this_id := id%A_Index% 922 | If ( _thisID_ = this_id ) 923 | { 924 | this_z := A_Index 925 | Break 926 | } 927 | } 928 | 929 | $next := this_z + _zDelta 930 | next_id := id%$next% 931 | WinGetClass, next_class, ahk_id %next_id% 932 | 933 | 934 | If ( next_class = "TTOTAL_CMD" ) ; Total Commander 935 | { 936 | ClipSaved := ClipboardAll 937 | Clipboard := "" 938 | 939 | SendMessage 1075, %cm_CopySrcPathToClip%, 0, , ahk_id %next_id% 940 | 941 | If (ErrorLevel = 0) 942 | { 943 | 944 | $ZFolder := clipboard 945 | Clipboard := ClipSaved 946 | } 947 | } 948 | 949 | 950 | If ( next_class = "ThunderRT6FormDC" ) ; XYPlorer 951 | { 952 | ClipSaved := ClipboardAll 953 | Clipboard := "" 954 | 955 | Send_XYPlorer_Message( next_id, "::copytext get('path', a);") 956 | ClipWait,0 957 | 958 | $ZFolder := clipboard 959 | Clipboard := ClipSaved 960 | } 961 | 962 | 963 | If ( next_class = "CabinetWClass" ) ; File Explorer 964 | { 965 | For $Exp in ComObjCreate("Shell.Application").Windows 966 | { 967 | try ; Attempts to execute code. 968 | { 969 | _checkID := $Exp.hwnd 970 | } 971 | catch e ; Handles the errors that Opus will generate. 972 | { 973 | ; Do nothing. Just ignore error. 974 | ; Proceed to the next Explorer instance 975 | } 976 | 977 | ; if ( $Exp.hwnd = next_id ) 978 | if ( next_id = _checkID ) 979 | { 980 | $ZFolder := $Exp.Document.Folder.Self.Path 981 | Break 982 | } 983 | } 984 | } 985 | 986 | 987 | If ( next_class = "dopus.lister" ) ; Directory Opus 988 | { 989 | ; Get dopus.exe loction 990 | WinGet, _thisPID, PID, ahk_id %next_id% 991 | _dopus_exe := GetModuleFileNameEx( _thisPID ) 992 | 993 | 994 | ; Get lister info 995 | Run, "%_dopus_exe%\..\dopusrt.exe" /info "%_tempfile%"`,paths,,, $DUMMY 996 | 997 | Sleep, 100 998 | 999 | FileRead, OpusInfo, %_tempfile% 1000 | 1001 | Sleep, 20 1002 | FileDelete, %_tempfile% 1003 | 1004 | ; Get active path of the most recent lister 1005 | RegExMatch(OpusInfo, "mO)^.*lister=\""" . next_id . "\"".*tab_state=\""1\"".*\>(.*)\<\/path\>$", out) 1006 | $ZFolder := out.Value(1) 1007 | ; MsgBox Active Z-folder = [%$ZFolder%] 1008 | 1009 | } 1010 | 1011 | 1012 | Return $ZFolder 1013 | } 1014 | 1015 | 1016 | 1017 | ;_____________________________________________________________________________ 1018 | ; 1019 | GetModuleFileNameEx( p_pid ) 1020 | ;_____________________________________________________________________________ 1021 | ; 1022 | ; From: https://autohotkey.com/board/topic/32965-getting-file-path-of-a-running-process/ 1023 | ; NotNull: changed "GetModuleFileNameExA" to "GetModuleFileNameExW"" 1024 | 1025 | { 1026 | 1027 | h_process := DllCall( "OpenProcess", "uint", 0x10|0x400, "int", false, "uint", p_pid ) 1028 | if ( ErrorLevel or h_process = 0 ) 1029 | return 1030 | 1031 | name_size = 255 1032 | VarSetCapacity( name, name_size ) 1033 | 1034 | result := DllCall( "psapi.dll\GetModuleFileNameExW", "uint", h_process, "uint", 0, "str", name, "uint", name_size ) 1035 | 1036 | DllCall( "CloseHandle", h_process ) 1037 | 1038 | return, name 1039 | } 1040 | 1041 | 1042 | 1043 | 1044 | ;_____________________________________________________________________________ 1045 | ; 1046 | Send_XYPlorer_Message(xyHwnd, message) 1047 | ;_____________________________________________________________________________ 1048 | ; 1049 | 1050 | { 1051 | size := StrLen(message) 1052 | If !(A_IsUnicode) 1053 | { 1054 | VarSetCapacity(data, size * 2, 0) 1055 | StrPut(message, &data, "UTF-16") 1056 | } Else 1057 | { 1058 | data := message 1059 | } 1060 | 1061 | VarSetCapacity(COPYDATA, A_PtrSize * 3, 0) 1062 | NumPut(4194305, COPYDATA, 0, "Ptr") 1063 | NumPut(size * 2, COPYDATA, A_PtrSize, "UInt") 1064 | NumPut(&data, COPYDATA, A_PtrSize * 2, "Ptr") 1065 | result := DllCall("User32.dll\SendMessageW", "Ptr", xyHwnd, "UInt", 74, "Ptr", 0, "Ptr", ©DATA, "Ptr") 1066 | Return 1067 | } 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | ;_____________________________________________________________________________ 1074 | ; 1075 | Debug_Controls: 1076 | ;_____________________________________________________________________________ 1077 | ; 1078 | 1079 | 1080 | 1081 | 1082 | ; Add ControlGetPos [, X, Y, Width, Height, Control, WinTitle, WinText, ExcludeTitle, ExcludeText] 1083 | ; change folder to ahk folder. change name to fingerpringt.csv 1084 | 1085 | 1086 | SetFormat, Integer, D 1087 | ; Header for list 1088 | Gui, Add, ListView, r30 w1024, Control|ID|PID||Text|X|Y|Width|Height 1089 | 1090 | ; Loop through controls 1091 | WinGet, ActivecontrolList, ControlList, A 1092 | 1093 | Loop, Parse, ActivecontrolList, `n 1094 | { 1095 | ; Get ID 1096 | ControlGet, _ctrlHandle, Hwnd,, %A_LoopField%, A 1097 | 1098 | ; Get Text 1099 | ControlGetText _ctrlText ,, ahk_id %_ctrlHandle% 1100 | 1101 | ; Get control coordinates 1102 | ControlGetPos _X, _Y, _Width, _Height, , ahk_id %_ctrlHandle% 1103 | ; Get PID 1104 | _parentHandle := DllCall("GetParent", "Ptr", _ctrlHandle) 1105 | 1106 | ; Add to listview ; abs for hex to dec 1107 | LV_Add(, A_LoopField, abs(_ctrlHandle), _parentHandle, _ctrlText, _X, _Y, _Width, _Height ) 1108 | 1109 | 1110 | _ctrlHandle := "" 1111 | _ctrlText := "" 1112 | _parentHandle := "" 1113 | _X := "" 1114 | _Y := "" 1115 | _Width := "" 1116 | _Height := "" 1117 | 1118 | } 1119 | 1120 | LV_ModifyCol() ; Auto-size each column to fit its contents. 1121 | LV_ModifyCol(2, "Integer") 1122 | LV_ModifyCol(3, "Integer") 1123 | 1124 | 1125 | Gui, Add, Button, y+10 w100 h30 gDebugExport, Export 1126 | Gui, Add, Button, x+10 w100 h30 gCancelLV, Cancel 1127 | 1128 | Gui, Show 1129 | 1130 | return 1131 | 1132 | 1133 | 1134 | ;_____________________________________________________________________________ 1135 | ; 1136 | DebugExport: 1137 | ;_____________________________________________________________________________ 1138 | ; 1139 | 1140 | _fileName := A_ScriptDir . "\" . $FingerPrint . ".csv" 1141 | oFile := FileOpen(_fileName, "w") ; Creates a new file, overwriting any existing file. 1142 | If (IsObject(oFile)) 1143 | { 1144 | ; Header 1145 | _line := "ControlName;ID;PID;Text;X;Y;Width;Height" 1146 | 1147 | oFile.WriteLine(_line) 1148 | 1149 | Gui, ListView 1150 | Loop % LV_GetCount() 1151 | { 1152 | LV_GetText(_col1, A_index, 1) 1153 | LV_GetText(_col2, A_index, 2) 1154 | LV_GetText(_col3, A_index, 3) 1155 | LV_GetText(_col4, A_index, 4) 1156 | LV_GetText(_col5, A_index, 5) 1157 | LV_GetText(_col6, A_index, 6) 1158 | LV_GetText(_col7, A_index, 7) 1159 | LV_GetText(_col8, A_index, 8) 1160 | _line := _col1 ";" _col2 "," _col3 ";" _col4 ";" _col5 ";" _col6 ";" _col7 ";" _col8 ";" 1161 | oFile.WriteLine(_line) 1162 | } 1163 | 1164 | oFile.Close() 1165 | oFile:="" 1166 | 1167 | Msgbox Results exported to:`n`n"%_filename%" 1168 | 1169 | } 1170 | Else ; File could not be initialized 1171 | { 1172 | Msgbox Can't create %_fileName% 1173 | } 1174 | 1175 | 1176 | 1177 | ; Clean up 1178 | _fileName := "" 1179 | _line := "" 1180 | _col1 := "" 1181 | _col2 := "" 1182 | _col3 := "" 1183 | _col4 := "" 1184 | _col5 := "" 1185 | _col6 := "" 1186 | _col7 := "" 1187 | _col8 := "" 1188 | 1189 | ;_____________________________________________________________________________ 1190 | CancelLV: 1191 | ;_____________________________________________________________________________ 1192 | 1193 | LV_Delete() 1194 | GUI, Destroy 1195 | 1196 | Return 1197 | 1198 | 1199 | /* 1200 | ============================================================================ 1201 | */ 1202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuickSwitch 2 | **Use opened file manager folders in File dialogs.** 3 | 4 | QuickSwitch is an alternative to [Listary's QuickSwitch](https://www.youtube.com/watch?v=9T9-OtRVeUw) as that is abandoned. 5 |
6 |
7 | ### What does QuickSwitch do? 8 | 9 | When in a file dialog, like Save As .. or Open ... , it can switch that dialog to any folder that is opened in a file manager. 10 | Currently supported file managers: File Explorer, Directory Opus, Total Commander and XYPlorer. 11 | 12 | QuickSwitch can do that in a couple of different ways: 13 | 14 | - **QuickSwitch Menu mode**. 15 | Out of the box, it will show you a list of opened folders to choose from. 16 | When you select one of those, the file dialog will switch to the selected folder. 17 | The menu will not be shown if there are no file manager folders to select from. 18 | - **AutoSwitch mode**. 19 | After selecting AutoSwitch from the menu, the menu will no longer be shown for that specific dialog, for example Notepad's Save As dialog. 20 | From there on, when you Alt-Tab to the file manager and Alt-Tab back to the file dialog, The file dialog will automatically open the folder that was active in that file manager. 21 | When the file manager was active before you open the file dialog, it will even open that folder straight away, without further needed action. 22 | The keyboard shortcut Control-Q will still open the menu if you need it, for example to reconfigure what to do in this dialog. 23 | 24 | - There is also an option **Never here**. 25 | Select that setting to 'mute' QuickSwitch in that specific dialog. 26 | Useful for example for webbrowser dialogs, as they already keep track of website/downloadfolder combinations. 27 | 28 | - **AutoSwitch Exception** 29 | AutoSwitch "calculates" the number of (hidden/normal) windows between the most recent used file manager and the file dialog. In 95% of the cases, this is 2 windows, like for example (1) Notepad's Open dialog, (2) Notepad itself and (3) File Explorer. 30 | For the remaining 5%, you can follow these steps when AutoSwitch is unable "to do it's thing": 31 | - Open the unwilling file dialog. 32 | (Nothing will happen as AutoSwitch doesn't understand/ miscalculates) 33 | - Press 'CTRL + Q' 34 | - Select *AutoSwitch exception* from the QuickSwitch menu 35 | - Follow the on-screen steps. 36 | 37 | In short, this lets QuickSwitch figure out and learn what the correct "window-distance" is for this specific application/dialog combination. 38 | The next time, that will be used. and AutoSwitch should work again. 39 |
40 |
41 | 42 | ## QuickSwitch is not finished yet ... 43 | ... but it should be fully functional in it's current form. 44 | 45 | On the To-Do list for the near future are: 46 | - Support for long paths ( longer than 259 characters) 47 | - A better user interface. There will be a simplified menu with less 'technical' entries. 48 | Suggestions are welcome. 49 | - A different way to 'talk with' Total Commander an XYplorer 50 | - A notification area (/system tray) menu, including icon 51 | - Option to load at startup 52 |
53 |
54 | 55 | ## Limitations 56 | - Windows 7 and up are supported. QuickSwitch will not run on lower versions. 57 | - Can not get information from file managers that run elevated (as administrator) 58 |
59 |
60 | 61 | ## Installation 62 | 63 | - Download the QuickSwitch zip-file from the [releases](https://github.com/gepruts/QuickSwitch/releases/latest) 64 | - Extract the zip-file containing QuickSwitch.exe to a folder 65 | Note: QuickSwitch will write it's ini-file to that same folder, so you need write access there. 66 | - That's all 67 |
68 |
69 | 70 | ## Running QuickSwitch 71 | 72 | To start, run QuickSwitch.exe. It will stay quietly in the background, until you open a File Dialog. 73 | To stop using QuickSwitch, right-click it's system tray icon - a white on green "H" - and choose **Exit** 74 | 75 | --------------------------------------------------------------------------------