2021-09-17 05:18:02 +02:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Runtime.InteropServices ;
using System.Timers ;
namespace MSFSPopoutPanelManager
{
public class WindowManager
{
[DllImport("user32.dll")]
public static extern bool GetWindowRect ( IntPtr hwnd , ref Rect rectangle ) ;
2021-09-21 02:19:46 +02:00
[DllImport("user32.dll")]
public static extern IntPtr GetWindowLong ( IntPtr hWnd , int nIndex ) ;
[DllImport("USER32.dll")]
public static extern int SetWindowLong ( IntPtr hWnd , int nIndex , uint dwNewLong ) ;
[DllImport("user32.dll")]
public static extern IntPtr SetWindowPos ( IntPtr hWnd , IntPtr hWndInsertAfter , int x , int y , int cx , int cy , int wFlags ) ;
[DllImport("user32.dll")]
static extern bool MoveWindow ( IntPtr hWnd , int x , int y , int width , int height , bool repaint ) ;
const int SWP_NOMOVE = 0x0002 ;
const int SWP_NOSIZE = 0x0001 ;
const int SWP_ALWAYS_ON_TOP = SWP_NOMOVE | SWP_NOSIZE ;
2021-09-17 05:18:02 +02:00
2021-09-21 02:19:46 +02:00
const int GWL_STYLE = - 16 ;
const int WS_SIZEBOX = 0x00040000 ;
const int WS_BORDER = 0x00800000 ;
const int WS_DLGFRAME = 0x00400000 ;
const int WS_CAPTION = WS_BORDER | WS_DLGFRAME ;
2021-09-17 05:18:02 +02:00
private const int MSFS_CONNECTION_RETRY_TIMEOUT = 2000 ;
2021-09-23 15:34:10 +02:00
private FileManager _fileManager ;
2021-09-17 05:18:02 +02:00
private Timer _timer ;
private UserData _userData ;
private MainWindow _simWindow ;
private AnalysisEngine _analysisEngine ;
2021-09-21 02:19:46 +02:00
private Dictionary < IntPtr , Int64 > _originalChildWindowStyles ;
2021-09-17 05:18:02 +02:00
2021-09-23 15:34:10 +02:00
private bool _currentHidePanelTitleBarStatus ;
private bool _currentAlwaysOnTopStatus ;
public WindowManager ( FileManager fileManager )
2021-09-17 05:18:02 +02:00
{
2021-09-23 15:34:10 +02:00
_fileManager = fileManager ;
2021-09-17 05:18:02 +02:00
_analysisEngine = new AnalysisEngine ( ) ;
_analysisEngine . OnStatusUpdated + = ( source , e ) = > OnStatusUpdated ? . Invoke ( source , e ) ;
_analysisEngine . OnOcrDebugged + = ( source , e ) = > OnOcrDebugged ? . Invoke ( source , e ) ;
}
public event EventHandler < EventArgs < string > > OnStatusUpdated ;
public event EventHandler OnSimulatorStarted ;
public event EventHandler < EventArgs < Dictionary < string , string > > > OnOcrDebugged ;
public void CheckSimulatorStarted ( )
{
// Autoconnect to flight simulator
_timer = new Timer ( ) ;
_timer . Interval = MSFS_CONNECTION_RETRY_TIMEOUT ;
_timer . Enabled = true ;
_timer . Elapsed + = ( source , e ) = >
{
var simulatorConnected = GetSimulatorWindow ( ) ;
if ( simulatorConnected )
{
OnSimulatorStarted ? . Invoke ( this , null ) ;
_timer . Enabled = false ;
}
} ;
}
2021-09-23 15:34:10 +02:00
public void Reset ( )
{
// reset these statuses
_currentHidePanelTitleBarStatus = false ;
_currentAlwaysOnTopStatus = false ;
RestorePanelTitleBar ( ) ;
_originalChildWindowStyles = null ;
}
2021-09-21 02:19:46 +02:00
public bool Analyze ( string profileName )
2021-09-17 05:18:02 +02:00
{
2021-09-23 15:34:10 +02:00
2021-09-21 02:19:46 +02:00
_originalChildWindowStyles = null ;
_simWindow . ChildWindowsData = new List < ChildWindow > ( ) ;
2021-09-23 15:34:10 +02:00
var evalData = _fileManager . ReadProfileData ( ) . Find ( x = > x . Profile = = profileName ) ;
_analysisEngine . Analyze ( ref _simWindow , evalData ) ;
2021-09-17 05:18:02 +02:00
2021-09-21 02:19:46 +02:00
return _simWindow . ChildWindowsData . FindAll ( x = > x . PopoutType = = PopoutType . Custom | | x . PopoutType = = PopoutType . BuiltIn ) . Count > 0 ;
}
2021-09-23 15:34:10 +02:00
public void ApplySettings ( string profileName , bool hidePanelTitleBar , bool alwaysOnTop )
2021-09-21 02:19:46 +02:00
{
// Try to load previous profiles
2021-09-23 15:34:10 +02:00
_userData = _fileManager . ReadUserData ( ) ;
2021-09-21 02:19:46 +02:00
var profileSettings = _userData ! = null ? _userData . Profiles . Find ( x = > x . Name = = profileName ) : null ;
if ( profileSettings = = null )
{
OnStatusUpdated ? . Invoke ( this , new EventArgs < string > ( "Profile settings does not exist. Please move pop out panels to desire location and click Save Settings." ) ) ;
return ;
}
// select all valid windows
var childWindows = _simWindow . ChildWindowsData . FindAll ( x = > x . PopoutType = = PopoutType . Custom | | x . PopoutType = = PopoutType . BuiltIn ) ;
if ( childWindows . Count > 0 )
{
ApplyPositions ( profileSettings , childWindows ) ;
2021-09-23 15:34:10 +02:00
if ( _currentHidePanelTitleBarStatus ! = hidePanelTitleBar )
{
_currentHidePanelTitleBarStatus = hidePanelTitleBar ;
ApplyHidePanelTitleBar ( hidePanelTitleBar , childWindows ) ;
}
if ( _currentAlwaysOnTopStatus ! = alwaysOnTop )
{
_currentAlwaysOnTopStatus = alwaysOnTop ;
ApplyAlwaysOnTop ( alwaysOnTop , childWindows ) ;
}
2021-09-21 02:19:46 +02:00
}
2021-09-17 05:18:02 +02:00
}
2021-09-21 02:19:46 +02:00
public void SaveSettings ( string profileName , bool hidePanelTitleBar , bool alwaysOnTop )
2021-09-17 05:18:02 +02:00
{
if ( _userData = = null )
_userData = new UserData ( ) ;
var profile = _userData . Profiles . Find ( x = > x . Name = = profileName ) ;
if ( profile = = null )
{
2021-09-21 02:19:46 +02:00
profile = new Profile ( ) { Name = profileName , AlwaysOnTop = alwaysOnTop , HidePanelTitleBar = hidePanelTitleBar } ;
2021-09-17 05:18:02 +02:00
_userData . Profiles . Add ( profile ) ;
}
2021-09-21 02:19:46 +02:00
else
{
profile . HidePanelTitleBar = hidePanelTitleBar ;
profile . AlwaysOnTop = alwaysOnTop ;
}
2021-09-17 05:18:02 +02:00
if ( _simWindow . ChildWindowsData . Count > 0 )
{
foreach ( var window in _simWindow . ChildWindowsData )
{
2021-09-21 02:19:46 +02:00
if ( ! window . Title . Contains ( "Failed Analysis" ) )
{
var rect = new Rect ( ) ;
GetWindowRect ( window . Handle , ref rect ) ;
2021-09-17 05:18:02 +02:00
2021-09-21 02:19:46 +02:00
if ( ! profile . PopoutNames . TryAdd ( window . Title , rect ) )
profile . PopoutNames [ window . Title ] = rect ;
}
2021-09-17 05:18:02 +02:00
}
2021-09-23 15:34:10 +02:00
_fileManager . WriteUserData ( _userData ) ;
2021-09-17 05:18:02 +02:00
OnStatusUpdated ? . Invoke ( this , new EventArgs < string > ( "Pop out panel positions have been saved." ) ) ;
}
}
2021-09-21 02:19:46 +02:00
public void RestorePanelTitleBar ( )
2021-09-17 05:18:02 +02:00
{
2021-09-21 02:19:46 +02:00
if ( _simWindow ! = null )
2021-09-17 05:18:02 +02:00
{
2021-09-21 02:19:46 +02:00
var childWindows = _simWindow . ChildWindowsData . FindAll ( x = > x . PopoutType = = PopoutType . Custom | | x . PopoutType = = PopoutType . BuiltIn ) ;
ApplyHidePanelTitleBar ( false , childWindows ) ;
2021-09-17 05:18:02 +02:00
}
2021-09-21 02:19:46 +02:00
}
2021-09-17 05:18:02 +02:00
2021-09-21 02:19:46 +02:00
private void ApplyPositions ( Profile userProfile , List < ChildWindow > childWindows )
{
foreach ( var childWindow in childWindows )
2021-09-17 05:18:02 +02:00
{
2021-09-21 02:19:46 +02:00
var hasCoordinates = userProfile . PopoutNames . ContainsKey ( childWindow . Title ) ;
if ( hasCoordinates )
2021-09-17 05:18:02 +02:00
{
2021-09-21 02:19:46 +02:00
var rect = userProfile . PopoutNames [ childWindow . Title ] ;
MoveWindow ( childWindow . Handle , rect . Left , rect . Top , rect . Right - rect . Left , rect . Bottom - rect . Top , true ) ;
}
}
}
2021-09-17 05:18:02 +02:00
2021-09-21 02:19:46 +02:00
private void ApplyAlwaysOnTop ( bool alwaysOnTop , List < ChildWindow > childWindows )
{
if ( alwaysOnTop )
{
foreach ( var childWindow in childWindows )
{
Rect rect = new Rect ( ) ;
GetWindowRect ( childWindow . Handle , ref rect ) ;
SetWindowPos ( childWindow . Handle , new IntPtr ( - 1 ) , rect . Left , rect . Top , rect . Right - rect . Left , rect . Bottom - rect . Top , SWP_ALWAYS_ON_TOP ) ;
}
}
2021-09-23 15:34:10 +02:00
else
{
foreach ( var childWindow in childWindows )
{
Rect rect = new Rect ( ) ;
GetWindowRect ( childWindow . Handle , ref rect ) ;
SetWindowPos ( childWindow . Handle , new IntPtr ( - 2 ) , rect . Left , rect . Top , rect . Right - rect . Left , rect . Bottom - rect . Top , 0 ) ;
}
}
2021-09-21 02:19:46 +02:00
}
private void ApplyHidePanelTitleBar ( bool hidePanelTitleBar , List < ChildWindow > childWindows )
{
if ( hidePanelTitleBar )
{
_originalChildWindowStyles = new Dictionary < IntPtr , Int64 > ( ) ;
foreach ( var childWindow in childWindows )
{
// Save the current panel title bar styles so we can restore it later
if ( ! _originalChildWindowStyles . ContainsKey ( childWindow . Handle ) )
_originalChildWindowStyles [ childWindow . Handle ] = GetWindowLong ( childWindow . Handle , GWL_STYLE ) . ToInt64 ( ) ;
SetWindowLong ( childWindow . Handle , GWL_STYLE , ( uint ) ( _originalChildWindowStyles [ childWindow . Handle ] & ~ ( WS_CAPTION | WS_SIZEBOX ) ) ) ;
}
}
else
{
if ( _originalChildWindowStyles ! = null )
{
foreach ( var childWindow in childWindows )
2021-09-17 05:18:02 +02:00
{
2021-09-21 02:19:46 +02:00
if ( _originalChildWindowStyles . ContainsKey ( childWindow . Handle ) )
{
SetWindowLong ( childWindow . Handle , GWL_STYLE , ( uint ) _originalChildWindowStyles [ childWindow . Handle ] ) ;
_originalChildWindowStyles . Remove ( childWindow . Handle ) ;
}
2021-09-17 05:18:02 +02:00
}
}
}
}
private bool GetSimulatorWindow ( )
{
// Get flight simulator process
foreach ( var process in Process . GetProcesses ( ) )
{
if ( process . ProcessName = = "FlightSimulator" & & _simWindow = = null )
{
_simWindow = new MainWindow ( )
{
ProcessId = process . Id ,
ProcessName = process . ProcessName ,
Title = "Microsoft Flight Simulator" ,
Handle = process . MainWindowHandle
} ;
return true ;
}
}
return false ;
}
}
}