1
0
Fork 0
mirror of https://github.com/hawkeye-stan/msfs-popout-panel-manager.git synced 2024-11-23 22:30:09 +00:00

Add display refocus

This commit is contained in:
hawkeye 2023-07-23 01:13:23 -04:00
parent cb3eaa1466
commit 836e127fa6
19 changed files with 348 additions and 75 deletions

View file

@ -0,0 +1,26 @@
using MSFSPopoutPanelManager.Shared;
namespace MSFSPopoutPanelManager.DomainModel.Profile
{
public class MonitorInfo : ObservableObject
{
public MonitorInfo()
{
IsSelected = false;
InitializeChildPropertyChangeBinding();
}
public string Name { get; set; }
public bool IsSelected { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
}

View file

@ -10,6 +10,7 @@
MultiMonitorWindow = 5, MultiMonitorWindow = 5,
PanelSourceWindow = 6, PanelSourceWindow = 6,
StatusMessageWindow = 7, StatusMessageWindow = 7,
RefocusDisplay = 8,
Unknown = 100 Unknown = 100
} }
} }

View file

@ -7,6 +7,7 @@ namespace MSFSPopoutPanelManager.DomainModel.Profile
public ProfileSetting() public ProfileSetting()
{ {
HudBarConfig = new HudBarConfig(); HudBarConfig = new HudBarConfig();
RefocusOnDisplay = new RefocusOnDisplay();
InitializeChildPropertyChangeBinding(); InitializeChildPropertyChangeBinding();
} }
@ -16,5 +17,7 @@ namespace MSFSPopoutPanelManager.DomainModel.Profile
public bool IncludeInGamePanels { get; set; } public bool IncludeInGamePanels { get; set; }
public HudBarConfig HudBarConfig { get; set; } public HudBarConfig HudBarConfig { get; set; }
public RefocusOnDisplay RefocusOnDisplay { get; set; }
} }
} }

View file

@ -0,0 +1,47 @@
using MSFSPopoutPanelManager.Shared;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace MSFSPopoutPanelManager.DomainModel.Profile
{
public class RefocusOnDisplay : ObservableObject
{
public RefocusOnDisplay()
{
IsEnabled = false;
Monitors = new ObservableCollection<MonitorInfo>();
Monitors.CollectionChanged += (sender, e) =>
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
if (e.NewItems[0] == null)
return;
((MonitorInfo)e.NewItems[0]).PropertyChanged += (sender, e) =>
{
var evtArg = e as PropertyChangedExtendedEventArgs;
if (!evtArg.DisableSave)
base.OnPropertyChanged(sender, e);
};
base.OnPropertyChanged(sender, new PropertyChangedEventArgs("Monitors"));
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
case System.Collections.Specialized.NotifyCollectionChangedAction.Move:
case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
base.OnPropertyChanged(sender, new PropertyChangedEventArgs("Monitors"));
break;
}
};
InitializeChildPropertyChangeBinding();
}
public bool IsEnabled { get; set; }
public ObservableCollection<MonitorInfo> Monitors { get; set; }
}
}

View file

@ -32,13 +32,16 @@
Background="Transparent" Background="Transparent"
DialogTheme="Inherit" DialogTheme="Inherit"
Identifier="RootDialog"> Identifier="RootDialog">
<materialDesign:DrawerHost OverlayBackground="Transparent" RightDrawerCornerRadius="15"> <materialDesign:DrawerHost
OpenMode="Standard"
OverlayBackground="Transparent"
RightDrawerCornerRadius="15">
<materialDesign:DrawerHost.RightDrawerContent> <materialDesign:DrawerHost.RightDrawerContent>
<DockPanel> <DockPanel>
<Button <Button
Width="{StaticResource IconSize}" Width="{StaticResource IconSize}"
Height="{StaticResource IconSize}" Height="{StaticResource IconSize}"
Margin="8,8,12,0" Margin="8,8,36,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Command="{x:Static materialDesign:DrawerHost.CloseDrawerCommand}" Command="{x:Static materialDesign:DrawerHost.CloseDrawerCommand}"
DockPanel.Dock="Top" DockPanel.Dock="Top"
@ -48,7 +51,7 @@
Height="{StaticResource IconSize}" Height="{StaticResource IconSize}"
Kind="ArrowRight" /> Kind="ArrowRight" />
</Button> </Button>
<StackPanel Name="panelPreferenceDrawer" /> <StackPanel Name="panelDrawers" />
</DockPanel> </DockPanel>
</materialDesign:DrawerHost.RightDrawerContent> </materialDesign:DrawerHost.RightDrawerContent>
<DockPanel> <DockPanel>

