mirror of
https://github.com/hawkeye-stan/msfs-popout-panel-manager.git
synced 2024-11-24 14:50:10 +00:00
202 lines
8.5 KiB
C#
202 lines
8.5 KiB
C#
using MSFSPopoutPanelManager.WindowsAgent;
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Threading;
|
|
|
|
namespace MSFSPopoutPanelManager.Orchestration
|
|
{
|
|
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
|
public class PanelAnalyzer
|
|
{
|
|
public static Point GetMagnifyingGlassIconCoordinate(IntPtr hwnd)
|
|
{
|
|
var sourceImage = TakeScreenShot(hwnd);
|
|
|
|
if (sourceImage == null)
|
|
return new Point(0, 0);
|
|
|
|
Rectangle rectangle = WindowActionManager.GetClientRect(hwnd);
|
|
|
|
var panelMenubarTop = GetPanelMenubarTop(sourceImage, rectangle);
|
|
if (panelMenubarTop > sourceImage.Height)
|
|
return Point.Empty;
|
|
|
|
var panelMenubarBottom = GetPanelMenubarBottom(sourceImage, rectangle);
|
|
if (panelMenubarBottom > sourceImage.Height)
|
|
return Point.Empty;
|
|
|
|
var panelsStartingLeft = GetPanelMenubarStartingLeft(sourceImage, rectangle, panelMenubarTop + 5);
|
|
|
|
// The center of magnifying glass icon is around (3.2 x height of menubar) to the right of the panel menubar starting left
|
|
// But need to use higher number here to click the left side of magnifying glass icon because on some panel, the ratio is smaller
|
|
var menubarHeight = panelMenubarBottom - panelMenubarTop;
|
|
var magnifyingIconXCoor = panelsStartingLeft - Convert.ToInt32(menubarHeight * 3.2); // ToDo: play around with this multiplier to find the best for all resolutions
|
|
var magnifyingIconYCoor = panelMenubarTop + Convert.ToInt32(menubarHeight / 2);
|
|
|
|
return new Point(magnifyingIconXCoor, magnifyingIconYCoor);
|
|
}
|
|
|
|
private static Bitmap TakeScreenShot(IntPtr windowHandle)
|
|
{
|
|
if (!WindowActionManager.IsWindow(windowHandle))
|
|
return null;
|
|
|
|
// Set window to foreground so nothing can hide the window
|
|
PInvoke.SetForegroundWindow(windowHandle);
|
|
Thread.Sleep(300);
|
|
|
|
Rectangle rectangle = WindowActionManager.GetWindowRect(windowHandle);
|
|
|
|
Rectangle clientRectangle = WindowActionManager.GetClientRect(windowHandle);
|
|
|
|
// Take a screen shot by removing the titlebar of the window
|
|
var left = rectangle.Left;
|
|
var top = rectangle.Top + (rectangle.Height - clientRectangle.Height) - 8; // 8 pixels adjustments
|
|
|
|
var bmp = new Bitmap(clientRectangle.Width, clientRectangle.Height, PixelFormat.Format24bppRgb);
|
|
|
|
using (Graphics g = Graphics.FromImage(bmp))
|
|
{
|
|
g.CopyFromScreen(new Point(left, top), Point.Empty, rectangle.Size);
|
|
}
|
|
|
|
// Place the above image in the same canvas size as before
|
|
Bitmap backingImage = new Bitmap(rectangle.Width, rectangle.Height);
|
|
using (Graphics gfx = Graphics.FromImage(backingImage))
|
|
{
|
|
using (SolidBrush brush = new SolidBrush(Color.FromArgb(255, 0, 0)))
|
|
{
|
|
gfx.FillRectangle(brush, 0, 0, rectangle.Width, rectangle.Height);
|
|
gfx.DrawImage(bmp, new Point(0, top));
|
|
}
|
|
}
|
|
|
|
return backingImage;
|
|
}
|
|
|
|
private static int GetPanelMenubarTop(Bitmap sourceImage, Rectangle rectangle)
|
|
{
|
|
// Get a snippet of 1 pixel wide vertical strip of windows. We will choose the strip left of center.
|
|
// This is to determine when the actual panel's vertical pixel starts in the window. This will allow accurate sizing of the template image
|
|
var left = Convert.ToInt32((rectangle.Width) * 0.70); // look at around 70% from the left
|
|
var top = sourceImage.Height - rectangle.Height;
|
|
|
|
if (top < 0 || left < 0)
|
|
return -1;
|
|
|
|
unsafe
|
|
{
|
|
var stripData = sourceImage.LockBits(new Rectangle(left, top, 1, rectangle.Height), ImageLockMode.ReadWrite, sourceImage.PixelFormat);
|
|
|
|
int bytesPerPixel = Bitmap.GetPixelFormatSize(stripData.PixelFormat) / 8;
|
|
int heightInPixels = stripData.Height;
|
|
int widthInBytes = stripData.Width * bytesPerPixel;
|
|
byte* ptrFirstPixel = (byte*)stripData.Scan0;
|
|
|
|
for (int y = 0; y < heightInPixels; y++)
|
|
{
|
|
byte* currentLine = ptrFirstPixel + (y * stripData.Stride);
|
|
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
|
|
{
|
|
int red = currentLine[x + 2];
|
|
int green = currentLine[x + 1];
|
|
int blue = currentLine[x];
|
|
|
|
if (red == 255 && green == 255 && blue == 255)
|
|
{
|
|
sourceImage.UnlockBits(stripData);
|
|
return y + top;
|
|
}
|
|
}
|
|
}
|
|
|
|
sourceImage.UnlockBits(stripData);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
private static int GetPanelMenubarBottom(Bitmap sourceImage, Rectangle rectangle)
|
|
{
|
|
// Get a snippet of 1 pixel wide vertical strip of windows. We will choose the strip about 70% from the left of the window
|
|
var left = Convert.ToInt32((rectangle.Width) * 0.7); // look at around 70% from the left
|
|
var top = sourceImage.Height - rectangle.Height;
|
|
|
|
if (top < 0 || left < 0)
|
|
return -1;
|
|
|
|
unsafe
|
|
{
|
|
var stripData = sourceImage.LockBits(new Rectangle(left, top, 1, rectangle.Height), ImageLockMode.ReadWrite, sourceImage.PixelFormat);
|
|
|
|
int bytesPerPixel = Bitmap.GetPixelFormatSize(stripData.PixelFormat) / 8;
|
|
int heightInPixels = stripData.Height;
|
|
int widthInBytes = stripData.Width * bytesPerPixel;
|
|
byte* ptrFirstPixel = (byte*)stripData.Scan0;
|
|
|
|
int menubarBottom = -1;
|
|
|
|
for (int y = 0; y < heightInPixels; y++)
|
|
{
|
|
byte* currentLine = ptrFirstPixel + (y * stripData.Stride);
|
|
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
|
|
{
|
|
int red = currentLine[x + 2];
|
|
int green = currentLine[x + 1];
|
|
int blue = currentLine[x];
|
|
|
|
if (red > 250 && green > 250 && blue > 250) // allows the color to be a little off white (ie. Fenix A30 EFB)
|
|
{
|
|
// found the top of menu bar
|
|
menubarBottom = y + top;
|
|
}
|
|
else if (menubarBottom > -1) /// it is no longer white in color, we hit menubar bottom
|
|
{
|
|
sourceImage.UnlockBits(stripData);
|
|
return menubarBottom;
|
|
}
|
|
}
|
|
}
|
|
|
|
sourceImage.UnlockBits(stripData);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
private static int GetPanelMenubarStartingLeft(Bitmap sourceImage, Rectangle rectangle, int top)
|
|
{
|
|
unsafe
|
|
{
|
|
var stripData = sourceImage.LockBits(new Rectangle(0, top, rectangle.Width, 1), ImageLockMode.ReadWrite, sourceImage.PixelFormat);
|
|
|
|
int bytesPerPixel = Bitmap.GetPixelFormatSize(stripData.PixelFormat) / 8;
|
|
int widthInPixels = stripData.Width;
|
|
int heightInBytes = stripData.Height * bytesPerPixel;
|
|
byte* ptrFirstPixel = (byte*)stripData.Scan0;
|
|
|
|
for (int x = 0; x < widthInPixels; x++)
|
|
{
|
|
byte* currentLine = ptrFirstPixel - (x * bytesPerPixel);
|
|
for (int y = 0; y < heightInBytes; y = y + bytesPerPixel)
|
|
{
|
|
int red = currentLine[y + 2];
|
|
int green = currentLine[y + 1];
|
|
int blue = currentLine[y];
|
|
|
|
if (red > 250 && green > 250 && blue > 250) // allows the color to be a little off white (ie. Fenix A30 EFB)
|
|
{
|
|
sourceImage.UnlockBits(stripData);
|
|
return sourceImage.Width - x;
|
|
}
|
|
}
|
|
}
|
|
|
|
sourceImage.UnlockBits(stripData);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
}
|