2023-07-12 22:41:31 +00:00
using MSFSPopoutPanelManager.DomainModel.Profile ;
using MSFSPopoutPanelManager.DomainModel.Setting ;
using System ;
using System.Diagnostics ;
using System.Linq ;
using System.Threading ;
namespace MSFSPopoutPanelManager.WindowsAgent
{
public class WindowEventManager
{
private static PInvoke . WinEventProc _winEvent ; // keep this as static to prevent garbage collect or the app will crash
private static IntPtr _winEventHook ;
private static int? _prevShowWinCmd ;
public static UserProfile ActiveProfile { private get ; set ; }
public static ApplicationSetting ApplicationSetting { private get ; set ; }
public static void HookWinEvent ( )
{
if ( ActiveProfile = = null | | ActiveProfile . PanelConfigs = = null )
return ;
UnhookWinEvent ( ) ;
Debug . WriteLine ( "Executing HookWinEvent()..." ) ;
2024-02-28 02:44:21 +00:00
var isRequiredPanelConfiguration = false ;
var isUsedNonTouchPanelRefocusLogic = false ;
2023-07-12 22:41:31 +00:00
if ( ( ! ActiveProfile . IsLocked | | ( ActiveProfile . IsLocked & & ApplicationSetting . PopOutSetting . EnablePanelResetWhenLocked ) )
& & ActiveProfile . PanelConfigs . Any ( p = > p . IsPopOutSuccess ! = null & & ( bool ) p . IsPopOutSuccess ) )
isRequiredPanelConfiguration = true ;
if ( ActiveProfile . PanelConfigs . Any ( p = > p . AutoGameRefocus & & ! p . TouchEnabled & & p . IsPopOutSuccess ! = null & & ( bool ) p . IsPopOutSuccess )
& & ! ActiveProfile . PanelConfigs . All ( p = > p . TouchEnabled )
& & ApplicationSetting . RefocusSetting . RefocusGameWindow . IsEnabled )
2024-02-28 02:44:21 +00:00
isUsedNonTouchPanelRefocusLogic = true ;
2023-07-12 22:41:31 +00:00
uint winEventMin , winEventMax ;
2024-02-28 02:44:21 +00:00
if ( isRequiredPanelConfiguration & & isUsedNonTouchPanelRefocusLogic )
2023-07-12 22:41:31 +00:00
{
winEventMin = PInvokeConstant . EVENT_SYSTEM_CAPTURESTART ;
winEventMax = PInvokeConstant . EVENT_OBJECT_STATECHANGE ;
}
else if ( isRequiredPanelConfiguration )
{
winEventMin = PInvokeConstant . EVENT_SYSTEM_MOVESIZEEND ;
winEventMax = PInvokeConstant . EVENT_OBJECT_STATECHANGE ;
}
2024-02-28 02:44:21 +00:00
else if ( isUsedNonTouchPanelRefocusLogic )
2023-07-12 22:41:31 +00:00
{
winEventMin = PInvokeConstant . EVENT_SYSTEM_CAPTURESTART ;
winEventMax = PInvokeConstant . EVENT_SYSTEM_CAPTUREEND ;
}
else
{
return ;
}
2024-02-28 02:44:21 +00:00
_winEvent = EventCallback ;
2023-07-12 22:41:31 +00:00
_winEventHook = PInvoke . SetWinEventHook ( winEventMin , winEventMax , IntPtr . Zero , _winEvent , 0 , 0 , PInvokeConstant . WINEVENT_OUTOFCONTEXT ) ;
Debug . WriteLine ( $"WinEventMin: {winEventMin} WinEventMax: {winEventMax}" ) ;
}
public static void UnhookWinEvent ( )
{
_prevShowWinCmd = null ;
// Unhook all Win API events
2024-02-28 02:44:21 +00:00
if ( _winEventHook = = IntPtr . Zero )
return ;
Debug . WriteLine ( "Executing UnhookWinEvent()..." ) ;
PInvoke . UnhookWinEvent ( _winEventHook ) ;
2023-07-12 22:41:31 +00:00
}
private static void EventCallback ( IntPtr hWinEventHook , uint iEvent , IntPtr hwnd , int idObject , int idChild , int dwEventThread , int dwmsEventTime )
{
switch ( iEvent )
{
case PInvokeConstant . EVENT_SYSTEM_MOVESIZEEND :
case PInvokeConstant . EVENT_SYSTEM_CAPTURESTART :
case PInvokeConstant . EVENT_SYSTEM_CAPTUREEND :
if ( hwnd = = IntPtr . Zero | | idObject ! = 0 | | hWinEventHook ! = _winEventHook ) // check by priority to speed up comparing of escaping constraints
return ;
HandleEventCallback ( hwnd , iEvent ) ;
break ;
case PInvokeConstant . EVENT_OBJECT_STATECHANGE :
if ( hwnd = = IntPtr . Zero | | hWinEventHook ! = _winEventHook )
return ;
HandleEventCallback ( hwnd , iEvent ) ;
break ;
}
}
private static void HandleEventCallback ( IntPtr hwnd , uint iEvent )
{
var panelConfig = ActiveProfile . PanelConfigs . FirstOrDefault ( panel = > panel . PanelHandle = = hwnd ) ;
if ( panelConfig = = null ) // Should not apply any other settings if panel is full screen mode
return ;
switch ( iEvent )
{
case PInvokeConstant . EVENT_OBJECT_STATECHANGE :
if ( ! ActiveProfile . IsLocked )
{
Thread . Sleep ( 300 ) ;
UpdatePanelCoordinates ( panelConfig ) ;
}
else
{
2023-09-08 15:12:47 +00:00
// Pop out is closed
var rect = WindowActionManager . GetWindowRectangle ( panelConfig . PanelHandle ) ;
2024-02-28 02:44:21 +00:00
if ( rect is { Width : 0 , Height : 0 } )
2023-09-08 15:12:47 +00:00
{
panelConfig . PanelHandle = IntPtr . MaxValue ;
_prevShowWinCmd = null ;
return ;
}
2024-02-28 02:44:21 +00:00
var wp = new WINDOWPLACEMENT ( ) ;
2023-07-12 22:41:31 +00:00
wp . length = System . Runtime . InteropServices . Marshal . SizeOf ( wp ) ;
PInvoke . GetWindowPlacement ( hwnd , ref wp ) ;
if ( _prevShowWinCmd = = null )
{
_prevShowWinCmd = wp . showCmd ;
Thread . Sleep ( 250 ) ;
break ;
}
2024-02-28 02:44:21 +00:00
switch ( wp . showCmd )
{
case PInvokeConstant . SW_SHOWMAXIMIZED when _prevShowWinCmd = = PInvokeConstant . SW_SHOWNORMAL :
PInvoke . ShowWindow ( hwnd , PInvokeConstant . SW_RESTORE ) ;
break ;
case PInvokeConstant . SW_SHOWMAXIMIZED when _prevShowWinCmd = = PInvokeConstant . SW_SHOWMINIMIZED :
PInvoke . ShowWindow ( hwnd , PInvokeConstant . SW_SHOWMINIMIZED ) ;
break ;
case PInvokeConstant . SW_SHOWMINIMIZED when _prevShowWinCmd = = PInvokeConstant . SW_SHOWNORMAL :
PInvoke . ShowWindow ( hwnd , PInvokeConstant . SW_RESTORE ) ;
break ;
case PInvokeConstant . SW_SHOWMINIMIZED when _prevShowWinCmd = = PInvokeConstant . SW_SHOWMAXIMIZED :
case PInvokeConstant . SW_SHOWNORMAL when _prevShowWinCmd = = PInvokeConstant . SW_SHOWMAXIMIZED :
PInvoke . ShowWindow ( hwnd , PInvokeConstant . SW_SHOWMAXIMIZED ) ;
break ;
case PInvokeConstant . SW_SHOWNORMAL when _prevShowWinCmd = = PInvokeConstant . SW_SHOWMINIMIZED :
PInvoke . ShowWindow ( hwnd , PInvokeConstant . SW_SHOWMINIMIZED ) ;
break ;
case PInvokeConstant . SW_SHOWNORMAL when _prevShowWinCmd = = PInvokeConstant . SW_SHOWNORMAL :
WindowActionManager . MoveWindow ( panelConfig . PanelHandle , panelConfig . Left , panelConfig . Top , panelConfig . Width , panelConfig . Height ) ;
break ;
}
2023-07-12 22:41:31 +00:00
_prevShowWinCmd = null ;
}
break ;
case PInvokeConstant . EVENT_SYSTEM_MOVESIZEEND :
if ( ActiveProfile . IsLocked )
WindowActionManager . MoveWindow ( panelConfig . PanelHandle , panelConfig . Left , panelConfig . Top , panelConfig . Width , panelConfig . Height ) ; // Move window back to original location
else
UpdatePanelCoordinates ( panelConfig ) ;
break ;
case PInvokeConstant . EVENT_SYSTEM_CAPTURESTART :
GameRefocusManager . HandleMouseDownEvent ( panelConfig ) ;
break ;
case PInvokeConstant . EVENT_SYSTEM_CAPTUREEND :
GameRefocusManager . HandleMouseUpEvent ( panelConfig ) ;
break ;
}
}
private static void UpdatePanelCoordinates ( PanelConfig panelConfig )
{
var rect = WindowActionManager . GetWindowRectangle ( panelConfig . PanelHandle ) ;
2023-09-08 15:12:47 +00:00
2024-02-28 02:44:21 +00:00
if ( rect is { Width : 0 , Height : 0 } ) // don't set if width and height = 0
2023-09-08 15:12:47 +00:00
{
panelConfig . PanelHandle = IntPtr . MaxValue ;
return ;
}
2023-07-12 22:41:31 +00:00
panelConfig . Left = rect . Left ;
panelConfig . Top = rect . Top ;
2023-07-21 21:45:16 +00:00
if ( panelConfig . PanelType = = PanelType . HudBarWindow )
return ;
2023-07-12 22:41:31 +00:00
panelConfig . Width = rect . Width ;
panelConfig . Height = rect . Height ;
}
}
}