View file

@ -4,11 +4,7 @@ using MSFSPopoutPanelManager.MainApp.ViewModel;
using MSFSPopoutPanelManager.WindowsAgent; using MSFSPopoutPanelManager.WindowsAgent;
using Prism.Commands; using Prism.Commands;
using System; using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Documents;
using System.Windows.Interop; using System.Windows.Interop;
namespace MSFSPopoutPanelManager.MainApp namespace MSFSPopoutPanelManager.MainApp
@ -77,14 +73,14 @@ namespace MSFSPopoutPanelManager.MainApp
private void SettingsButton_Click(object sender, RoutedEventArgs e) private void SettingsButton_Click(object sender, RoutedEventArgs e)
{ {
this.panelPreferenceDrawer.Children.Clear(); this.panelDrawers.Children.Clear();
this.panelPreferenceDrawer.Children.Add(new PreferenceDrawer()); this.panelDrawers.Children.Add(new PreferenceDrawer());
} }
private void HelpButton_Click(object sender, RoutedEventArgs e) private void HelpButton_Click(object sender, RoutedEventArgs e)
{ {
this.panelPreferenceDrawer.Children.Clear(); this.panelDrawers.Children.Clear();
this.panelPreferenceDrawer.Children.Add(new HelpDrawer()); this.panelDrawers.Children.Add(new HelpDrawer());
} }
private void BtnMinimize_Click(object sender, RoutedEventArgs e) private void BtnMinimize_Click(object sender, RoutedEventArgs e)

View file

@ -26,7 +26,7 @@
Kind="ChevronDown" Kind="ChevronDown"
Opacity="0.5" Opacity="0.5"
RenderTransformOrigin="0.5 0.5" RenderTransformOrigin="0.5 0.5"
Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow'}"> Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow and DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}">
<wpf:PackIcon.RenderTransform> <wpf:PackIcon.RenderTransform>
<RotateTransform x:Name="ExpandPathRotateTransform" /> <RotateTransform x:Name="ExpandPathRotateTransform" />
</wpf:PackIcon.RenderTransform> </wpf:PackIcon.RenderTransform>

View file

