mirror of
https://github.com/hawkeye-stan/msfs-popout-panel-manager.git
synced 2024-11-25 15:20:10 +00:00
v1.2.0.0 updates
This commit is contained in:
parent
d4c4203931
commit
bba7331dbb
7 changed files with 182 additions and 63 deletions
|
@ -51,7 +51,7 @@ namespace MSFSPopoutPanelManager
|
|||
public event EventHandler<EventArgs<string>> OnStatusUpdated;
|
||||
public event EventHandler<EventArgs<Dictionary<string, string>>> OnOcrDebugged;
|
||||
|
||||
public void Analyze(ref MainWindow simWindow, string profile)
|
||||
public void Analyze(ref MainWindow simWindow, OcrEvalData ocrEvaluationData)
|
||||
{
|
||||
MainWindow processZeroMainWindow = null;
|
||||
|
||||
|
@ -107,7 +107,6 @@ namespace MSFSPopoutPanelManager
|
|||
|
||||
if(simWindow.ChildWindowsData.Count > 0)
|
||||
{
|
||||
var ocrEvaluationData = FileManager.ReadProfileData().Find(x => x.Profile == profile);
|
||||
var ocrImageScale = ocrEvaluationData.OCRImageScale;
|
||||
Dictionary<string, string> debugInfo = new Dictionary<string, string>();
|
||||
|
||||
|
@ -133,7 +132,7 @@ namespace MSFSPopoutPanelManager
|
|||
SetForegroundWindow(childWindow.Handle);
|
||||
Thread.Sleep(500);
|
||||
|
||||
var image = TakeScreenShot(rect);
|
||||
var image = TakeScreenShot(rect, childWindow.Handle.ToInt32());
|
||||
MoveWindow(childWindow.Handle, rect.Left, rect.Top, originalWidth, originalHeight, true);
|
||||
|
||||
// OCR the image into text
|
||||
|
@ -220,7 +219,7 @@ namespace MSFSPopoutPanelManager
|
|||
return true;
|
||||
}
|
||||
|
||||
private byte[] TakeScreenShot(Rect rect)
|
||||
private byte[] TakeScreenShot(Rect rect, int imageId)
|
||||
{
|
||||
var bounds = new System.Drawing.Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
|
||||
var bitmap = new Bitmap(bounds.Width, bounds.Height);
|
||||
|
@ -237,9 +236,17 @@ namespace MSFSPopoutPanelManager
|
|||
using(var img = SixLabors.ImageSharp.Image.Load(imageBytes))
|
||||
{
|
||||
img.Mutate(x => x.Invert().GaussianSharpen().Grayscale());
|
||||
|
||||
double imageRatio = 250 / 72.0; // change from default of 72 DPI to 250 DPI
|
||||
|
||||
img.Metadata.HorizontalResolution *= imageRatio;
|
||||
img.Metadata.VerticalResolution *= imageRatio;
|
||||
var memoryStream = new MemoryStream();
|
||||
img.Save(memoryStream, new SixLabors.ImageSharp.Formats.Bmp.BmpEncoder());
|
||||
img.Save(@".\test.jpg");
|
||||
#if DEBUG
|
||||
Directory.CreateDirectory("imageDebug");
|
||||
img.Save(@$"./imageDebug/test-{imageId}.jpg");
|
||||
#endif
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,18 @@ namespace MSFSPopoutPanelManager
|
|||
{
|
||||
public class FileManager
|
||||
{
|
||||
public static UserData ReadUserData()
|
||||
private string _startupPath;
|
||||
|
||||
public FileManager(string startupPath)
|
||||
{
|
||||
_startupPath = startupPath;
|
||||
}
|
||||
|
||||
public UserData ReadUserData()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(@".\config\userdata.json"))
|
||||
using (StreamReader reader = new StreamReader(_startupPath + @"\config\userdata.json"))
|
||||
{
|
||||
string json = reader.ReadToEnd();
|
||||
return JsonConvert.DeserializeObject<UserData>(json);
|
||||
|
@ -23,18 +30,18 @@ namespace MSFSPopoutPanelManager
|
|||
}
|
||||
}
|
||||
|
||||
public static void WriteUserData(UserData userData)
|
||||
public void WriteUserData(UserData userData)
|
||||
{
|
||||
using (StreamWriter file = File.CreateText(@".\config\userdata.json"))
|
||||
using (StreamWriter file = File.CreateText(_startupPath + @"\config\userdata.json"))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.Serialize(file, userData);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<OcrEvalData> ReadProfileData()
|
||||
public List<OcrEvalData> ReadProfileData()
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(@".\config\ocrdata.json"))
|
||||
using (StreamReader reader = new StreamReader(_startupPath + @"\config\ocrdata.json"))
|
||||
{
|
||||
string json = reader.ReadToEnd();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>1.1</Version>
|
||||
<Version>1.2</Version>
|
||||
<AssemblyName>MSFSPopoutPanelManager</AssemblyName>
|
||||
<RootNamespace>MSFSPopoutPanelManager</RootNamespace>
|
||||
<ApplicationIcon>WindowManager.ico</ApplicationIcon>
|
||||
|
@ -104,6 +104,9 @@
|
|||
<None Update="LICENSE">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="VERSION.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Vesion.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
|
84
MainForm.cs
84
MainForm.cs
|
@ -12,7 +12,8 @@ namespace MSFSPopoutPanelManager
|
|||
public partial class MainForm : Form
|
||||
{
|
||||
private SynchronizationContext _syncRoot;
|
||||
private WindowManager _popoutWindowsManager;
|
||||
private FileManager _fileManager;
|
||||
private WindowManager _windowManager;
|
||||
|
||||
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
|
||||
private const UInt32 SWP_NOSIZE = 0x0001;
|
||||
|
@ -25,19 +26,22 @@ namespace MSFSPopoutPanelManager
|
|||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_syncRoot = SynchronizationContext.Current;
|
||||
|
||||
_fileManager = new FileManager(Application.StartupPath);
|
||||
|
||||
_windowManager = new WindowManager(_fileManager);
|
||||
_windowManager.OnStatusUpdated += HandleOnStatusUpdated;
|
||||
_windowManager.OnSimulatorStarted += HandleOnSimulatorStarted;
|
||||
_windowManager.OnOcrDebugged += HandleOnOcrDebugged;
|
||||
_windowManager.CheckSimulatorStarted();
|
||||
|
||||
SetProfileDropDown();
|
||||
|
||||
_popoutWindowsManager = new WindowManager();
|
||||
_popoutWindowsManager.OnStatusUpdated += HandleOnStatusUpdated;
|
||||
_popoutWindowsManager.OnSimulatorStarted += HandleOnSimulatorStarted;
|
||||
_popoutWindowsManager.OnOcrDebugged += HandleOnOcrDebugged;
|
||||
_popoutWindowsManager.CheckSimulatorStarted();
|
||||
|
||||
#if DEBUG
|
||||
// Set application windows always on top for easy debugging
|
||||
SetWindowPos(this.Handle, HWND_TOPMOST, this.Left, this.Top, this.Width, this.Height, TOPMOST_FLAGS);
|
||||
|
||||
#endif
|
||||
var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
||||
lblVersion.Text += version.ToString();
|
||||
}
|
||||
|
@ -47,7 +51,7 @@ namespace MSFSPopoutPanelManager
|
|||
txtStatus.Clear();
|
||||
|
||||
var profile = GetProfileDropDown();
|
||||
var success = _popoutWindowsManager.Analyze(profile);
|
||||
var success = _windowManager.Analyze(profile);
|
||||
|
||||
btnApplySettings.Enabled = success;
|
||||
btnSaveSettings.Enabled = success;
|
||||
|
@ -58,7 +62,7 @@ namespace MSFSPopoutPanelManager
|
|||
txtStatus.Clear();
|
||||
|
||||
var profile = GetProfileDropDown();
|
||||
_popoutWindowsManager.ApplySettings(profile, chkHidePanelTitleBar.Checked, chkAlwaysOnTop.Checked);
|
||||
_windowManager.ApplySettings(profile, chkHidePanelTitleBar.Checked, chkAlwaysOnTop.Checked);
|
||||
}
|
||||
|
||||
private void btnSaveSettings_Click(object sender, EventArgs e)
|
||||
|
@ -66,15 +70,15 @@ namespace MSFSPopoutPanelManager
|
|||
txtStatus.Clear();
|
||||
|
||||
var profile = GetProfileDropDown();
|
||||
_popoutWindowsManager.SaveSettings(profile, chkHidePanelTitleBar.Checked, chkAlwaysOnTop.Checked);
|
||||
_windowManager.SaveSettings(profile, chkHidePanelTitleBar.Checked, chkAlwaysOnTop.Checked);
|
||||
}
|
||||
|
||||
private void SetProfileDropDown()
|
||||
{
|
||||
try
|
||||
{
|
||||
var profileData = FileManager.ReadProfileData();
|
||||
var profiles = profileData.Select(x => x.Profile).Distinct();
|
||||
var profileData = _fileManager.ReadProfileData();
|
||||
var profiles = profileData.Select(x => x.Profile).Distinct().OrderBy(x => x);
|
||||
var defaultProfile = profileData.Find(x => x.DefaultProfile);
|
||||
|
||||
comboBoxProfile.DataSource = profiles.ToList();
|
||||
|
@ -91,6 +95,32 @@ namespace MSFSPopoutPanelManager
|
|||
return comboBoxProfile.SelectedItem.ToString();
|
||||
}
|
||||
|
||||
private void comboBoxProfile_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
_windowManager.Reset();
|
||||
|
||||
var userData = _fileManager.ReadUserData();
|
||||
|
||||
if (userData != null)
|
||||
{
|
||||
var userProfile = userData.Profiles.Find(x => x.Name == Convert.ToString(comboBoxProfile.SelectedValue));
|
||||
if (userProfile != null)
|
||||
{
|
||||
chkAlwaysOnTop.Checked = userProfile.AlwaysOnTop;
|
||||
chkHidePanelTitleBar.Checked = userProfile.HidePanelTitleBar;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default values
|
||||
chkAlwaysOnTop.Checked = false;
|
||||
chkHidePanelTitleBar.Checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
btnApplySettings.Enabled = false;
|
||||
btnSaveSettings.Enabled = false;
|
||||
}
|
||||
|
||||
private void HandleOnStatusUpdated(object source, EventArgs<string> arg)
|
||||
{
|
||||
_syncRoot.Post(SetStatusMessage, arg.Value);
|
||||
|
@ -163,7 +193,7 @@ namespace MSFSPopoutPanelManager
|
|||
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
// Put all panels popout back to original state
|
||||
_popoutWindowsManager.RestorePanelTitleBar();
|
||||
_windowManager.RestorePanelTitleBar();
|
||||
}
|
||||
|
||||
private void MainForm_Resize(object sender, EventArgs e)
|
||||
|
@ -186,28 +216,6 @@ namespace MSFSPopoutPanelManager
|
|||
WindowState = FormWindowState.Normal;
|
||||
}
|
||||
|
||||
private void comboBoxProfile_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
var userData = FileManager.ReadUserData();
|
||||
|
||||
if (userData != null)
|
||||
{
|
||||
var userProfile = userData.Profiles.Find(x => x.Name == Convert.ToString(comboBoxProfile.SelectedValue));
|
||||
if (userProfile != null)
|
||||
{
|
||||
chkAlwaysOnTop.Checked = userProfile.AlwaysOnTop;
|
||||
chkHidePanelTitleBar.Checked = userProfile.HidePanelTitleBar;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default values
|
||||
chkAlwaysOnTop.Checked = false;
|
||||
chkHidePanelTitleBar.Checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
btnApplySettings.Enabled = false;
|
||||
btnSaveSettings.Enabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
14
VERSION.md
14
VERSION.md
|
@ -1,13 +1,21 @@
|
|||
# Version History
|
||||
<hr/>
|
||||
|
||||
## Version 1.1
|
||||
## Version 1.2.0.0
|
||||
* Increase OCR image accuracy by raising image DPI before analysis.
|
||||
* Added (very experimental) Asobo A320 and FlybyWire A320NX profiles as testing sample. These profiles do only work 100% of the time. Continue investigation into better OCR accuracy will be needed.
|
||||
* Added profile dropdown sorted by profile name.
|
||||
* Fixed an issue of unable to set or reset panel to NOT ALWAYS ON TOP
|
||||
* Fixed application path issue for not able to find ocrdata.json file at startup.
|
||||
* Removed MSFS Pop Out Panel Manager is always on top (not the actual in-game panels themselves). Now it is only always on top during development debug mode if you compile and run the application from source code.
|
||||
|
||||
## Version 1.1.0.0
|
||||
* Added caption title for the "untitled" windows. After analysis, if the panel window matches the name in the profile/ocr definition file, it will now display a caption of "Custom - XXXXX" (ie. Custom - PFD). This allows user to use various 3rd party windows layout manager to organize pop out panel windows.
|
||||
* Added hide panel title bar feature.
|
||||
* Added ability to have pop out panels to be always on top.
|
||||
* Added minimize application to tray feature.
|
||||
* Made application flow more intuitive.
|
||||
* Fix various small bugs in the application.
|
||||
* Fixed various small bugs in the application.
|
||||
|
||||
## Version 1.0
|
||||
## Version 1.0.0.0
|
||||
* Initial Release
|
|
@ -35,14 +35,20 @@ namespace MSFSPopoutPanelManager
|
|||
const int WS_CAPTION = WS_BORDER | WS_DLGFRAME;
|
||||
|
||||
private const int MSFS_CONNECTION_RETRY_TIMEOUT = 2000;
|
||||
private FileManager _fileManager;
|
||||
private Timer _timer;
|
||||
private UserData _userData;
|
||||
private MainWindow _simWindow;
|
||||
private AnalysisEngine _analysisEngine;
|
||||
private Dictionary<IntPtr, Int64> _originalChildWindowStyles;
|
||||
|
||||
public WindowManager()
|
||||
private bool _currentHidePanelTitleBarStatus;
|
||||
private bool _currentAlwaysOnTopStatus;
|
||||
|
||||
public WindowManager(FileManager fileManager)
|
||||
{
|
||||
_fileManager = fileManager;
|
||||
|
||||
_analysisEngine = new AnalysisEngine();
|
||||
_analysisEngine.OnStatusUpdated += (source, e) => OnStatusUpdated?.Invoke(source, e);
|
||||
_analysisEngine.OnOcrDebugged += (source, e) => OnOcrDebugged?.Invoke(source, e);
|
||||
|
@ -70,20 +76,33 @@ namespace MSFSPopoutPanelManager
|
|||
};
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
// reset these statuses
|
||||
_currentHidePanelTitleBarStatus = false;
|
||||
_currentAlwaysOnTopStatus = false;
|
||||
RestorePanelTitleBar();
|
||||
|
||||
_originalChildWindowStyles = null;
|
||||
}
|
||||
|
||||
public bool Analyze(string profileName)
|
||||
{
|
||||
|
||||
|
||||
_originalChildWindowStyles = null;
|
||||
_simWindow.ChildWindowsData = new List<ChildWindow>();
|
||||
|
||||
_analysisEngine.Analyze(ref _simWindow, profileName);
|
||||
var evalData = _fileManager.ReadProfileData().Find(x => x.Profile == profileName);
|
||||
_analysisEngine.Analyze(ref _simWindow, evalData);
|
||||
|
||||
return _simWindow.ChildWindowsData.FindAll(x => x.PopoutType == PopoutType.Custom || x.PopoutType == PopoutType.BuiltIn).Count > 0;
|
||||
}
|
||||
|
||||
public void ApplySettings(string profileName, bool showPanelTitleBar, bool alwaysOnTop)
|
||||
public void ApplySettings(string profileName, bool hidePanelTitleBar, bool alwaysOnTop)
|
||||
{
|
||||
// Try to load previous profiles
|
||||
_userData = FileManager.ReadUserData();
|
||||
_userData = _fileManager.ReadUserData();
|
||||
var profileSettings = _userData != null ? _userData.Profiles.Find(x => x.Name == profileName) : null;
|
||||
|
||||
if (profileSettings == null)
|
||||
|
@ -98,8 +117,18 @@ namespace MSFSPopoutPanelManager
|
|||
if (childWindows.Count > 0)
|
||||
{
|
||||
ApplyPositions(profileSettings, childWindows);
|
||||
ApplyAlwaysOnTop(alwaysOnTop, childWindows);
|
||||
ApplyHidePanelTitleBar(showPanelTitleBar, childWindows);
|
||||
|
||||
if (_currentHidePanelTitleBarStatus != hidePanelTitleBar)
|
||||
{
|
||||
_currentHidePanelTitleBarStatus = hidePanelTitleBar;
|
||||
ApplyHidePanelTitleBar(hidePanelTitleBar, childWindows);
|
||||
}
|
||||
|
||||
if(_currentAlwaysOnTopStatus != alwaysOnTop)
|
||||
{
|
||||
_currentAlwaysOnTopStatus = alwaysOnTop;
|
||||
ApplyAlwaysOnTop(alwaysOnTop, childWindows);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +163,7 @@ namespace MSFSPopoutPanelManager
|
|||
}
|
||||
}
|
||||
|
||||
FileManager.WriteUserData(_userData);
|
||||
_fileManager.WriteUserData(_userData);
|
||||
OnStatusUpdated?.Invoke(this, new EventArgs<string>("Pop out panel positions have been saved."));
|
||||
}
|
||||
}
|
||||
|
@ -173,6 +202,15 @@ namespace MSFSPopoutPanelManager
|
|||
SetWindowPos(childWindow.Handle, new IntPtr(-1), rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top, SWP_ALWAYS_ON_TOP);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyHidePanelTitleBar(bool hidePanelTitleBar, List<ChildWindow> childWindows)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[
|
||||
// G1000
|
||||
// G1000 NXi
|
||||
{
|
||||
"profile": "G1000",
|
||||
"profile": "G1000 / G1000 NXi",
|
||||
"defaultProfile": "true",
|
||||
"ocrImageScale": 1.0,
|
||||
"evalData": [
|
||||
|
@ -35,9 +35,57 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
// Flybywire A320NX
|
||||
{
|
||||
"profile": "Flybywire A320NX",
|
||||
"defaultProfile": "false",
|
||||
"ocrImageScale": 1,
|
||||
"evalData": [
|
||||
{
|
||||
"popoutName": "Screen1",
|
||||
"data": [ "QNH", "29.92" ]
|
||||
},
|
||||
{
|
||||
"popoutName": "Screen2",
|
||||
"data": [ "REL", "GW" ]
|
||||
},
|
||||
{
|
||||
"popoutName": "Screen3",
|
||||
"data": [ "TAS", "GS", "NM", "GPS", "Primary", "PPOS" ]
|
||||
},
|
||||
{
|
||||
"popoutName": "Screen4",
|
||||
"data": [ "F.FLOW", "AUTO BRK", "KG/MIN", "FOB", "TAT", "SAT" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
// Asobo A320
|
||||
{
|
||||
"profile": "Asobo A320",
|
||||
"defaultProfile": "false",
|
||||
"ocrImageScale": 1,
|
||||
"evalData": [
|
||||
{
|
||||
"popoutName": "Screen1",
|
||||
"data": [ "IDLE" ]
|
||||
},
|
||||
{
|
||||
"popoutName": "Screen2",
|
||||
"data": [ "TAS", "GS", "NM" ]
|
||||
},
|
||||
{
|
||||
"popoutName": "Screen3",
|
||||
"data": [ "F.FLOW", "KG", "KG/MIN", "FOB", "TAT", "SAT" ]
|
||||
},
|
||||
{
|
||||
"popoutName": "Screen4",
|
||||
"data": [ "SPD", "SEL", "CLB", "NAV", "QNH" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
// Custom Sample Profile - delete this if you don't need it
|
||||
{
|
||||
"profile": "Custom Sample Profile",
|
||||
"profile": "ZZZ - Custom Sample Profile",
|
||||
"defaultProfile": "false",
|
||||
"ocrImageScale": 1.0,
|
||||
"evalData": [
|
||||
|
|
Loading…
Reference in a new issue