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

Version 3.0.1

This commit is contained in:
hawkeye 2021-12-20 09:57:33 -05:00
parent ee61fdbe88
commit 0a3d485363
8 changed files with 118 additions and 48 deletions

View file

@ -5,7 +5,7 @@
<TargetFramework>net5.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<Platforms>x64;AnyCPU</Platforms>
<Version>3.0</Version>
<Version>3.0.1</Version>
<AssemblyName>MSFSPopoutPanelManager</AssemblyName>
<RootNamespace>MSFSPopoutPanelManager</RootNamespace>
<ApplicationIcon>WindowManager.ico</ApplicationIcon>
@ -13,8 +13,8 @@
<Product>MSFS 2020 Popout Panel Manager</Product>
<PackageId>MSFS 2020 Popout Panel Manager</PackageId>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<AssemblyVersion>3.0.1.0</AssemblyVersion>
<FileVersion>3.0.1.0</FileVersion>
<WeaverConfiguration>
<Weavers>
<PropertyChanged />

View file

@ -149,6 +149,12 @@ namespace MSFSPopoutPanelManager.Provider
// Add the built-in pop outs (ie. ATC, VFR Map) to the panel list
PInvoke.EnumWindows(new PInvoke.CallBack(EnumBuiltinPopoutCallBack), _profile.PanelSourceCoordinates.Count + 1);
// Add the MSFS Touch Panel (My other github project) windows to the panel list
PInvoke.EnumWindows(new PInvoke.CallBack(EnumMSFSTouchPanelPopoutCallBack), _profile.PanelSourceCoordinates.Count + 1);
if (_panels.Count == 0)
throw new PopoutManagerException("No panels have been found. Please select or open at least one in-game panel or MSFS Touch Panel App's panel.");
// Line up all the panels and fill in meta data
for (var i = _panels.Count - 1; i >= 0; i--)
{
@ -158,7 +164,7 @@ namespace MSFSPopoutPanelManager.Provider
_panels[i].Width = 800;
_panels[i].Height = 600;
PInvoke.MoveWindow(_panels[i].PanelHandle, -8 + _panels[i].Top, _panels[i].Left, _panels[i].Width, _panels[i].Height, true);
PInvoke.MoveWindow(_panels[i].PanelHandle, _panels[i].Top, _panels[i].Left, _panels[i].Width, _panels[i].Height, true);
PInvoke.SetForegroundWindow(_panels[i].PanelHandle);
Thread.Sleep(200);
}
@ -295,6 +301,22 @@ namespace MSFSPopoutPanelManager.Provider
return true;
}
public bool EnumMSFSTouchPanelPopoutCallBack(IntPtr hwnd, int index)
{
var panelInfo = GetPanelWindowInfo(hwnd);
if (panelInfo != null && panelInfo.PanelType == PanelType.MSFSTouchPanel)
{
if (!_panels.Exists(x => x.PanelHandle == hwnd))
{
panelInfo.PanelIndex = index;
_panels.Add(panelInfo);
}
}
return true;
}
private PanelConfig GetPanelWindowInfo(IntPtr hwnd)
{
var className = PInvoke.GetClassName(hwnd);
@ -316,6 +338,22 @@ namespace MSFSPopoutPanelManager.Provider
return panelInfo;
}
else // For MSFS Touch Panel window
{
var caption = PInvoke.GetWindowText(hwnd);
var panelInfo = new PanelConfig();
panelInfo.PanelHandle = hwnd;
panelInfo.PanelName = caption;
if (caption.IndexOf("MSFS Touch Panel |") > -1)
{
panelInfo.PanelType = PanelType.MSFSTouchPanel;
return panelInfo;
}
else
return null;
}
return null;
}

View file

@ -4,6 +4,7 @@
{
FlightSimMainWindow,
BuiltInPopout,
CustomPopout
CustomPopout,
MSFSTouchPanel
}
}

View file

@ -31,7 +31,7 @@ namespace MSFSPopoutPanelManager.UI
panelSteps.Controls.Add(_ucPanelConfiguration);
// Set version number
lblVersion.Text += System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
lblVersion.Text += $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Major}.{System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Minor}.{System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Build}";
_controller = new StartUpController(this);
_controller.OnSimConnectionChanged += HandleSimConnectionChanged;