@ -216,36 +216,38 @@
x:Name="StackPanelAdjustment" x:Name="StackPanelAdjustment"
Width="440" Width="440"
Orientation="Horizontal" Orientation="Horizontal"
Visibility="{c:Binding 'DataItem.PanelType==profileDomain:PanelType.BuiltInPopout or DataItem.PanelType==profileDomain:PanelType.HudBarWindow or DataItem.PanelSource.X != null'}"> Visibility="{c:Binding 'DataItem.PanelType==profileDomain:PanelType.RefocusDisplay or DataItem.PanelType==profileDomain:PanelType.BuiltInPopout or DataItem.PanelType==profileDomain:PanelType.HudBarWindow or DataItem.PanelSource.X != null'}">
<local:PanelConfigField <local:PanelConfigField
Margin="20,0,0,0" Margin="20,0,0,0"
BindingPath="Top" BindingPath="Top"
DataItem="{Binding DataItem}" DataItem="{Binding DataItem}"
IsEnabled="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}"
SourceUpdated="Data_SourceUpdated" /> SourceUpdated="Data_SourceUpdated" />
<local:PanelConfigField <local:PanelConfigField
Margin="20,0,0,0" Margin="20,0,0,0"
BindingPath="Left" BindingPath="Left"
DataItem="{Binding DataItem}" DataItem="{Binding DataItem}"
IsEnabled="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}"
SourceUpdated="Data_SourceUpdated" /> SourceUpdated="Data_SourceUpdated" />
<local:PanelConfigField <local:PanelConfigField
Margin="20,0,0,0" Margin="20,0,0,0"
BindingPath="Width" BindingPath="Width"
DataItem="{Binding DataItem}" DataItem="{Binding DataItem}"
IsEnabled="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow'}" IsEnabled="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow and DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}"
SourceUpdated="Data_SourceUpdated" /> SourceUpdated="Data_SourceUpdated" />
<local:PanelConfigField <local:PanelConfigField
Margin="20,0,0,0" Margin="20,0,0,0"
BindingPath="Height" BindingPath="Height"
DataItem="{Binding DataItem}" DataItem="{Binding DataItem}"
IsEnabled="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow'}" IsEnabled="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow and DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}"
SourceUpdated="Data_SourceUpdated" /> SourceUpdated="Data_SourceUpdated" />
<local:MoveAndResizePanelButton Margin="12,0,0,0" /> <local:MoveAndResizePanelButton Margin="12,0,0,0" Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}" />
<local:TouchEnabledButton <local:TouchEnabledButton
Width="{StaticResource IconSize}" Width="{StaticResource IconSize}"
Margin="12,0,0,0" Margin="12,0,0,0"
Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow'}" /> Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow and DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}" />
</StackPanel> </StackPanel>
<!-- Source panel icon --> <!-- Source panel icon -->
@ -288,7 +290,8 @@
Margin="0" Margin="0"
Command="{Binding DeletePanelCommand}" Command="{Binding DeletePanelCommand}"
KeyboardNavigation.AcceptsReturn="False" KeyboardNavigation.AcceptsReturn="False"
ToolTip="Delete panel"> ToolTip="Delete panel"
Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay and DataItem.PanelType!=profileDomain:PanelType.HudBarWindow'}">
<materialDesign:PackIcon <materialDesign:PackIcon
Width="{StaticResource IconSize}" Width="{StaticResource IconSize}"
Height="{StaticResource IconSize}" Height="{StaticResource IconSize}"
@ -301,8 +304,7 @@
Margin="42,8,24,16" Margin="42,8,24,16"
Orientation="Horizontal" Orientation="Horizontal"
TextBlock.Foreground="{DynamicResource MaterialDesignBody}" TextBlock.Foreground="{DynamicResource MaterialDesignBody}"
Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow'}"> Visibility="{c:Binding 'DataItem.PanelType!=profileDomain:PanelType.HudBarWindow and DataItem.PanelType!=profileDomain:PanelType.RefocusDisplay'}">
<WrapPanel> <WrapPanel>
<ToggleButton <ToggleButton
x:Name="TglBtnAlwaysOnTop" x:Name="TglBtnAlwaysOnTop"

View file

@ -3,6 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="clr-namespace:MSFSPopoutPanelManager.DomainModel;assembly=DomainModel"
xmlns:localcontrol="clr-namespace:MSFSPopoutPanelManager.MainApp.CustomControl" xmlns:localcontrol="clr-namespace:MSFSPopoutPanelManager.MainApp.CustomControl"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@ -201,7 +202,7 @@
<ToggleButton IsChecked="{Binding AppSettingData.ApplicationSetting.AutoPopOutSetting.IsEnabled, Mode=TwoWay}" Style="{StaticResource ToggleButton}" /> <ToggleButton IsChecked="{Binding AppSettingData.ApplicationSetting.AutoPopOutSetting.IsEnabled, Mode=TwoWay}" Style="{StaticResource ToggleButton}" />
<TextBlock Style="{StaticResource TextBlockLabel}">Automatic pop out panels when an aircraft livery is bound to a profile. The following steps will be performed.</TextBlock> <TextBlock Style="{StaticResource TextBlockLabel}">Automatic pop out panels when an aircraft livery is bound to a profile. The following steps will be performed.</TextBlock>
</WrapPanel> </WrapPanel>
<StackPanel Margin="46,0,0,0" Orientation="Vertical"> <StackPanel Margin="34,0,0,0" Orientation="Vertical">
<TextBlock Margin="0,10,0,0" Style="{StaticResource TextBlockLabel}"> <TextBlock Margin="0,10,0,0" Style="{StaticResource TextBlockLabel}">
1. Detect flight start signal using SimConnect. 1. Detect flight start signal using SimConnect.
</TextBlock> </TextBlock>
@ -256,7 +257,7 @@
<WrapPanel Orientation="Vertical" Visibility="{Binding AppSettingData.ApplicationSetting.PopOutSetting.AutoPanning.IsEnabled, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}"> <WrapPanel Orientation="Vertical" Visibility="{Binding AppSettingData.ApplicationSetting.PopOutSetting.AutoPanning.IsEnabled, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}">
<StackPanel <StackPanel
Width="Auto" Width="Auto"
Margin="40,15,0,0" Margin="44,15,0,0"
VerticalAlignment="Top" VerticalAlignment="Top"
Orientation="Horizontal"> Orientation="Horizontal">
<WrapPanel> <WrapPanel>
@ -279,7 +280,7 @@
</ComboBox> </ComboBox>
</WrapPanel> </WrapPanel>
<TextBlock <TextBlock
Width="620" Width="600"
Margin="10,3,0,0" Margin="10,3,0,0"
Style="{StaticResource TextBlockLabel}"> Style="{StaticResource TextBlockLabel}">
Configure key binding for saving and recalling of custom MSFS cockpit camera view when defining the locations of pop out panel. Requires binding keystroke to custom camera in MSFS control setting. (Default: Ctrl-Alt-0 to save and Alt-0 to load). Configure key binding for saving and recalling of custom MSFS cockpit camera view when defining the locations of pop out panel. Requires binding keystroke to custom camera in MSFS control setting. (Default: Ctrl-Alt-0 to save and Alt-0 to load).

