1- using Flow . Launcher . Infrastructure . QuickSwitch . Interface ;
1+ using System ;
2+ using System . Threading ;
3+ using Flow . Launcher . Infrastructure . Logger ;
4+ using Flow . Launcher . Infrastructure . QuickSwitch . Interface ;
25using Windows . Win32 ;
36using Windows . Win32 . Foundation ;
7+ using Windows . Win32 . UI . WindowsAndMessaging ;
48
59namespace Flow . Launcher . Infrastructure . QuickSwitch . Models
610{
@@ -57,7 +61,7 @@ public WindowsDialogWindow(HWND handle)
5761 Handle = handle ;
5862 }
5963
60- public IQuickSwitchDialogTab GetCurrentTab ( )
64+ public IQuickSwitchDialogWindowTab GetCurrentTab ( )
6165 {
6266 return new WindowsDialogTab ( Handle ) ;
6367 }
@@ -68,31 +72,153 @@ public void Dispose()
6872 }
6973 }
7074
71- internal class WindowsDialogTab : IQuickSwitchDialogTab
75+ internal class WindowsDialogTab : IQuickSwitchDialogWindowTab
7276 {
7377 public HWND Handle { get ; private set ; }
7478
79+ private static readonly string ClassName = nameof ( WindowsDialogTab ) ;
80+
81+ private readonly bool _legacy = false ;
82+
83+ private readonly HWND _pathControl ;
84+ private readonly HWND _pathEditor ;
85+ private readonly HWND _fileEditor ;
86+ private readonly HWND _openButton ;
87+
7588 public WindowsDialogTab ( HWND handle )
7689 {
7790 Handle = handle ;
91+
92+ // Get the handle of the path editor
93+ // The window with class name "ComboBoxEx32" is not visible when the path editor is not with the keyboard focus
94+ _pathControl = PInvoke . GetDlgItem ( handle , 0x0000 ) ; // WorkerW
95+ _pathControl = PInvoke . GetDlgItem ( _pathControl , 0xA005 ) ; // ReBarWindow32
96+ _pathControl = PInvoke . GetDlgItem ( _pathControl , 0xA205 ) ; // Address Band Root
97+ _pathControl = PInvoke . GetDlgItem ( _pathControl , 0x0000 ) ; // msctls_progress32
98+ _pathControl = PInvoke . GetDlgItem ( _pathControl , 0xA205 ) ; // ComboBoxEx32
99+ if ( _pathControl == HWND . Null )
100+ {
101+ // https://github.com/idkidknow/Flow.Launcher.Plugin.DirQuickJump/issues/1
102+ // The dialog is a legacy one, so we edit file name editor directly.
103+ _legacy = true ;
104+ _pathEditor = HWND . Null ;
105+ Log . Info ( ClassName , "Failed to find path control handle - Legacy dialog" ) ;
106+ }
107+ else
108+ {
109+ _pathEditor = PInvoke . GetDlgItem ( _pathControl , 0xA205 ) ; // ComboBox
110+ _pathEditor = PInvoke . GetDlgItem ( _pathEditor , 0xA205 ) ; // Edit
111+ if ( _pathEditor == HWND . Null )
112+ {
113+ Log . Error ( ClassName , "Failed to find path editor handle" ) ;
114+ }
115+ }
116+
117+ // Get the handle of the file name editor of Open file dialog
118+ _fileEditor = PInvoke . GetDlgItem ( handle , 0x047C ) ; // ComboBoxEx32
119+ _fileEditor = PInvoke . GetDlgItem ( _fileEditor , 0x047C ) ; // ComboBox
120+ _fileEditor = PInvoke . GetDlgItem ( _fileEditor , 0x047C ) ; // Edit
121+ if ( _fileEditor == HWND . Null )
122+ {
123+ // Get the handle of the file name editor of Save/SaveAs file dialog
124+ _fileEditor = PInvoke . GetDlgItem ( handle , 0x0000 ) ; // DUIViewWndClassName
125+ _fileEditor = PInvoke . GetDlgItem ( _fileEditor , 0x0000 ) ; // DirectUIHWND
126+ _fileEditor = PInvoke . GetDlgItem ( _fileEditor , 0x0000 ) ; // FloatNotifySink
127+ _fileEditor = PInvoke . GetDlgItem ( _fileEditor , 0x0000 ) ; // ComboBox
128+ _fileEditor = PInvoke . GetDlgItem ( _fileEditor , 0x03E9 ) ; // Edit
129+ if ( _fileEditor == HWND . Null )
130+ {
131+ Log . Error ( ClassName , "Failed to find file name editor handle" ) ;
132+ }
133+ }
134+
135+ // Get the handle of the open button
136+ _openButton = PInvoke . GetDlgItem ( handle , 0x0001 ) ; // Open/Save/SaveAs Button
137+ if ( _openButton == HWND . Null )
138+ {
139+ Log . Error ( ClassName , "Failed to find open button handle" ) ;
140+ }
78141 }
79142
80143 public string GetCurrentFolder ( )
81144 {
82- // TODO
83- return string . Empty ;
145+ if ( _pathEditor . IsNull ) return string . Empty ;
146+ return GetWindowText ( _pathEditor ) ;
84147 }
85148
86149 public string GetCurrentFile ( )
87150 {
88- // TODO
89- return string . Empty ;
151+ if ( _fileEditor . IsNull ) return string . Empty ;
152+ return GetWindowText ( _fileEditor ) ;
90153 }
91154
92- public bool OpenFolder ( string path )
155+ public bool JumpFolder ( string path , bool auto )
93156 {
94- // TODO
95- return false ;
157+ if ( _legacy || auto )
158+ {
159+ // https://github.com/idkidknow/Flow.Launcher.Plugin.DirQuickJump/issues/1
160+ // The dialog is a legacy one, so we edit file name text box directly
161+ if ( _fileEditor . IsNull ) return false ;
162+ SetWindowText ( _fileEditor , path ) ;
163+
164+ if ( _openButton . IsNull ) return false ;
165+ PInvoke . SendMessage ( _openButton , PInvoke . BM_CLICK , 0 , 0 ) ;
166+
167+ return true ;
168+ }
169+
170+ if ( _pathControl . IsNull ) return false ;
171+
172+ var timeOut = ! SpinWait . SpinUntil ( ( ) =>
173+ {
174+ var style = PInvoke . GetWindowLong ( _pathControl , WINDOW_LONG_PTR_INDEX . GWL_STYLE ) ;
175+ return ( style & ( int ) WINDOW_STYLE . WS_VISIBLE ) != 0 ;
176+ } , 1000 ) ;
177+ if ( timeOut )
178+ {
179+ Log . Error ( ClassName , "Path control is not visible" ) ;
180+ return false ;
181+ }
182+
183+ if ( _pathEditor . IsNull ) return false ;
184+
185+ SetWindowText ( _pathEditor , path ) ;
186+ return true ;
187+ }
188+
189+ public bool JumpFile ( string path )
190+ {
191+ if ( _fileEditor . IsNull ) return false ;
192+ SetWindowText ( _fileEditor , path ) ;
193+ return true ;
194+ }
195+
196+ public bool Open ( )
197+ {
198+ if ( _openButton . IsNull ) return false ;
199+ PInvoke . PostMessage ( _openButton , PInvoke . BM_CLICK , 0 , 0 ) ;
200+ return true ;
201+ }
202+
203+ private static unsafe string GetWindowText ( HWND handle )
204+ {
205+ int length ;
206+ Span < char > buffer = stackalloc char [ 1000 ] ;
207+ fixed ( char * pBuffer = buffer )
208+ {
209+ // If the control has no title bar or text, or if the control handle is invalid, the return value is zero.
210+ length = ( int ) PInvoke . SendMessage ( handle , PInvoke . WM_GETTEXT , 1000 , ( nint ) pBuffer ) ;
211+ }
212+
213+ return buffer [ ..length ] . ToString ( ) ;
214+ }
215+
216+ private static unsafe nint SetWindowText ( HWND handle , string text )
217+ {
218+ fixed ( char * textPtr = text + '\0 ' )
219+ {
220+ return PInvoke . SendMessage ( handle , PInvoke . WM_SETTEXT , 0 , ( nint ) textPtr ) . Value ;
221+ }
96222 }
97223
98224 public void Dispose ( )
0 commit comments