2023-07-12 22:41:31 +00:00
using MSFSPopoutPanelManager.DomainModel.Profile ;
using MSFSPopoutPanelManager.DomainModel.Setting ;
using MSFSPopoutPanelManager.Shared ;
2022-07-23 19:23:32 +00:00
using MSFSPopoutPanelManager.WindowsAgent ;
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
2023-07-12 22:41:31 +00:00
using System.Windows ;
2022-07-23 19:23:32 +00:00
namespace MSFSPopoutPanelManager.Orchestration
{
2024-02-28 02:44:21 +00:00
public class PanelPopOutOrchestrator : BaseOrchestrator
2022-07-23 19:23:32 +00:00
{
2023-08-16 06:42:18 +00:00
private const int READY_TO_FLY_BUTTON_APPEARANCE_DELAY = 2000 ;
2023-08-16 17:13:39 +00:00
private const int CAMERA_VIEW_HOME_COCKPIT_MODE = 8 ;
private const int CAMERA_VIEW_CUSTOM_CAMERA = 7 ;
2023-08-16 06:42:18 +00:00
2024-02-28 02:44:21 +00:00
private readonly FlightSimOrchestrator _flightSimOrchestrator ;
private readonly PanelSourceOrchestrator _panelSourceOrchestrator ;
private readonly PanelConfigurationOrchestrator _panelConfigurationOrchestrator ;
2024-03-03 05:02:21 +00:00
private readonly KeyboardOrchestrator _keyboardOrchestrator ;
2022-07-23 19:23:32 +00:00
2024-03-03 05:02:21 +00:00
public PanelPopOutOrchestrator ( SharedStorage sharedStorage , FlightSimOrchestrator flightSimOrchestrator , PanelSourceOrchestrator panelSourceOrchestrator , PanelConfigurationOrchestrator panelConfigurationOrchestrator , KeyboardOrchestrator keyboardOrchestrator ) : base ( sharedStorage )
2023-07-12 22:41:31 +00:00
{
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator = flightSimOrchestrator ;
_panelSourceOrchestrator = panelSourceOrchestrator ;
_panelConfigurationOrchestrator = panelConfigurationOrchestrator ;
2024-03-03 05:02:21 +00:00
_keyboardOrchestrator = keyboardOrchestrator ;
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
flightSimOrchestrator . OnFlightStarted + = async ( _ , _ ) = >
{
if ( AppSettingData . ApplicationSetting . AutoPopOutSetting . IsEnabled )
await AutoPopOut ( ) ;
} ;
2024-03-03 05:02:21 +00:00
2024-03-04 03:10:13 +00:00
_keyboardOrchestrator . OnKeystrokeDetected + = async ( _ , e ) = >
2024-03-03 05:02:21 +00:00
{
if ( e . KeyBinding = = AppSetting . KeyboardShortcutSetting . PopOutKeyboardBinding & & ! ActiveProfile . IsDisabledStartPopOut )
2024-03-04 03:10:13 +00:00
await ManualPopOut ( ) ;
2024-03-03 05:02:21 +00:00
} ;
2024-02-28 02:44:21 +00:00
}
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
private UserProfile ActiveProfile = > ProfileData ? . ActiveProfile ;
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
private ApplicationSetting AppSetting = > AppSettingData ? . ApplicationSetting ;
2023-08-14 19:51:28 +00:00
2022-07-23 19:23:32 +00:00
public event EventHandler OnPopOutStarted ;
2023-07-12 22:41:31 +00:00
public event EventHandler OnPopOutCompleted ;
public event EventHandler < PanelConfig > OnHudBarOpened ;
2024-02-28 02:44:21 +00:00
public event EventHandler < PanelConfig > OnNumPadOpened ;
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
public async Task ManualPopOut ( )
2022-07-23 19:23:32 +00:00
{
2024-02-28 02:44:21 +00:00
if ( ProfileData . ActiveProfile . IsDisabledStartPopOut | | ! FlightSimData . IsInCockpit )
2023-08-14 19:51:28 +00:00
return ;
2024-02-28 02:44:21 +00:00
ActiveProfile . IsDisabledStartPopOut = true ;
OnPopOutStarted ? . Invoke ( this , EventArgs . Empty ) ;
await CoreSteps ( ) ;
2022-07-23 19:23:32 +00:00
}
2024-02-28 02:44:21 +00:00
public async Task AutoPopOut ( )
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
await Application . Current . Dispatcher . Invoke ( async ( ) = >
2022-07-23 19:23:32 +00:00
{
2024-02-28 02:44:21 +00:00
ProfileData . AutoSwitchProfile ( ) ;
2022-07-23 19:23:32 +00:00
2023-07-26 20:22:44 +00:00
if ( ActiveProfile = = null )
return ;
2023-07-12 22:41:31 +00:00
// Do not do auto pop out if no profile matches the current aircraft
2024-02-28 02:44:21 +00:00
if ( ActiveProfile . AircraftBindings . All ( p = > p ! = FlightSimData . AircraftName ) )
2023-07-12 22:41:31 +00:00
return ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// Do not do auto pop out if no panel configs defined
if ( ActiveProfile . PanelConfigs . Count = = 0 )
return ;
2022-10-16 13:11:01 +00:00
2023-07-12 22:41:31 +00:00
// Do not do auto pop out if not all custom panels have panel source defined
if ( ActiveProfile . PanelConfigs . Count ( p = > p . PanelType = = PanelType . CustomPopout ) > 0 & &
ActiveProfile . PanelConfigs . Count ( p = > p . PanelType = = PanelType . CustomPopout & & p . HasPanelSource ) ! = ActiveProfile . PanelConfigs . Count ( p = > p . PanelType = = PanelType . CustomPopout ) )
return ;
2024-02-28 02:44:21 +00:00
StepReadyToFlyDelay ( true ) ;
2023-08-16 06:42:18 +00:00
2024-02-28 02:44:21 +00:00
ActiveProfile . IsDisabledStartPopOut = true ;
OnPopOutStarted ? . Invoke ( this , EventArgs . Empty ) ;
await CoreSteps ( ) ;
2023-07-12 22:41:31 +00:00
} ) ;
2022-07-23 19:23:32 +00:00
}
2024-02-28 02:44:21 +00:00
public void ClosePopOut ( )
{
2024-03-12 13:14:17 +00:00
CloseAllPopOuts ( ) ;
2024-02-28 02:44:21 +00:00
if ( ActiveProfile ! = null )
ActiveProfile . IsPoppedOut = false ;
}
private async Task CoreSteps ( )
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
if ( ActiveProfile = = null | | ActiveProfile . IsEditingPanelSource | | ActiveProfile . HasUnidentifiedPanelSource )
return ;
2022-09-06 04:07:03 +00:00
2023-07-12 22:41:31 +00:00
StatusMessageWriter . IsEnabled = true ;
StatusMessageWriter . ClearMessage ( ) ;
2024-02-28 02:44:21 +00:00
StatusMessageWriter . WriteMessageWithNewLine ( "Pop out in progress. Please wait and do not move your mouse." , StatusMessageType . Info ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
StepPopoutPrep ( ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// *** THIS MUST BE DONE FIRST. Get the built-in panel list to be configured later
List < IntPtr > builtInPanelHandles = WindowActionManager . GetWindowsByPanelType ( new List < PanelType > ( ) { PanelType . BuiltInPopout } ) ;
2022-07-23 19:23:32 +00:00
2023-11-05 02:10:03 +00:00
await StepAddCustomPanels ( builtInPanelHandles ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
StepAddBuiltInPanels ( builtInPanelHandles ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
StepAddHudBar ( ) ;
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
StepAddNumPad ( ) ;
2023-07-23 05:13:23 +00:00
SetupRefocusDisplay ( ) ;
2023-07-12 22:41:31 +00:00
StepApplyPanelConfig ( ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
await StepPostPopout ( ) ;
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
ActiveProfile . IsDisabledStartPopOut = false ;
OnPopOutCompleted ? . Invoke ( this , EventArgs . Empty ) ;
2023-08-16 17:13:39 +00:00
2023-07-12 22:41:31 +00:00
StatusMessageWriter . IsEnabled = false ;
}
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
private void StepPopoutPrep ( )
{
2024-02-28 02:44:21 +00:00
_panelConfigurationOrchestrator . EndConfiguration ( ) ;
2023-07-12 22:41:31 +00:00
// Set profile pop out status
2024-02-28 02:44:21 +00:00
ProfileData . ResetActiveProfile ( ) ;
2022-07-23 19:23:32 +00:00
// Close all existing custom pop out panels
2024-03-12 13:14:17 +00:00
CloseAllPopOuts ( ) ;
2022-07-23 19:23:32 +00:00
// Close all panel source overlays
2024-02-28 02:44:21 +00:00
_panelSourceOrchestrator . CloseAllPanelSource ( ) ;
2023-07-12 22:41:31 +00:00
}
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
private void StepReadyToFlyDelay ( bool isAutoPopOut )
2023-08-16 06:42:18 +00:00
{
if ( ! isAutoPopOut )
return ;
2024-02-28 02:44:21 +00:00
// Ready to fly button plugin default delay
Thread . Sleep ( READY_TO_FLY_BUTTON_APPEARANCE_DELAY ) ;
2023-08-16 06:42:18 +00:00
if ( AppSetting . AutoPopOutSetting . ReadyToFlyDelay = = 0 )
return ;
2024-02-28 02:44:21 +00:00
// Extra wait for cockpit view to appear and align
Thread . Sleep ( AppSetting . AutoPopOutSetting . ReadyToFlyDelay * 1000 ) ;
2023-08-16 06:42:18 +00:00
}
2024-02-28 02:44:21 +00:00
2023-11-05 02:10:03 +00:00
private async Task StepAddCustomPanels ( List < IntPtr > builtInPanelHandles )
2023-07-12 22:41:31 +00:00
{
if ( ! ActiveProfile . HasCustomPanels )
2022-07-23 19:23:32 +00:00
return ;
2023-09-02 04:10:40 +00:00
if ( ! await StepPreCustomPanelPopOut ( ) )
{
ActiveProfile . PanelConfigs . Where ( p = > p . PanelType = = PanelType . CustomPopout ) . ToList ( ) . ForEach ( p = > p . PanelHandle = IntPtr . Zero ) ;
return ;
}
2022-09-06 04:07:03 +00:00
2023-07-12 22:41:31 +00:00
await StepCustomPanelPopOut ( builtInPanelHandles ) ;
2022-09-06 04:07:03 +00:00
2023-07-12 22:41:31 +00:00
await StepPostCustomPanelPopOut ( ) ;
2022-07-23 19:23:32 +00:00
}
2023-09-02 04:10:40 +00:00
private async Task < bool > StepPreCustomPanelPopOut ( )
2022-07-23 19:23:32 +00:00
{
2023-09-02 04:10:40 +00:00
return await Task . Run ( ( ) = >
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
// Set Windowed Display Mode window's configuration if needed
2024-02-28 02:44:21 +00:00
if ( AppSettingData . ApplicationSetting . WindowedModeSetting . AutoResizeMsfsGameWindow & & WindowActionManager . IsMsfsGameInWindowedMode ( ) )
2022-07-23 19:23:32 +00:00
{
2023-08-16 03:41:14 +00:00
WorkflowStepWithMessage . Execute ( "Moving and resizing MSFS game window" , ( ) = >
{
WindowActionManager . SetMsfsGameWindowLocation ( ActiveProfile . MsfsGameWindowConfig ) ;
Thread . Sleep ( 1000 ) ;
} ) ;
2022-07-23 19:23:32 +00:00
}
2023-07-12 22:41:31 +00:00
2024-02-28 02:44:21 +00:00
// Turn on power and avionics if required to pop out panels at least one (fix Cessna 208b grand caravan mod where battery is reported as on)
2023-07-12 22:41:31 +00:00
if ( ActiveProfile . ProfileSetting . PowerOnRequiredForColdStart )
2022-07-23 19:23:32 +00:00
{
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . TurnOnPower ( ) ;
_flightSimOrchestrator . TurnOnAvionics ( ) ;
2022-07-23 19:23:32 +00:00
}
2023-07-12 22:41:31 +00:00
// Turn off TrackIR if TrackIR is started
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . TurnOffTrackIR ( ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// Turn on Active Pause
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . TurnOnActivePause ( ) ;
2023-08-19 01:44:35 +00:00
2023-07-12 22:41:31 +00:00
// Setting custom camera angle for auto panning
2024-02-28 02:44:21 +00:00
if ( AppSetting . PopOutSetting . AutoPanning . IsEnabled & & ActiveProfile . IsUsedLegacyCameraSystem )
2023-07-12 22:41:31 +00:00
{
2023-08-16 03:41:14 +00:00
StatusMessageWriter . WriteMessageWithNewLine ( "Setting auto panning camera view" , StatusMessageType . Info ) ;
2023-08-16 17:13:39 +00:00
2024-02-28 02:44:21 +00:00
if ( FlightSimData . CameraViewTypeAndIndex1 = = CAMERA_VIEW_HOME_COCKPIT_MODE )
2023-08-16 03:41:14 +00:00
{
2024-02-28 02:44:21 +00:00
SetCockpitZoomLevel ( ProfileData . ActiveProfile . PanelSourceCockpitZoomFactor , AppSetting . GeneralSetting . TurboMode ) ;
2023-08-16 17:13:39 +00:00
}
else
2023-08-16 03:41:14 +00:00
{
2024-02-28 02:44:21 +00:00
WorkflowStepWithMessage . Execute ( "Resetting camera view" , ( ) = > ResetCockpitView ( AppSetting . GeneralSetting . TurboMode ) , true ) ;
2023-08-16 17:13:39 +00:00
2024-02-28 02:44:21 +00:00
var success = WorkflowStepWithMessage . Execute ( "Loading custom camera view" , ( ) = > LoadCustomView ( AppSetting . PopOutSetting . AutoPanning . KeyBinding , AppSetting . GeneralSetting . TurboMode , false ) , true ) ;
2023-09-02 04:10:40 +00:00
if ( ! success )
return false ;
2024-02-28 02:44:21 +00:00
WorkflowStepWithMessage . Execute ( "Setting camera zoom level" , ( ) = > SetCockpitZoomLevel ( 50 , AppSetting . GeneralSetting . TurboMode ) , true ) ;
2023-08-16 17:13:39 +00:00
}
2023-07-12 22:41:31 +00:00
}
2023-09-02 04:10:40 +00:00
return true ;
2023-07-12 22:41:31 +00:00
} ) ;
2022-07-23 19:23:32 +00:00
}
2023-07-12 22:41:31 +00:00
private async Task StepCustomPanelPopOut ( List < IntPtr > builtInPanelHandles )
2022-09-06 04:07:03 +00:00
{
2023-07-12 22:41:31 +00:00
await Task . Run ( ( ) = >
2022-09-06 04:07:03 +00:00
{
2023-07-12 22:41:31 +00:00
// Save current application location to restore it after pop out
var appLocation = WindowActionManager . GetWindowRectangle ( WindowProcessManager . GetApplicationProcess ( ) . Handle ) ;
2022-09-06 04:07:03 +00:00
2023-08-16 03:41:14 +00:00
if ( ActiveProfile . PanelConfigs . Count > 0 )
StatusMessageWriter . WriteMessageWithNewLine ( "Popping out user defined panels" , StatusMessageType . Info ) ;
2024-02-28 02:44:21 +00:00
// Resetting camera to default first
if ( ! ActiveProfile . IsUsedLegacyCameraSystem )
{
_flightSimOrchestrator . ResetCameraView ( ) ;
Thread . Sleep ( 250 ) ;
}
2023-07-12 22:41:31 +00:00
int index = 0 ;
foreach ( var panelConfig in ActiveProfile . PanelConfigs )
2022-09-06 04:07:03 +00:00
{
2023-07-12 22:41:31 +00:00
if ( panelConfig . PanelType = = PanelType . CustomPopout )
{
2023-08-16 03:41:14 +00:00
WorkflowStepWithMessage . Execute ( panelConfig . PanelName , ( ) = >
{
2024-02-28 02:44:21 +00:00
if ( ! ActiveProfile . IsUsedLegacyCameraSystem )
_flightSimOrchestrator . SetFixedCamera ( panelConfig . FixedCameraConfig . CameraType , panelConfig . FixedCameraConfig . CameraIndex ) ;
2023-08-16 03:41:14 +00:00
panelConfig . IsSelectedPanelSource = true ;
2023-11-05 02:10:03 +00:00
2024-02-28 02:44:21 +00:00
if ( panelConfig . PanelSource . X ! = null & & panelConfig . PanelSource . Y ! = null )
InputEmulationManager . PrepareToPopOutPanel ( ( int ) panelConfig . PanelSource . X , ( int ) panelConfig . PanelSource . Y , AppSetting . GeneralSetting . TurboMode ) ;
2023-11-05 02:10:03 +00:00
ExecuteCustomPopout ( panelConfig , builtInPanelHandles , index + + ) ;
2023-09-29 06:15:02 +00:00
2023-08-16 03:41:14 +00:00
ApplyPanelLocation ( panelConfig ) ;
panelConfig . IsSelectedPanelSource = false ;
if ( panelConfig . IsPopOutSuccess ! = null & & ! ( bool ) panelConfig . IsPopOutSuccess )
return false ;
else
return true ;
} , true ) ;
2023-07-12 22:41:31 +00:00
}
}
2022-09-06 04:07:03 +00:00
2023-07-12 22:41:31 +00:00
// Restore current application location
WindowActionManager . MoveWindow ( WindowProcessManager . GetApplicationProcess ( ) . Handle , appLocation ) ;
} ) ;
2022-09-06 04:07:03 +00:00
}
2023-07-12 22:41:31 +00:00
private async Task StepPostCustomPanelPopOut ( )
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
await Task . Run ( ( ) = >
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
if ( ActiveProfile . ProfileSetting . PowerOnRequiredForColdStart )
{
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . TurnOffAvionics ( ) ;
_flightSimOrchestrator . TurnOffPower ( ) ;
2023-07-12 22:41:31 +00:00
}
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// Turn TrackIR back on
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . TurnOnTrackIR ( ) ;
2023-08-16 06:42:18 +00:00
Thread . Sleep ( 500 ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// Turn on Active Pause
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . TurnOffActivePause ( ) ;
2023-08-16 06:42:18 +00:00
Thread . Sleep ( 500 ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// Return to custom camera view if set
2023-08-16 03:41:14 +00:00
ReturnToAfterPopOutCameraView ( ) ;
2023-07-12 22:41:31 +00:00
} ) ;
}
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
private void StepAddBuiltInPanels ( List < IntPtr > builtInPanelHandles )
{
if ( ActiveProfile . ProfileSetting . IncludeInGamePanels )
{
2023-08-16 03:41:14 +00:00
WorkflowStepWithMessage . Execute ( "Configuring built-in panel" , ( ) = >
2023-07-12 22:41:31 +00:00
{
2024-02-28 02:44:21 +00:00
var count = 0 ;
2023-08-16 03:41:14 +00:00
while ( builtInPanelHandles . Count = = 0 & & count < 5 )
{
builtInPanelHandles = WindowActionManager . GetWindowsByPanelType ( new List < PanelType > ( ) { PanelType . BuiltInPopout } ) ;
2023-09-05 00:55:45 +00:00
count + + ;
2023-08-16 03:41:14 +00:00
}
2023-07-12 22:41:31 +00:00
2023-08-16 03:41:14 +00:00
foreach ( var panelHandle in builtInPanelHandles )
2022-07-23 19:23:32 +00:00
{
2023-08-16 03:41:14 +00:00
var panelCaption = WindowActionManager . GetWindowCaption ( panelHandle ) ;
var panelConfig = ActiveProfile . PanelConfigs . FirstOrDefault ( p = > p . PanelName = = panelCaption ) ;
if ( panelConfig = = null )
2022-07-23 19:23:32 +00:00
{
2023-08-16 03:41:14 +00:00
if ( ! ActiveProfile . IsLocked )
2022-07-23 19:23:32 +00:00
{
2023-08-16 03:41:14 +00:00
var rectangle = WindowActionManager . GetWindowRectangle ( panelHandle ) ;
panelConfig = new PanelConfig ( )
{
PanelHandle = panelHandle ,
PanelType = PanelType . BuiltInPopout ,
PanelName = panelCaption ,
Top = rectangle . Top ,
Left = rectangle . Left ,
Width = rectangle . Width ,
Height = rectangle . Height ,
AutoGameRefocus = false
} ;
ActiveProfile . PanelConfigs . Add ( panelConfig ) ;
}
2022-07-23 19:23:32 +00:00
}
2023-08-16 03:41:14 +00:00
else
{
panelConfig . PanelHandle = panelHandle ;
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
// Need to do it twice for MSFS to take this setting (MSFS issue)
2023-08-16 03:41:14 +00:00
ApplyPanelLocation ( panelConfig ) ;
ApplyPanelLocation ( panelConfig ) ;
}
2023-07-12 22:41:31 +00:00
}
2022-07-23 19:23:32 +00:00
2023-08-16 03:41:14 +00:00
// Set handles for missing built-in panels
foreach ( var panelConfig in ActiveProfile . PanelConfigs )
{
if ( panelConfig . PanelType = = PanelType . BuiltInPopout & & panelConfig . PanelHandle = = IntPtr . MaxValue )
panelConfig . PanelHandle = IntPtr . Zero ;
}
2022-07-23 19:23:32 +00:00
2024-03-05 03:01:13 +00:00
return ! ActiveProfile . PanelConfigs . Any ( p = > p . PanelType = = PanelType . BuiltInPopout & & p . IsPopOutSuccess ! = null & & ! ( bool ) p . IsPopOutSuccess ) & &
ActiveProfile . PanelConfigs . Count ( p = > p . PanelType = = PanelType . BuiltInPopout ) ! = 0 ;
2023-08-16 03:41:14 +00:00
} ) ;
2023-07-12 22:41:31 +00:00
}
2022-07-23 19:23:32 +00:00
}
2023-07-12 22:41:31 +00:00
private void StepAddHudBar ( )
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
if ( ! ActiveProfile . ProfileSetting . HudBarConfig . IsEnabled )
return ;
2023-08-16 03:41:14 +00:00
WorkflowStepWithMessage . Execute ( "Opening HUD Bar" , ( ) = >
{
var panelConfig = ActiveProfile . PanelConfigs . FirstOrDefault ( p = > p . PanelType = = PanelType . HudBarWindow ) ;
OnHudBarOpened ? . Invoke ( this , panelConfig ) ;
} ) ;
2023-07-12 22:41:31 +00:00
}
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
private void StepAddNumPad ( )
{
if ( ! ActiveProfile . ProfileSetting . NumPadConfig . IsEnabled )
return ;
WorkflowStepWithMessage . Execute ( "Opening Virtual NumPad" , ( ) = >
{
var panelConfig = ActiveProfile . PanelConfigs . FirstOrDefault ( p = > p . PanelType = = PanelType . NumPadWindow ) ;
OnNumPadOpened ? . Invoke ( this , panelConfig ) ;
} ) ;
}
2023-07-23 05:13:23 +00:00
public void SetupRefocusDisplay ( )
{
if ( ! ActiveProfile . ProfileSetting . RefocusOnDisplay . IsEnabled )
return ;
2024-02-28 02:44:21 +00:00
var panelConfigs = ActiveProfile . PanelConfigs . Where ( p = > p . PanelType = = PanelType . RefocusDisplay ) . ToList ( ) ;
2023-08-16 03:41:14 +00:00
2024-02-28 02:44:21 +00:00
if ( panelConfigs . Count = = 0 )
2023-08-16 03:41:14 +00:00
return ;
2024-02-28 02:44:21 +00:00
StatusMessageWriter . WriteMessageWithNewLine ( "Configuring monitors for auto refocus on touch" , StatusMessageType . Info ) ;
2023-08-16 03:41:14 +00:00
foreach ( var panelConfig in panelConfigs )
2024-02-28 02:44:21 +00:00
WorkflowStepWithMessage . Execute ( panelConfig . PanelName , ( ) = > panelConfig . PanelHandle = new IntPtr ( 1 ) , true ) ;
2023-07-23 05:13:23 +00:00
}
2023-07-12 22:41:31 +00:00
private void StepApplyPanelConfig ( )
{
// Must apply other panel config after pop out since MSFS popping out action will overwrite panel config such as Always on Top
foreach ( var panelConfig in ActiveProfile . PanelConfigs )
{
ApplyPanelConfig ( panelConfig ) ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// Set title bar color
2024-02-28 02:44:21 +00:00
if ( AppSettingData . ApplicationSetting . PopOutSetting . PopOutTitleBarCustomization . IsEnabled & & ! panelConfig . FullScreen )
2022-07-23 19:23:32 +00:00
{
2024-02-28 02:44:21 +00:00
WindowActionManager . SetWindowTitleBarColor ( panelConfig . PanelHandle , AppSettingData . ApplicationSetting . PopOutSetting . PopOutTitleBarCustomization . HexColor ) ;
2022-07-23 19:23:32 +00:00
}
2023-07-12 22:41:31 +00:00
}
}
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
private async Task StepPostPopout ( )
{
await Task . Run ( ( ) = >
{
// Set profile pop out status
ActiveProfile . IsPoppedOut = true ;
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
// Must use application dispatcher to dispatch UI events (winEventHook)
2024-02-28 02:44:21 +00:00
_panelConfigurationOrchestrator . StartConfiguration ( ) ;
2022-09-06 04:07:03 +00:00
2023-07-12 22:41:31 +00:00
// Start touch hook
2024-02-28 02:44:21 +00:00
_panelConfigurationOrchestrator . StartTouchHook ( ) ;
2022-07-23 19:23:32 +00:00
2024-02-28 02:44:21 +00:00
StatusMessageWriter . WriteMessageWithNewLine (
CheckForPopOutError ( )
? "Pop out has been completed with error."
: "Pop out has been completed successfully." , StatusMessageType . Info ) ;
2023-08-17 06:03:17 +00:00
Thread . Sleep ( 1000 ) ;
2022-07-23 19:23:32 +00:00
} ) ;
2023-07-12 22:41:31 +00:00
}
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
private void ExecuteCustomPopout ( PanelConfig panel , List < IntPtr > builtInPanelHandles , int index )
{
2023-09-29 06:15:02 +00:00
// There should only be one handle that is not in both builtInPanelHandles vs latestAceAppWindowsWithCaptionHandles
var handle = TryPopOutCustomPanel ( panel . PanelSource , builtInPanelHandles , AppSetting . GeneralSetting . TurboMode ) ;
2022-10-16 13:11:01 +00:00
2023-09-29 06:15:02 +00:00
if ( handle = = IntPtr . Zero )
{
panel . PanelHandle = IntPtr . Zero ;
return ;
}
2022-09-11 13:50:04 +00:00
2023-09-29 06:15:02 +00:00
// Unable to pop out panel, the handle was previously popped out's handle
2024-02-28 02:44:21 +00:00
if ( ProfileData . ActiveProfile . PanelConfigs . Any ( p = > p . PanelHandle . Equals ( handle ) ) | | handle . Equals ( WindowProcessManager . SimulatorProcess . Handle ) | | handle = = IntPtr . Zero )
2023-09-29 06:15:02 +00:00
{
panel . PanelHandle = IntPtr . Zero ;
return ;
}
2022-09-11 13:50:04 +00:00
2023-09-29 06:15:02 +00:00
panel . PanelHandle = handle ;
WindowActionManager . SetWindowCaption ( panel . PanelHandle , $"{panel.PanelName} (Custom)" ) ;
2023-07-12 22:41:31 +00:00
2023-09-29 06:15:02 +00:00
// First time popping out
if ( panel . Width = = 0 & & panel . Height = = 0 )
{
var rect = WindowActionManager . GetWindowRectangle ( panel . PanelHandle ) ;
panel . Top = 0 + index * 30 ;
panel . Left = 0 + index * 30 ;
panel . Width = rect . Width ;
panel . Height = rect . Height ;
2022-09-11 13:50:04 +00:00
}
2023-07-12 22:41:31 +00:00
}
2023-09-29 06:15:02 +00:00
private IntPtr TryPopOutCustomPanel ( PanelSource panelSource , List < IntPtr > builtInPanelHandles , bool isTurbo )
2023-07-12 22:41:31 +00:00
{
2023-09-29 06:15:02 +00:00
// Try to pop out 5 times before failure with 1/2 second wait in between
2023-07-12 22:41:31 +00:00
int count = 0 ;
do
{
2024-02-28 02:44:21 +00:00
if ( panelSource . X ! = null & & panelSource . Y ! = null )
InputEmulationManager . PopOutPanel ( ( int ) panelSource . X , ( int ) panelSource . Y , AppSetting . PopOutSetting . UseLeftRightControlToPopOut , isTurbo ) ;
2023-09-29 06:15:02 +00:00
2023-07-12 22:41:31 +00:00
var latestAceAppWindowsWithCaptionHandles = WindowActionManager . GetWindowsByPanelType ( new List < PanelType > ( ) { PanelType . BuiltInPopout } ) ;
// There should only be one handle that is not in both builtInPanelHandles vs latestAceAppWindowsWithCaptionHandles
var handle = latestAceAppWindowsWithCaptionHandles . Except ( builtInPanelHandles ) . FirstOrDefault ( ) ;
if ( handle ! = IntPtr . Zero )
return handle ;
2023-09-10 16:19:41 +00:00
Thread . Sleep ( 500 ) ;
2023-07-12 22:41:31 +00:00
count + + ;
}
2023-09-29 06:15:02 +00:00
while ( count < 5 ) ;
2023-07-12 22:41:31 +00:00
return IntPtr . Zero ;
}
private void ApplyPanelLocation ( PanelConfig panel )
{
if ( panel . IsPopOutSuccess = = null | | ! ( ( bool ) panel . IsPopOutSuccess ) | | panel . PanelHandle = = IntPtr . Zero )
return ;
// Apply top/left/width/height
WindowActionManager . MoveWindow ( panel . PanelHandle , panel . Left , panel . Top , panel . Width , panel . Height ) ;
}
private void ApplyPanelConfig ( PanelConfig panel )
{
if ( panel . IsPopOutSuccess = = null | | ! ( ( bool ) panel . IsPopOutSuccess ) | | panel . PanelHandle = = IntPtr . Zero )
return ;
2022-09-11 13:50:04 +00:00
2023-07-12 22:41:31 +00:00
if ( ! panel . FullScreen )
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
// Apply always on top
if ( panel . AlwaysOnTop )
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
WindowActionManager . ApplyAlwaysOnTop ( panel . PanelHandle , panel . PanelType , panel . AlwaysOnTop ) ;
2022-07-23 19:23:32 +00:00
Thread . Sleep ( 250 ) ;
2023-07-12 22:41:31 +00:00
}
2022-09-11 13:50:04 +00:00
2023-07-12 22:41:31 +00:00
// Apply hide title bar
if ( panel . HideTitlebar )
{
WindowActionManager . ApplyHidePanelTitleBar ( panel . PanelHandle , true ) ;
Thread . Sleep ( 250 ) ;
2022-07-23 19:23:32 +00:00
}
2023-07-12 22:41:31 +00:00
}
if ( panel . FullScreen & & ! panel . AlwaysOnTop & & ! panel . HideTitlebar )
{
Thread . Sleep ( 500 ) ;
InputEmulationManager . ToggleFullScreenPanel ( panel . PanelHandle ) ;
Thread . Sleep ( 250 ) ;
}
2024-03-05 03:01:13 +00:00
if ( panel . FloatingPanel . IsEnabled & & panel . FloatingPanel . HasKeyboardBinding & & panel . FloatingPanel . IsHiddenOnStart )
{
panel . IsFloating = false ;
WindowActionManager . MinimizeWindow ( panel . PanelHandle ) ;
}
2022-07-23 19:23:32 +00:00
}
private void ReturnToAfterPopOutCameraView ( )
{
2023-07-12 22:41:31 +00:00
if ( ! AppSetting . PopOutSetting . AfterPopOutCameraView . IsEnabled )
2022-07-23 19:23:32 +00:00
return ;
2023-08-16 03:41:14 +00:00
StatusMessageWriter . WriteMessageWithNewLine ( "Applying cockpit view after pop out" , StatusMessageType . Info ) ;
2024-02-28 02:44:21 +00:00
if ( FlightSimData . CameraViewTypeAndIndex1 = = CAMERA_VIEW_HOME_COCKPIT_MODE )
2022-07-23 19:23:32 +00:00
{
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . ResetCameraView ( ) ;
2023-08-16 17:13:39 +00:00
}
else
{
switch ( AppSetting . PopOutSetting . AfterPopOutCameraView . CameraView )
{
case AfterPopOutCameraViewType . CockpitCenterView :
2024-02-28 02:44:21 +00:00
WorkflowStepWithMessage . Execute ( "Resetting camera view" , ( ) = > ResetCockpitView ( AppSetting . GeneralSetting . TurboMode ) , true ) ;
2023-08-16 17:13:39 +00:00
break ;
case AfterPopOutCameraViewType . CustomCameraView :
2024-02-28 02:44:21 +00:00
WorkflowStepWithMessage . Execute ( "Resetting camera view" , ( ) = > ResetCockpitView ( AppSetting . GeneralSetting . TurboMode ) , true ) ;
WorkflowStepWithMessage . Execute ( "Loading custom camera view" , ( ) = > LoadCustomView ( AppSetting . PopOutSetting . AfterPopOutCameraView . KeyBinding , AppSetting . GeneralSetting . TurboMode , true ) , true ) ;
2023-08-16 17:13:39 +00:00
break ;
}
2022-07-23 19:23:32 +00:00
}
}
2023-07-12 22:41:31 +00:00
private bool CheckForPopOutError ( )
{
return ActiveProfile . PanelConfigs . Count ( p = > p . IsPopOutSuccess ! = null & & ( bool ) p . IsPopOutSuccess ) ! = ActiveProfile . PanelConfigs . Count ( p = > p . IsPopOutSuccess ! = null ) ;
}
2023-08-14 04:35:14 +00:00
2023-09-29 06:15:02 +00:00
private void ResetCockpitView ( bool isTurboMode )
2023-08-16 03:41:14 +00:00
{
2024-02-28 02:44:21 +00:00
const int retry = 5 ;
2023-08-16 03:41:14 +00:00
for ( var i = 0 ; i < retry ; i + + )
{
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . ResetCameraView ( ) ;
2023-09-29 06:15:02 +00:00
Thread . Sleep ( isTurboMode ? 600 : 1000 ) ; // wait for flightsimdata to be updated
2024-02-28 02:44:21 +00:00
if ( FlightSimData . CameraViewTypeAndIndex1 is 0 or 1 )
2023-08-16 03:41:14 +00:00
break ;
}
}
2024-02-28 02:44:21 +00:00
private bool LoadCustomView ( string keyBinding , bool isTurboMode , bool ignoreError )
2023-08-14 04:35:14 +00:00
{
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . ResetCameraView ( ) ;
Thread . Sleep ( 250 ) ;
const int retry = 5 ;
2023-08-14 04:35:14 +00:00
for ( var i = 0 ; i < retry ; i + + )
{
2024-02-28 02:44:21 +00:00
InputEmulationManager . LoadCustomView ( keyBinding ) ;
Thread . Sleep ( isTurboMode ? 1000 : 1200 ) ; // wait for flightsimdata to be updated
if ( FlightSimData . CameraViewTypeAndIndex1 = = CAMERA_VIEW_CUSTOM_CAMERA ) // custom camera view enum
2023-09-02 04:10:40 +00:00
return true ;
2023-08-14 04:35:14 +00:00
}
2023-09-02 04:10:40 +00:00
2023-11-05 02:10:03 +00:00
return ignoreError ;
2023-08-14 04:35:14 +00:00
}
2023-08-14 06:29:30 +00:00
2023-09-29 06:15:02 +00:00
private void SetCockpitZoomLevel ( int zoom , bool isTurboMode )
2023-08-14 06:29:30 +00:00
{
2024-02-28 02:44:21 +00:00
const int retry = 10 ;
2023-08-14 06:29:30 +00:00
for ( var i = 0 ; i < retry ; i + + )
{
2024-02-28 02:44:21 +00:00
_flightSimOrchestrator . SetCockpitCameraZoomLevel ( zoom ) ;
2023-09-29 06:15:02 +00:00
Thread . Sleep ( isTurboMode ? 600 : 1000 ) ; // wait for flightsimdata to be updated
2023-08-14 06:29:30 +00:00
2024-02-28 02:44:21 +00:00
if ( FlightSimData . CockpitCameraZoom = = zoom )
2023-08-14 06:29:30 +00:00
break ;
}
}
2022-07-23 19:23:32 +00:00
}
}