View file

@ -22,7 +22,7 @@ namespace MSFSPopoutPanelManager.UI
dataGridViewPanels.DataSource = _controller.PanelConfigs;
dataGridViewPanels.CellBeginEdit += HandleCellBeginEdit;
dataGridViewPanels.CellValidating += HandleCellValidating;
dataGridViewPanels.CellValueChanged += HandleCellValueChanged;
dataGridViewPanels.CellEndEdit += HandleCellValueChanged;
dataGridViewPanels.CellContentClick += HandleCellValueChanged;
buttonSaveSettings.Click += (source, e) => { dataGridViewPanels.EndEdit(); _controller.SaveSettings(); };

View file

@ -10,7 +10,8 @@ namespace MSFSPopoutPanelManager.UIController
public class PanelConfigurationController : BaseController
{
private const int WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_MOVESIZEEND = 0x000B;
//private const uint EVENT_SYSTEM_MOVESIZEEND = 0x000B;
private const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;
private static PInvoke.WinEventProc _winEvent; // keep this as static to prevent garbage collect or the app will crash
private IntPtr _winEventHook;
@ -52,36 +53,33 @@ namespace MSFSPopoutPanelManager.UIController
public void CellValueChanged(int rowIndex, PanelConfigDataColumn column, object newCellValue)
{
int orignalLeft = PanelConfigs[rowIndex].Left;
if (rowIndex != -1)
{
switch (column)
{
case PanelConfigDataColumn.PanelName:
PanelConfigs[rowIndex].PanelName = Convert.ToString(newCellValue);
PInvoke.SetWindowText(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].PanelName);
break;
case PanelConfigDataColumn.Left:
PanelConfigs[rowIndex].Left = Convert.ToInt32(newCellValue);
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height, true);
break;
case PanelConfigDataColumn.Top:
PanelConfigs[rowIndex].Top = Convert.ToInt32(newCellValue);
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height, true);
break;
case PanelConfigDataColumn.Width:
PanelConfigs[rowIndex].Width = Convert.ToInt32(newCellValue);
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height, true);
MSFSBugPanelShiftWorkaround(PanelConfigs[rowIndex].PanelHandle, orignalLeft, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height);
break;
case PanelConfigDataColumn.Height:
PanelConfigs[rowIndex].Height = Convert.ToInt32(newCellValue);
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height, true);
MSFSBugPanelShiftWorkaround(PanelConfigs[rowIndex].PanelHandle, orignalLeft, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height);
break;
case PanelConfigDataColumn.AlwaysOnTop:
PanelConfigs[rowIndex].AlwaysOnTop = Convert.ToBoolean(newCellValue);
WindowManager.ApplyAlwaysOnTop(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].AlwaysOnTop, new Rectangle(PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height));
break;
case PanelConfigDataColumn.HideTitlebar:
PanelConfigs[rowIndex].HideTitlebar = Convert.ToBoolean(newCellValue);
WindowManager.ApplyHidePanelTitleBar(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].HideTitlebar);
break;
default:
@ -92,64 +90,89 @@ namespace MSFSPopoutPanelManager.UIController
public void CellValueIncrDecr(int rowIndex, PanelConfigDataColumn column, int changeAmount)
{
int orignalLeft = PanelConfigs[rowIndex].Left;
if (rowIndex != -1)
{
switch (column)
{
case PanelConfigDataColumn.Left:
PanelConfigs[rowIndex].Left += changeAmount;
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left + changeAmount, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height, false);
break;
case PanelConfigDataColumn.Top:
PanelConfigs[rowIndex].Top += changeAmount;
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top + changeAmount, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height, false);
break;
case PanelConfigDataColumn.Width:
PanelConfigs[rowIndex].Width += changeAmount;
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width + changeAmount, PanelConfigs[rowIndex].Height, false);
MSFSBugPanelShiftWorkaround(PanelConfigs[rowIndex].PanelHandle, orignalLeft, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width + changeAmount, PanelConfigs[rowIndex].Height);
break;
case PanelConfigDataColumn.Height:
PanelConfigs[rowIndex].Height += changeAmount;
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height + changeAmount, false);
MSFSBugPanelShiftWorkaround(PanelConfigs[rowIndex].PanelHandle, orignalLeft, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height + changeAmount);
break;
default:
return;
}
RefreshDataUI?.Invoke(this, null);
PInvoke.MoveWindow(PanelConfigs[rowIndex].PanelHandle, PanelConfigs[rowIndex].Left, PanelConfigs[rowIndex].Top, PanelConfigs[rowIndex].Width, PanelConfigs[rowIndex].Height, true);
}
}
private void MSFSBugPanelShiftWorkaround(IntPtr handle, int originalLeft, int top, int width, int height)
{
// Fixed MSFS bug, create workaround where on 2nd or later instance of width adjustment, the panel shift to the left by itself
// Wait for system to catch up on panel coordinate that were just applied
System.Threading.Thread.Sleep(200);
Rectangle rectangle;
PInvoke.GetWindowRect(handle, out rectangle);
if (rectangle.Left != originalLeft)
PInvoke.MoveWindow(handle, originalLeft, top, width, height, false);
}
private void HandlePopOutCompleted(object sender, EventArgs e)
{
// Populate panel data
BaseController.ActiveUserPlaneProfile.PanelConfigs.ForEach(p => PanelConfigs.Add(p));
// Setup panel config event hooks
_winEventHook = PInvoke.SetWinEventHook(EVENT_SYSTEM_MOVESIZEEND, EVENT_SYSTEM_MOVESIZEEND, IntPtr.Zero, _winEvent, 0, 0, WINEVENT_OUTOFCONTEXT);
_winEventHook = PInvoke.SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, _winEvent, 0, 0, WINEVENT_OUTOFCONTEXT);
}
private Rectangle _lastWindowRectangle;
private void EventCallback(IntPtr hWinEventHook, uint iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime)
{
if (hWnd == IntPtr.Zero) return;
var panelConfig = PanelConfigs.FirstOrDefault(panel => panel.PanelHandle == hWnd);
if (panelConfig != null)
{
var rowIndex = PanelConfigs.IndexOf(panelConfig);
HightlightSelectedPanel?.Invoke(this, new EventArgs<int>(rowIndex));
if (panelConfig != null)
{
switch (iEvent)
{
case EVENT_SYSTEM_MOVESIZEEND:
case EVENT_OBJECT_LOCATIONCHANGE:
Rectangle winRectangle;
Rectangle clientRectangle;
PInvoke.GetWindowRect(panelConfig.PanelHandle, out winRectangle);
if (_lastWindowRectangle == winRectangle) // ignore duplicate callback messages
return;
_lastWindowRectangle = winRectangle;
Rectangle clientRectangle;
PInvoke.GetClientRect(panelConfig.PanelHandle, out clientRectangle);
panelConfig.Top = winRectangle.Top;
panelConfig.Left = winRectangle.Left;
panelConfig.Top = winRectangle.Top;
panelConfig.Width = clientRectangle.Width + 16;
panelConfig.Height = clientRectangle.Height + 39;
HightlightSelectedPanel?.Invoke(this, new EventArgs<int>(rowIndex));
break;
}

View file

@ -140,10 +140,10 @@ namespace MSFSPopoutPanelManager.UIController
_panelSelectionManager.ShowPanelLocationOverlay(false);
ShowPanelLocationOverlay = false;
if (PanelCoordinates.Count == 0)
OnUIStateChanged?.Invoke(this, new EventArgs<PanelSelectionUIState>(PanelSelectionUIState.ProfileSelected));
else
OnUIStateChanged?.Invoke(this, new EventArgs<PanelSelectionUIState>(PanelSelectionUIState.PanelSelectionCompletedValid));
//if (PanelCoordinates.Count == 0)
// OnUIStateChanged?.Invoke(this, new EventArgs<PanelSelectionUIState>(PanelSelectionUIState.ProfileSelected));
//else
OnUIStateChanged?.Invoke(this, new EventArgs<PanelSelectionUIState>(PanelSelectionUIState.PanelSelectionCompletedValid));
}
}
@ -255,13 +255,13 @@ namespace MSFSPopoutPanelManager.UIController
if (_parentForm != null)
_parentForm.WindowState = FormWindowState.Normal;
if (PanelCoordinates.Count > 0)
{
//if (PanelCoordinates.Count > 0)
//{
ActiveUserPlaneProfile.PanelSourceCoordinates = PanelCoordinates.ToList();
OnUIStateChanged?.Invoke(this, new EventArgs<PanelSelectionUIState>(PanelSelectionUIState.PanelSelectionCompletedValid));
}
else
OnUIStateChanged?.Invoke(this, new EventArgs<PanelSelectionUIState>(PanelSelectionUIState.PanelSelectionCompletedInvalid));
//}
//else
// OnUIStateChanged?.Invoke(this, new EventArgs<PanelSelectionUIState>(PanelSelectionUIState.PanelSelectionCompletedInvalid));
ShowPanelLocationOverlay = true;

View file

@ -1,7 +1,15 @@
# Version History
<hr/>
## Version 3.0.0.0
## Version 3.0.1
* Added workaround for MSFS pop out panel adjustment bug so using the position data grid to adjust width and height will work as expected.
- In MSFS, when changing height or width of a pop out panel (2nd time for same panel and onward), there is an MSFS bug that will unexpectedly shifted the panel by 8px to the left for each adjustment.
* Improved realtime feedback of panel's current coordiates as you move panels around or adjust the top, left, height and width of panel.
* Fixed always on top issue when moving panel around for placement inside other overlay or bezel.
* Added support to create profile just to save locations of built-in panels only (VFR, ATC, etc).
* Added support to save locations for web panels from my other github project "MSFS Touch Panel".
## Version 3.0.0
* Provided 2X pop out and panel separation performance.
* Better support for all screen resolutions.
* Added Cold Start feature. Panels can be popped out and recalled later even when they're not turned on.
@ -11,7 +19,7 @@
* Added realtime readout during panel positioning.
* Added exception tracing to help troubleshoot application issue.
## Vesion 2.2.0.0
## Vesion 2.2.0
* Disabled ability to launch multiple instances of the application.
* Added autostart feature when MSFS starts. The application will create or modify exe.xml. A backup copy of exe.xml will be created.
* Added better support for 4K display resolution and non-standard display resolution.
@ -19,32 +27,32 @@
* Improved panel pop out separation accuracy and performance.
* Updated application packaging to single file executable to reduce file clutter.
## Vesion 2.1.1.0
## Vesion 2.1.1
* Fixed panel separation issue for super ultrawide monitor (for example: 3840x1080)
## Vesion 2.1.0.0
## Vesion 2.1.0
* Added ability to delete built-in profile.
* Added ability to create and delete custom user profile.
* Improved image recognition algorithm using SUSAN Corner block matching algorithm.
## Vesion 2.0.3.0
## Vesion 2.0.3
* Fixed a crash bug when splitting out panel when trying to analyze the last split panel.
* Added PMS50.com GTN750 mod configuration
## Vesion 2.0.2.0
## Vesion 2.0.2
* Added one second delay on mouse click when the application is trying to separate the chained pop out windows.
## Vesion 2.0.1.0
## Vesion 2.0.1
* Changed how screen resolution is detected. Used vertical instead of horizontal resolution to account for ultra wide monitors.
## Version 2.0.0.0
## Version 2.0.0
* Used new image recognition instead of OCR technology to determine pop outs.
* Added auto pop out feature.
* Allowed moving pop out panels using coordinates/width/height after analysis.
* Added additional plane profiles.
* Running on non-native monitor resolution will not work because of image scaling issue when doing image analysis.
## Version 1.2.0.0
## Version 1.2.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.
@ -54,7 +62,7 @@
* Fixed application path issue for not able to find ocrdata.json file at startup.
* Removed MSFS Pop Out Panel Manager is always on top. This is intefering with image operations.
## Version 1.1.0.0
## Version 1.1.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.
@ -62,5 +70,5 @@
* Made application flow more intuitive.
* Fixed various small bugs in the application.
## Version 1.0.0.0
## Version 1.0.0
* Initial Release