View file

@ -1,8 +1,4 @@
using Microsoft.Extensions.DependencyInjection; using System.Windows.Controls;
using MSFSPopoutPanelManager.MainApp.ViewModel;
using System;
using System.Windows;
using System.Windows.Controls;
namespace MSFSPopoutPanelManager.MainApp namespace MSFSPopoutPanelManager.MainApp
{ {
@ -13,4 +9,4 @@ namespace MSFSPopoutPanelManager.MainApp
InitializeComponent(); InitializeComponent();
} }
} }
} }

View file

@ -51,6 +51,16 @@
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<Style
x:Key="TxtBlockDisableWhenLockedInner"
BasedOn="{StaticResource TextBlockLabel}"
TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.ProfileData.ActiveProfile.IsLocked, RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}}" Value="True">
<Setter Property="Foreground" Value="DimGray" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style <Style
x:Key="CmbBoxDisableWhenLocked" x:Key="CmbBoxDisableWhenLocked"
BasedOn="{StaticResource MaterialDesignComboBox}" BasedOn="{StaticResource MaterialDesignComboBox}"
@ -226,7 +236,6 @@
<TextBlock Style="{StaticResource TxtBlockDisableWhenLocked}" ToolTip="Add in-game menu bar panels such as VFR Map, Checklist, ATC, etc. to profile to enable panel size and location management and touch support">Include in-game menu bar panels for pop out management and touch screen support</TextBlock> <TextBlock Style="{StaticResource TxtBlockDisableWhenLocked}" ToolTip="Add in-game menu bar panels such as VFR Map, Checklist, ATC, etc. to profile to enable panel size and location management and touch support">Include in-game menu bar panels for pop out management and touch screen support</TextBlock>
</WrapPanel> </WrapPanel>
<StackPanel Margin="0,8,0,0" Orientation="Horizontal"> <StackPanel Margin="0,8,0,0" Orientation="Horizontal">
<WrapPanel> <WrapPanel>
<ToggleButton <ToggleButton
@ -247,6 +256,66 @@
SelectedValue="{Binding ProfileData.ActiveProfile.ProfileSetting.HudBarConfig.HudBarType, Mode=TwoWay, Converter={StaticResource StringToHudBarTypeConverter}}" SelectedValue="{Binding ProfileData.ActiveProfile.ProfileSetting.HudBarConfig.HudBarType, Mode=TwoWay, Converter={StaticResource StringToHudBarTypeConverter}}"
Style="{StaticResource CmbBoxDisableWhenLocked}" /> Style="{StaticResource CmbBoxDisableWhenLocked}" />
</WrapPanel> </WrapPanel>
</StackPanel>
<StackPanel Margin="0,8,0,0" Orientation="Vertical">
<WrapPanel>
<ToggleButton
IsChecked="{Binding ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.IsEnabled, Mode=TwoWay, NotifyOnTargetUpdated=True}"
IsEnabled="{c:Binding '!ProfileData.ActiveProfile.IsLocked',
Mode=OneWay}"
Style="{StaticResource ToggleButton}"
TargetUpdated="AddRefocusDisplay_TargetUpdated" />
<TextBlock Style="{StaticResource TxtBlockDisableWhenLocked}" ToolTip="Automactically set focus back to game window after a period of inactivity after touching the designated monitor. This is overcome a bug in MSFS where NVidia frame generation does not work when focus is not in the game window.">Enable entire monitor display to have game refocus function when touch</TextBlock>
</WrapPanel>
<WrapPanel
Margin="36,0,0,0"
IsEnabled="{c:Binding !ProfileData.ActiveProfile.IsLocked}"
Orientation="Horizontal"
Visibility="{Binding ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.IsEnabled, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}">
<WrapPanel Orientation="Vertical" Visibility="{Binding ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.IsEnabled, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}">
<ItemsControl
Margin="0"
Padding="8"
ItemsSource="{Binding ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.Monitors, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type domain:MonitorInfo}">
<WrapPanel Margin="0,0,0,4" Orientation="Horizontal">
<CheckBox
VerticalAlignment="Center"
Command="{Binding DataContext.RefocusDisplaySelectionUpdatedCommand, RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}}"
CommandParameter="{Binding Name}"
IsChecked="{Binding IsSelected, Mode=TwoWay}" />
<WrapPanel
Margin="8,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Margin="0,0,5,0"
FontWeight="Bold"
Style="{StaticResource TxtBlockDisableWhenLockedInner}"
Text="{Binding Name}" />
<TextBlock Style="{StaticResource TxtBlockDisableWhenLockedInner}" Text="(" />
<TextBlock Style="{StaticResource TxtBlockDisableWhenLockedInner}" Text="{Binding Width}" />
<TextBlock Style="{StaticResource TxtBlockDisableWhenLockedInner}" Text="x" />
<TextBlock Style="{StaticResource TxtBlockDisableWhenLockedInner}" Text="{Binding Height}" />
<TextBlock Style="{StaticResource TxtBlockDisableWhenLockedInner}" Text=")" />
</WrapPanel>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
<Button
Width="160"
Margin="20,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Command="{Binding RefocusDisplayRefreshedCommand}"
Style="{StaticResource MaterialDesignOutlinedLightButton}">
Refresh Display List
</Button>
</WrapPanel>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>

