@@ -222,18 +222,194 @@ static async Task MaximizeWindow(Process process)
222222 // SW_MAXIMIZE = 3
223223 ShowWindow ( process . MainWindowHandle , 3 ) ;
224224 SetForegroundWindow ( process . MainWindowHandle ) ;
225+
226+ // Wait briefly for the window to finish layout after maximize
227+ await Task . Delay ( 500 ) ;
228+ CenterVerticalSplit ( process . MainWindowHandle ) ;
225229 return ;
226230 }
227231
228232 await Task . Delay ( 100 ) ;
229233 }
230234 }
231235
236+ static void CenterVerticalSplit ( IntPtr mainWindow )
237+ {
238+ // Collect all child windows with their parent, class name, and rect
239+ var children = new List < ( IntPtr Handle , IntPtr Parent , string ClassName , RECT Rect ) > ( ) ;
240+ EnumChildWindows ( mainWindow , ( hwnd , _ ) =>
241+ {
242+ GetWindowRect ( hwnd , out var rect ) ;
243+ var className = GetWindowClassName ( hwnd ) ;
244+ children . Add ( ( hwnd , GetParent ( hwnd ) , className , rect ) ) ;
245+ return true ;
246+ } , IntPtr . Zero ) ;
247+
248+ // Log child window hierarchy for diagnostics
249+ Log . Information ( "CenterVerticalSplit: found {Count} child windows" , children . Count ) ;
250+ foreach ( var child in children )
251+ {
252+ var w = child . Rect . Right - child . Rect . Left ;
253+ var h = child . Rect . Bottom - child . Rect . Top ;
254+ Log . Information (
255+ " hwnd={Handle} parent={Parent} class={ClassName} pos=({Left},{Top}) size={Width}x{Height}" ,
256+ child . Handle , child . Parent , child . ClassName ,
257+ child . Rect . Left , child . Rect . Top , w , h ) ;
258+ }
259+
260+ // Find the vertical splitter: look for pairs of side-by-side siblings
261+ // with similar height that together span most of their parent's width.
262+ // Pick the pair with the largest combined area.
263+ var bestArea = 0 ;
264+ var bestLeftRect = default ( RECT ) ;
265+ var bestRightRect = default ( RECT ) ;
266+ var bestParent = IntPtr . Zero ;
267+
268+ foreach ( var group in children . GroupBy ( c => c . Parent ) )
269+ {
270+ var siblings = group . ToList ( ) ;
271+
272+ for ( var i = 0 ; i < siblings . Count ; i ++ )
273+ {
274+ for ( var j = i + 1 ; j < siblings . Count ; j ++ )
275+ {
276+ var a = siblings [ i ] ;
277+ var b = siblings [ j ] ;
278+ var heightA = a . Rect . Bottom - a . Rect . Top ;
279+ var heightB = b . Rect . Bottom - b . Rect . Top ;
280+
281+ var widthA = a . Rect . Right - a . Rect . Left ;
282+ var widthB = b . Rect . Right - b . Rect . Left ;
283+
284+ if ( heightA < 100 || heightB < 100 ||
285+ widthA <= 0 || widthB <= 0 )
286+ {
287+ continue ;
288+ }
289+
290+ if ( Math . Abs ( heightA - heightB ) > 20 ||
291+ Math . Abs ( a . Rect . Top - b . Rect . Top ) > 20 )
292+ {
293+ continue ;
294+ }
295+
296+ GetClientRect ( group . Key , out var parentClient ) ;
297+ var totalSpan = Math . Max ( a . Rect . Right , b . Rect . Right ) - Math . Min ( a . Rect . Left , b . Rect . Left ) ;
298+ if ( totalSpan < parentClient . Right * 0.8 )
299+ {
300+ continue ;
301+ }
302+
303+ var area = ( a . Rect . Right - a . Rect . Left ) * heightA +
304+ ( b . Rect . Right - b . Rect . Left ) * heightB ;
305+ if ( area <= bestArea )
306+ {
307+ continue ;
308+ }
309+
310+ bestArea = area ;
311+ bestParent = group . Key ;
312+ if ( a . Rect . Left <= b . Rect . Left )
313+ {
314+ bestLeftRect = a . Rect ;
315+ bestRightRect = b . Rect ;
316+ }
317+ else
318+ {
319+ bestLeftRect = b . Rect ;
320+ bestRightRect = a . Rect ;
321+ }
322+ }
323+ }
324+ }
325+
326+ if ( bestArea == 0 )
327+ {
328+ Log . Information ( "CenterVerticalSplit: no matching split panel pair found" ) ;
329+ return ;
330+ }
331+
332+ // The splitter bar sits in the gap between the two panels.
333+ // Convert splitter screen position to parent client coordinates and
334+ // send mouse messages directly to the parent (SplitContainer) window.
335+ var splitterScreenX = ( bestLeftRect . Right + bestRightRect . Left ) / 2 ;
336+ var splitterScreenY = ( bestLeftRect . Top + bestLeftRect . Bottom ) / 2 ;
337+
338+ var splitterPoint = new POINT { X = splitterScreenX , Y = splitterScreenY } ;
339+ ScreenToClient ( bestParent , ref splitterPoint ) ;
340+
341+ GetClientRect ( bestParent , out var client ) ;
342+ var targetClientX = client . Right / 2 ;
343+
344+ Log . Information (
345+ "CenterVerticalSplit: sending drag from client ({FromX},{FromY}) to ({ToX},{ToY})" ,
346+ splitterPoint . X , splitterPoint . Y , targetClientX , splitterPoint . Y ) ;
347+
348+ var downLParam = MakeLParam ( splitterPoint . X , splitterPoint . Y ) ;
349+ var moveLParam = MakeLParam ( targetClientX , splitterPoint . Y ) ;
350+
351+ // WM_LBUTTONDOWN = 0x0201, WM_MOUSEMOVE = 0x0200, WM_LBUTTONUP = 0x0202
352+ // MK_LBUTTON = 0x0001
353+ SendMessage ( bestParent , 0x0201 , ( IntPtr ) 0x0001 , downLParam ) ;
354+ SendMessage ( bestParent , 0x0200 , ( IntPtr ) 0x0001 , moveLParam ) ;
355+ SendMessage ( bestParent , 0x0202 , IntPtr . Zero , moveLParam ) ;
356+ }
357+
358+ static IntPtr MakeLParam ( int x , int y ) =>
359+ ( IntPtr ) ( ( y << 16 ) | ( x & 0xFFFF ) ) ;
360+
361+ delegate bool EnumWindowsProc ( IntPtr hWnd , IntPtr lParam ) ;
362+
363+ [ StructLayout ( LayoutKind . Sequential ) ]
364+ struct RECT
365+ {
366+ public int Left , Top , Right , Bottom ;
367+ }
368+
369+ [ StructLayout ( LayoutKind . Sequential ) ]
370+ struct POINT
371+ {
372+ public int X , Y ;
373+ }
374+
232375 [ LibraryImport ( "user32.dll" ) ]
233376 [ return : MarshalAs ( UnmanagedType . Bool ) ]
234377 private static partial bool ShowWindow ( IntPtr hWnd , int nCmdShow ) ;
235378
236379 [ LibraryImport ( "user32.dll" ) ]
237380 [ return : MarshalAs ( UnmanagedType . Bool ) ]
238381 private static partial bool SetForegroundWindow ( IntPtr hWnd ) ;
382+
383+ [ LibraryImport ( "user32.dll" ) ]
384+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
385+ private static partial bool EnumChildWindows ( IntPtr hWndParent , EnumWindowsProc lpEnumFunc , IntPtr lParam ) ;
386+
387+ [ LibraryImport ( "user32.dll" ) ]
388+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
389+ private static partial bool GetWindowRect ( IntPtr hWnd , out RECT lpRect ) ;
390+
391+ [ LibraryImport ( "user32.dll" ) ]
392+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
393+ private static partial bool GetClientRect ( IntPtr hWnd , out RECT lpRect ) ;
394+
395+ [ LibraryImport ( "user32.dll" ) ]
396+ private static partial IntPtr GetParent ( IntPtr hWnd ) ;
397+
398+ [ LibraryImport ( "user32.dll" ) ]
399+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
400+ private static partial bool ScreenToClient ( IntPtr hWnd , ref POINT lpPoint ) ;
401+
402+ [ LibraryImport ( "user32.dll" , EntryPoint = "SendMessageW" ) ]
403+ private static partial IntPtr SendMessage ( IntPtr hWnd , uint msg , IntPtr wParam , IntPtr lParam ) ;
404+
405+ static string GetWindowClassName ( IntPtr hWnd )
406+ {
407+ var buffer = new System . Text . StringBuilder ( 256 ) ;
408+ GetClassName ( hWnd , buffer , buffer . Capacity ) ;
409+ return buffer . ToString ( ) ;
410+ }
411+
412+ [ DllImport ( "user32.dll" , CharSet = CharSet . Auto ) ]
413+ private static extern int GetClassName ( IntPtr hWnd , System . Text . StringBuilder lpClassName , int nMaxCount ) ;
414+
239415}
0 commit comments