11using System ;
2+ using System . Collections . Generic ;
23using System . IO ;
34using System . Runtime . InteropServices ;
45using System . Threading ;
@@ -48,6 +49,13 @@ public static class QuickSwitch
4849
4950 private static DispatcherTimer _dragMoveTimer = null ;
5051
52+ // A list of all file dialog windows that are auto switched already
53+ private static readonly List < HWND > _autoSwitchedDialogs = new ( ) ;
54+
55+ private static readonly object _autoSwitchedDialogsLock = new ( ) ;
56+
57+ private static readonly SemaphoreSlim _navigationLock = new ( 1 , 1 ) ;
58+
5159 private static HWND _mainWindowHandle = HWND . Null ;
5260
5361 private static HWND _dialogWindowHandle = HWND . Null ;
@@ -199,14 +207,16 @@ private static void NavigateDialogPath(Action action = null)
199207 return ;
200208 }
201209
210+ Log . Debug ( ClassName , $ "Path: { path } ") ;
202211 JumpToPath ( path , action ) ;
203212 }
204213
205- public static bool JumpToPath ( string path , Action action = null )
214+ [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Usage" , "VSTHRD101:Avoid unsupported async delegates" , Justification = "<Pending>" ) ]
215+ public static void JumpToPath ( string path , Action action = null )
206216 {
207- if ( ! CheckPath ( path , out var isFile ) ) return false ;
217+ if ( ! CheckPath ( path , out var isFile ) ) return ;
208218
209- var t = new Thread ( ( ) =>
219+ var t = new Thread ( async ( ) =>
210220 {
211221 // Jump after flow launcher window vanished (after JumpAction returned true)
212222 // and the dialog had been in the foreground.
@@ -217,20 +227,47 @@ public static bool JumpToPath(string path, Action action = null)
217227 } ;
218228
219229 // Assume that the dialog is in the foreground now
220- if ( isFile )
230+ await _navigationLock . WaitAsync ( ) ;
231+ try
232+ {
233+ var dialog = Win32Helper . GetForegroundWindowHWND ( ) ;
234+
235+ bool result ;
236+ if ( isFile )
237+ {
238+ result = Win32Helper . FileJump ( path , dialog ) ;
239+ }
240+ else
241+ {
242+ result = Win32Helper . DirJump ( path , dialog ) ;
243+ }
244+
245+ if ( result )
246+ {
247+ lock ( _autoSwitchedDialogsLock )
248+ {
249+ _autoSwitchedDialogs . Add ( dialog ) ;
250+ }
251+ }
252+ else
253+ {
254+ Log . Error ( ClassName , "Failed to jump to path" ) ;
255+ }
256+ }
257+ catch ( System . Exception e )
221258 {
222- Win32Helper . FileJump ( path , Win32Helper . GetForegroundWindow ( ) ) ;
259+ Log . Exception ( ClassName , "Failed to jump to path" , e ) ;
223260 }
224- else
261+ finally
225262 {
226- Win32Helper . DirJump ( path , Win32Helper . GetForegroundWindow ( ) ) ;
263+ _navigationLock . Release ( ) ;
227264 }
228-
265+
229266 // Invoke action if provided
230267 action ? . Invoke ( ) ;
231268 } ) ;
232269 t . Start ( ) ;
233- return true ;
270+ return ;
234271
235272 static bool CheckPath ( string path , out bool file )
236273 {
@@ -278,6 +315,8 @@ uint dwmsEventTime
278315 // File dialog window
279316 if ( GetWindowClassName ( hwnd ) == DialogWindowClassName )
280317 {
318+ Log . Debug ( ClassName , $ "Hwnd: { hwnd } ") ;
319+
281320 lock ( _dialogWindowHandleLock )
282321 {
283322 _dialogWindowHandle = hwnd ;
@@ -286,24 +325,43 @@ uint dwmsEventTime
286325 // Navigate to path
287326 if ( _settings . AutoQuickSwitch )
288327 {
289- Win32Helper . SetForegroundWindow ( hwnd ) ;
290- NavigateDialogPath ( ( ) =>
328+ // Check if we have already switched for this dialog
329+ bool alreadySwitched ;
330+ lock ( _dialogWindowHandleLock )
331+ {
332+ alreadySwitched = _autoSwitchedDialogs . Contains ( hwnd ) ;
333+ }
334+
335+ // Just show quick switch window
336+ if ( alreadySwitched )
291337 {
292- // Show quick switch window after path is navigated
293338 if ( _settings . ShowQuickSwitchWindow )
294339 {
295340 ShowQuickSwitchWindow ? . Invoke ( _dialogWindowHandle . Value ) ;
296341 _dragMoveTimer ? . Start ( ) ;
297342 }
298- } ) ;
299- return ;
343+ }
344+ // Show quick switch window after navigating the path
345+ else
346+ {
347+ NavigateDialogPath ( ( ) =>
348+ {
349+ if ( _settings . ShowQuickSwitchWindow )
350+ {
351+ ShowQuickSwitchWindow ? . Invoke ( _dialogWindowHandle . Value ) ;
352+ _dragMoveTimer ? . Start ( ) ;
353+ }
354+ } ) ;
355+ }
300356 }
301-
302- // Show quick switch window
303- if ( _settings . ShowQuickSwitchWindow )
357+ else
304358 {
305- ShowQuickSwitchWindow ? . Invoke ( _dialogWindowHandle . Value ) ;
306- _dragMoveTimer ? . Start ( ) ;
359+ // Show quick switch window
360+ if ( _settings . ShowQuickSwitchWindow )
361+ {
362+ ShowQuickSwitchWindow ? . Invoke ( _dialogWindowHandle . Value ) ;
363+ _dragMoveTimer ? . Start ( ) ;
364+ }
307365 }
308366 }
309367 // Quick switch window
@@ -413,10 +471,15 @@ uint dwmsEventTime
413471 // If the dialog window is destroyed, set _dialogWindowHandle to null
414472 if ( _dialogWindowHandle != HWND . Null && _dialogWindowHandle == hwnd )
415473 {
474+ Log . Debug ( ClassName , $ "Dialog Hwnd: { hwnd } ") ;
416475 lock ( _dialogWindowHandleLock )
417476 {
418477 _dialogWindowHandle = HWND . Null ;
419478 }
479+ lock ( _autoSwitchedDialogsLock )
480+ {
481+ _autoSwitchedDialogs . Remove ( hwnd ) ;
482+ }
420483 ResetQuickSwitchWindow ? . Invoke ( ) ;
421484 _dragMoveTimer ? . Stop ( ) ;
422485 }
0 commit comments