View file

@ -52,6 +52,11 @@ namespace MSFSPopoutPanelManager.MainApp
{ {
_viewModel.AddHudBarUpdatedCommand.Execute(null); _viewModel.AddHudBarUpdatedCommand.Execute(null);
} }
private void AddRefocusDisplay_TargetUpdated(object sender, DataTransferEventArgs e)
{
_viewModel.RefocusDisplayUpdatedCommand.Execute(null);
}
} }

View file

@ -2,6 +2,7 @@
using MSFSPopoutPanelManager.DomainModel.Profile; using MSFSPopoutPanelManager.DomainModel.Profile;
using MSFSPopoutPanelManager.Orchestration; using MSFSPopoutPanelManager.Orchestration;
using MSFSPopoutPanelManager.Shared; using MSFSPopoutPanelManager.Shared;
using MSFSPopoutPanelManager.WindowsAgent;
using Prism.Commands; using Prism.Commands;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -28,6 +29,12 @@ namespace MSFSPopoutPanelManager.MainApp.ViewModel
public ICommand AddHudBarUpdatedCommand { get; } public ICommand AddHudBarUpdatedCommand { get; }
public ICommand RefocusDisplayUpdatedCommand { get; }
public ICommand RefocusDisplayRefreshedCommand { get; }
public DelegateCommand<string> RefocusDisplaySelectionUpdatedCommand { get; }
public List<string> HudBarTypes => Enum.GetNames(typeof(HudBarType)).Where(x => x != "None").Select(x => x.Replace("_", " ")).ToList(); public List<string> HudBarTypes => Enum.GetNames(typeof(HudBarType)).Where(x => x != "None").Select(x => x.Replace("_", " ")).ToList();
@ -68,6 +75,12 @@ namespace MSFSPopoutPanelManager.MainApp.ViewModel
IncludeInGamePanelUpdatedCommand = new DelegateCommand(OnIncludeInGamePanelUpdated); IncludeInGamePanelUpdatedCommand = new DelegateCommand(OnIncludeInGamePanelUpdated);
AddHudBarUpdatedCommand = new DelegateCommand(OnAddHudBarUpdated); AddHudBarUpdatedCommand = new DelegateCommand(OnAddHudBarUpdated);
RefocusDisplayUpdatedCommand = new DelegateCommand(OnRefocusDisplayUpdated);
RefocusDisplayRefreshedCommand = new DelegateCommand(OnRefocusDisplayRefreshed);
RefocusDisplaySelectionUpdatedCommand = new DelegateCommand<string>(RefocusDisplaySelectionUpdated);
} }
private async void OnDeleteProfile() private async void OnDeleteProfile()
@ -124,14 +137,100 @@ namespace MSFSPopoutPanelManager.MainApp.ViewModel
private void OnIncludeInGamePanelUpdated() private void OnIncludeInGamePanelUpdated()
{ {
if (Orchestrator.ProfileData.ActiveProfile != null && !Orchestrator.ProfileData.ActiveProfile.ProfileSetting.IncludeInGamePanels) if (ProfileData.ActiveProfile != null && !ProfileData.ActiveProfile.ProfileSetting.IncludeInGamePanels)
Orchestrator.ProfileData.ActiveProfile.PanelConfigs.RemoveAll(p => p.PanelType == PanelType.BuiltInPopout); ProfileData.ActiveProfile.PanelConfigs.RemoveAll(p => p.PanelType == PanelType.BuiltInPopout);
} }
private void OnAddHudBarUpdated() private void OnAddHudBarUpdated()
{ {
if (Orchestrator.ProfileData.ActiveProfile != null && !Orchestrator.ProfileData.ActiveProfile.ProfileSetting.HudBarConfig.IsEnabled) if (ProfileData.ActiveProfile == null)
Orchestrator.ProfileData.ActiveProfile.PanelConfigs.RemoveAll(p => p.PanelType == PanelType.HudBarWindow); return;
if (ProfileData.ActiveProfile.ProfileSetting.HudBarConfig.IsEnabled)
{
if (ProfileData.ActiveProfile.PanelConfigs.Any(p => p.PanelType == PanelType.HudBarWindow))
return;
ProfileData.ActiveProfile.PanelConfigs.Add(new PanelConfig
{
PanelName = "HUD Bar",
PanelType = PanelType.HudBarWindow,
Left = 0,
Top = 0,
Width = 1920,
Height = 40,
AutoGameRefocus = false
});
}
else
{
ProfileData.ActiveProfile.PanelConfigs.RemoveAll(p => p.PanelType == PanelType.HudBarWindow);
}
}
private void OnRefocusDisplayUpdated()
{
if (ProfileData.ActiveProfile == null)
return;
if (ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.Monitors.Count == 0)
{
var monitors = WindowActionManager.GetMonitorsInfo().OrderBy(m => m.Name);
foreach (var monitor in monitors)
ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.Monitors.Add(monitor);
}
if (!ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.IsEnabled)
{
ProfileData.ActiveProfile.PanelConfigs.RemoveAll(p => p.PanelType == PanelType.RefocusDisplay);
ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.Monitors.ToList().ForEach(p => p.IsSelected = false);
}
}
private void OnRefocusDisplayRefreshed()
{
if (ProfileData.ActiveProfile == null)
return;
ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.Monitors.Clear();
ProfileData.ActiveProfile.PanelConfigs.RemoveAll(p => p.PanelType == PanelType.RefocusDisplay);
var monitors = WindowActionManager.GetMonitorsInfo().OrderBy(m => m.Name);
foreach (var monitor in monitors)
ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.Monitors.Add(monitor);
}
private void RefocusDisplaySelectionUpdated(string arg)
{
if (ProfileData.ActiveProfile == null)
return;
var monitor = ProfileData.ActiveProfile.ProfileSetting.RefocusOnDisplay.Monitors.FirstOrDefault(m => m.Name == arg);
if (monitor == null)
return;
if(!monitor.IsSelected)
{
ProfileData.ActiveProfile.PanelConfigs.RemoveAll(p => p.PanelName == arg && p.PanelType == PanelType.RefocusDisplay);
}
else
{
ProfileData.ActiveProfile.PanelConfigs.Add(new PanelConfig
{
PanelName = arg,
PanelType = PanelType.RefocusDisplay,
Left = monitor.X,
Top = monitor.Y,
Width = monitor.Width,
Height = monitor.Height,
HideTitlebar = true,
FullScreen = true,
TouchEnabled = true
});
}
} }
} }
} }

