mirror of
https://github.com/peter-tanner/Vivado-Dark-Mode-Windows-demo.git
synced 2024-11-30 09:00:31 +08:00
227 lines
8.7 KiB
C#
227 lines
8.7 KiB
C#
using System.Runtime.InteropServices;
|
|
using Karna.Magnification;
|
|
using System.Windows.Forms;
|
|
using System.Text;
|
|
using System.Diagnostics;
|
|
|
|
namespace WindowOverlayApp
|
|
{
|
|
public partial class Form1 : Form
|
|
{
|
|
const int SWP_NOACTIVATE = 0x0010;
|
|
const int SWP_SHOWWINDOW = 0x0040;
|
|
const int SWP_NOMOVE = 0x0002;
|
|
const int SWP_NOSIZE = 0x0001;
|
|
|
|
// Window event constants
|
|
const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;
|
|
const uint EVENT_SYSTEM_FOREGROUND = 0x0003; // Triggers when a window comes to the foreground
|
|
const uint WINEVENT_OUTOFCONTEXT = 0x0000;
|
|
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
static extern IntPtr GetParent(IntPtr hWnd);
|
|
|
|
[DllImport("user32.dll")]
|
|
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
static extern bool GetClientRect(IntPtr hWnd, ref RECT lpRect);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc,
|
|
uint idProcess, uint idThread, uint dwFlags);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
|
|
|
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
|
|
|
[DllImport("user32.dll")]
|
|
static extern IntPtr GetForegroundWindow();
|
|
|
|
const int GW_HWNDFIRST = 0;
|
|
const int GW_HWNDLAST = 1;
|
|
const int GW_HWNDNEXT = 2;
|
|
const int GW_HWNDPREV = 3;
|
|
const int GW_OWNER = 4;
|
|
const int GW_CHILD = 5;
|
|
const int GW_ENABLEDPOPUP = 6;
|
|
|
|
// Delegate for WinEvent hook
|
|
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
|
|
|
|
private IntPtr notepadHandle = IntPtr.Zero;
|
|
private IntPtr winEventHook = IntPtr.Zero;
|
|
private IntPtr foregroundEventHook = IntPtr.Zero;
|
|
private WinEventDelegate winEventDelegate, foregroundEventDelegate;
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct RECT
|
|
{
|
|
public int Left;
|
|
public int Top;
|
|
public int Right;
|
|
public int Bottom;
|
|
}
|
|
|
|
Magnifier magnifier;
|
|
private System.Windows.Forms.Timer resizeTimer;
|
|
private bool isResizing = false;
|
|
|
|
public Form1()
|
|
{
|
|
InitializeComponent();
|
|
|
|
winEventDelegate = new WinEventDelegate(WinEventProc);
|
|
foregroundEventDelegate = new WinEventDelegate(ForegroundEventProc);
|
|
|
|
magnifier = new Magnifier(this);
|
|
}
|
|
|
|
const int WS_EX_TOOLWINDOW = 0x00000080; // Hides from Alt+Tab
|
|
const int WS_EX_APPWINDOW = 0x00040000; // Forces a window to appear in Alt+Tab
|
|
const int WS_EX_NOACTIVATE = 0x08000000; // Prevents the window from receiving focus
|
|
protected override CreateParams CreateParams
|
|
{
|
|
get
|
|
{
|
|
const int WS_EX_LAYERED = 0x80000;
|
|
const int WS_EX_TRANSPARENT = 0x20;
|
|
CreateParams cp = base.CreateParams;
|
|
// Hide the window from Alt+Tab and taskbar by using WS_EX_TOOLWINDOW
|
|
cp.ExStyle |= WS_EX_TOOLWINDOW;
|
|
cp.ExStyle |= WS_EX_LAYERED;
|
|
cp.ExStyle |= WS_EX_TRANSPARENT;
|
|
return cp;
|
|
}
|
|
}
|
|
|
|
protected override void OnLoad(EventArgs e)
|
|
{
|
|
base.OnLoad(e);
|
|
|
|
// Find the Notepad window by its title (change this if your Notepad title is different)
|
|
notepadHandle = FindWindow(null, "Vivado 2024.1");
|
|
|
|
if (notepadHandle != IntPtr.Zero)
|
|
{
|
|
// Hook into the window events to track movements, resizes, and other changes
|
|
winEventHook = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, winEventDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);
|
|
foregroundEventHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, foregroundEventDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);
|
|
UpdateOverlayWindow(); // Update position and size at load
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("Notepad window not found.");
|
|
}
|
|
}
|
|
|
|
protected override void OnFormClosed(FormClosedEventArgs e)
|
|
{
|
|
base.OnFormClosed(e);
|
|
// Unhook the event when closing the form
|
|
if (winEventHook != IntPtr.Zero)
|
|
{
|
|
UnhookWinEvent(winEventHook);
|
|
}
|
|
}
|
|
|
|
private RECT lastRect; // To store the last known rectangle
|
|
|
|
private void UpdateOverlayWindow()
|
|
{
|
|
SetWindowPos(this.Handle, -1, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
if (notepadHandle == IntPtr.Zero)
|
|
return;
|
|
|
|
// Get the position and size of the Notepad window
|
|
RECT rect = new RECT();
|
|
if (GetWindowRect(notepadHandle, ref rect))
|
|
{
|
|
// Adjust for window borders in Aero
|
|
const int windowBorder = 2;
|
|
const int aeroBorder = 7 + windowBorder;
|
|
const int aeroBorderTop = -1 + windowBorder;
|
|
|
|
rect.Left += aeroBorder;
|
|
rect.Top += aeroBorderTop;
|
|
rect.Right -= aeroBorder;
|
|
rect.Bottom -= aeroBorder;
|
|
|
|
// Set this form's size and position to match Notepad's
|
|
this.Size = new Size(rect.Right - rect.Left, rect.Bottom - rect.Top);
|
|
this.Location = new Point(rect.Left, rect.Top);
|
|
|
|
// Overlay this window on top of Notepad's window
|
|
|
|
//magnifier.ResizeMagnifier();
|
|
//SetWindowPos(this.Handle, GetWindow(notepadHandle, GW_OWNER), 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
SetWindowPos(this.Handle, -1, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
magnifier.UpdateMaginifier();
|
|
}
|
|
}
|
|
|
|
|
|
// This method is called whenever the Notepad window changes position or size
|
|
private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
|
{
|
|
if (hwnd == notepadHandle)
|
|
{
|
|
UpdateOverlayWindow(); // Adjust overlay window whenever the target window moves or resizes
|
|
}
|
|
}
|
|
|
|
private void ForegroundEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
|
{
|
|
if (IsAnyParentMatching(hwnd, notepadHandle))
|
|
{
|
|
UpdateOverlayWindow();
|
|
} else if (!IsWindowClass(hwnd, "ForegroundStaging") && !IsWindowClass(hwnd, "MultitaskingViewFrame"))
|
|
{
|
|
SetWindowPos(this.Handle, 1, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
}
|
|
}
|
|
|
|
static bool IsAnyParentMatching(IntPtr hwnd, IntPtr targetHwnd)
|
|
{
|
|
IntPtr currentHwnd = hwnd;
|
|
|
|
while (currentHwnd != IntPtr.Zero)
|
|
{
|
|
if (currentHwnd == targetHwnd)
|
|
return true;
|
|
|
|
currentHwnd = GetParent(currentHwnd);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
static bool IsWindowClass(IntPtr hWnd, string className)
|
|
{
|
|
StringBuilder wClassName = new StringBuilder(className.Length+20);
|
|
GetClassName(hWnd, wClassName, className.Length+20);
|
|
Debug.WriteLine(wClassName);
|
|
return wClassName.ToString() == className;
|
|
}
|
|
|
|
private void textBox1_TextChanged(object sender, EventArgs e)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|