View file

@ -71,8 +71,9 @@ namespace MSFSPopoutPanelManager.Orchestration
return; return;
var hasTouchEnabledPanel = ActiveProfile.PanelConfigs.Any(p => p.TouchEnabled && p.IsPopOutSuccess != null && (bool)p.IsPopOutSuccess); var hasTouchEnabledPanel = ActiveProfile.PanelConfigs.Any(p => p.TouchEnabled && p.IsPopOutSuccess != null && (bool)p.IsPopOutSuccess);
var hasRefocusDisplays = ActiveProfile.PanelConfigs.Any(p => p.PanelType == PanelType.RefocusDisplay);
if (hasTouchEnabledPanel && !TouchEventManager.IsHooked) if (hasRefocusDisplays || (hasTouchEnabledPanel && !TouchEventManager.IsHooked))
TouchEventManager.Hook(); TouchEventManager.Hook();
}); });
} }

View file

@ -94,6 +94,8 @@ namespace MSFSPopoutPanelManager.Orchestration
StepAddHudBar(); StepAddHudBar();
SetupRefocusDisplay();
StepApplyPanelConfig(); StepApplyPanelConfig();
await StepPostPopout(); await StepPostPopout();
@ -101,7 +103,6 @@ namespace MSFSPopoutPanelManager.Orchestration
StatusMessageWriter.IsEnabled = false; StatusMessageWriter.IsEnabled = false;
} }
private void StepPopoutPrep() private void StepPopoutPrep()
{ {
PanelConfigurationOrchestrator.EndConfiguration(); PanelConfigurationOrchestrator.EndConfiguration();
@ -305,23 +306,25 @@ namespace MSFSPopoutPanelManager.Orchestration
var panelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(p => p.PanelType == PanelType.HudBarWindow); var panelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(p => p.PanelType == PanelType.HudBarWindow);
if (panelConfig == null)
{
panelConfig = new PanelConfig()
{
PanelName = "HUD Bar",
PanelType = PanelType.HudBarWindow,
AutoGameRefocus = false
};
ActiveProfile.PanelConfigs.Add(panelConfig);
}
OnHudBarOpened?.Invoke(this, panelConfig); OnHudBarOpened?.Invoke(this, panelConfig);
StatusMessageWriter.WriteOkStatusMessage(); StatusMessageWriter.WriteOkStatusMessage();
} }
public void SetupRefocusDisplay()
{
if (!ActiveProfile.ProfileSetting.RefocusOnDisplay.IsEnabled)
return;
var panelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(p => p.PanelType == PanelType.RefocusDisplay);
if (panelConfig != null)
{
StatusMessageWriter.WriteMessage($"Configurating {panelConfig.PanelName} for auto refocus on touch", StatusMessageType.Info);
panelConfig.PanelHandle = new IntPtr(1);
StatusMessageWriter.WriteOkStatusMessage();
}
}
private void StepApplyPanelConfig() 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 // Must apply other panel config after pop out since MSFS popping out action will overwrite panel config such as Always on Top

View file

@ -64,10 +64,10 @@ namespace MSFSPopoutPanelManager.WindowsAgent
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowLong(IntPtr hwnd, int nIndex); public static extern IntPtr GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll")] [DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetCurrentThreadId(); public static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
@ -86,7 +86,7 @@ namespace MSFSPopoutPanelManager.WindowsAgent
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowRect(IntPtr hwnd, out Rectangle lpRect); private static extern int GetWindowRect(IntPtr hwnd, out Rectangle lpRect);
[DllImport("user32.dll", CharSet = CharSet.Auto)] [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText(IntPtr hwnd, StringBuilder lpWindowText, int nMaxCount); private static extern int GetWindowText(IntPtr hwnd, StringBuilder lpWindowText, int nMaxCount);
public static string GetWindowText(IntPtr hwnd) public static string GetWindowText(IntPtr hwnd)
@ -100,7 +100,7 @@ namespace MSFSPopoutPanelManager.WindowsAgent
catch { return string.Empty; } catch { return string.Empty; }
} }
[DllImport("user32.dll")] [DllImport("user32.dll", SetLastError = true)]
public static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect); public static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
@ -266,6 +266,4 @@ namespace MSFSPopoutPanelManager.WindowsAgent
DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_SYSTEMBACKDROP_TYPE,
DWMWA_LAST DWMWA_LAST
} }
} }

View file

@ -99,8 +99,11 @@ namespace MSFSPopoutPanelManager.WindowsAgent
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
if (!_isTouchDown) if (!_isTouchDown)
{ {
_isTouchDown = true;
_refocusedTaskIndex++; _refocusedTaskIndex++;
if (panelConfig.PanelType == PanelType.RefocusDisplay)
return 1;
_isTouchDown = true;
if (_isDragged) if (_isDragged)
return 1; return 1;
@ -118,31 +121,34 @@ namespace MSFSPopoutPanelManager.WindowsAgent
case WM_LBUTTONUP: case WM_LBUTTONUP:
Task.Run(() => Task.Run(() =>
{ {
while (_isTouchDown) { } if (panelConfig.PanelType != PanelType.RefocusDisplay)
if (_isDragged)
{ {
if (ApplicationSetting.TouchSetting.TouchDownUpDelay > 0) while (_isTouchDown) { }
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay);
PInvoke.SetCursorPos(info.pt.X, info.pt.Y); if (_isDragged)
{
if (ApplicationSetting.TouchSetting.TouchDownUpDelay > 0)
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay);
if (ApplicationSetting.TouchSetting.TouchDownUpDelay > 0) PInvoke.SetCursorPos(info.pt.X, info.pt.Y);
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay);
InputEmulationManager.LeftClickFast(info.pt.X, info.pt.Y); if (ApplicationSetting.TouchSetting.TouchDownUpDelay > 0)
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay);
_isDragged = false; InputEmulationManager.LeftClickFast(info.pt.X, info.pt.Y);
_isDragged = false;
}
else
{
if (ApplicationSetting.TouchSetting.TouchDownUpDelay > 0)
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X, info.pt.Y, 0, 0);
}
_isTouchDown = false;
} }
else
{
if(ApplicationSetting.TouchSetting.TouchDownUpDelay > 0)
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X, info.pt.Y, 0, 0);
}
_isTouchDown = false;
// Refocus game window // Refocus game window
if (ApplicationSetting.RefocusSetting.RefocusGameWindow.IsEnabled && panelConfig.AutoGameRefocus) if (ApplicationSetting.RefocusSetting.RefocusGameWindow.IsEnabled && panelConfig.AutoGameRefocus)
@ -155,6 +161,9 @@ namespace MSFSPopoutPanelManager.WindowsAgent
{ {
var rect = WindowActionManager.GetWindowRectangle(WindowProcessManager.SimulatorProcess.Handle); var rect = WindowActionManager.GetWindowRectangle(WindowProcessManager.SimulatorProcess.Handle);
PInvoke.SetCursorPos(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); PInvoke.SetCursorPos(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
if (panelConfig.PanelType == PanelType.RefocusDisplay)
InputEmulationManager.LeftClick(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
} }
} }
}); });

View file

@ -5,6 +5,7 @@ using System.Drawing;
using System.Globalization; using System.Globalization;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Windows.Forms;
namespace MSFSPopoutPanelManager.WindowsAgent namespace MSFSPopoutPanelManager.WindowsAgent
{ {
@ -298,5 +299,17 @@ namespace MSFSPopoutPanelManager.WindowsAgent
if (int.TryParse(hexColor, NumberStyles.HexNumber, null, out color)) if (int.TryParse(hexColor, NumberStyles.HexNumber, null, out color))
PInvoke.DwmSetWindowAttribute(hwnd, DwmWindowAttribute.DWMWA_CAPTION_COLOR, ref color, sizeof(Int32)); PInvoke.DwmSetWindowAttribute(hwnd, DwmWindowAttribute.DWMWA_CAPTION_COLOR, ref color, sizeof(Int32));
} }
public static List<MonitorInfo> GetMonitorsInfo()
{
var monitors = new List<MonitorInfo>();
foreach (Screen screen in Screen.AllScreens)
{
monitors.Add(new MonitorInfo { Name = screen.DeviceName.Substring(screen.DeviceName.LastIndexOf("\\") + 1), X = screen.Bounds.X, Y = screen.Bounds.Y, Width = screen.Bounds.Width, Height = screen.Bounds.Height });
}
return monitors;
}
} }
} }

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net7.0-windows</TargetFramework>
@ -17,6 +17,7 @@
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType> <DebugType>Embedded</DebugType>
<Configurations>Debug;Releasel;Local</Configurations> <Configurations>Debug;Releasel;Local</Configurations>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>