diff --git a/CommunityToolkit.App.Shared/Controls/TitleBar/InfoHelper.cs b/CommunityToolkit.App.Shared/Controls/TitleBar/InfoHelper.cs
new file mode 100644
index 0000000..ff1672a
--- /dev/null
+++ b/CommunityToolkit.App.Shared/Controls/TitleBar/InfoHelper.cs
@@ -0,0 +1,34 @@
+using Windows.ApplicationModel;
+using Windows.Storage;
+using Windows.System.Profile;
+
+namespace CommunityToolkit.App.Shared.Controls;
+internal static class InfoHelper
+{
+ public static Version AppVersion { get; } = new Version(
+ Package.Current.Id.Version.Major,
+ Package.Current.Id.Version.Minor,
+ Package.Current.Id.Version.Build,
+ Package.Current.Id.Version.Revision
+ );
+
+ public static Version SystemVersion { get; }
+
+ public static SystemDataPaths SystemDataPath { get; } = SystemDataPaths.GetDefault();
+
+ public static UserDataPaths UserDataPath { get; } = UserDataPaths.GetDefault();
+
+ public static string AppInstalledLocation { get; } = Package.Current.InstalledLocation.Path;
+
+ static InfoHelper()
+ {
+ string systemVersion = AnalyticsInfo.VersionInfo.DeviceFamilyVersion;
+ ulong version = ulong.Parse(systemVersion);
+ SystemVersion = new Version(
+ (int)((version & 0xFFFF000000000000L) >> 48),
+ (int)((version & 0x0000FFFF00000000L) >> 32),
+ (int)((version & 0x00000000FFFF0000L) >> 16),
+ (int)(version & 0x000000000000FFFFL)
+ );
+ }
+}
\ No newline at end of file
diff --git a/CommunityToolkit.App.Shared/Controls/TitleBar/NativeMethods.cs b/CommunityToolkit.App.Shared/Controls/TitleBar/NativeMethods.cs
index 6e50ae3..35bdbef 100644
--- a/CommunityToolkit.App.Shared/Controls/TitleBar/NativeMethods.cs
+++ b/CommunityToolkit.App.Shared/Controls/TitleBar/NativeMethods.cs
@@ -6,42 +6,88 @@
#pragma warning disable CA1060
using System.Runtime.InteropServices;
-using WinRT.Interop;
-using Microsoft.UI;
-using Microsoft.UI.Windowing;
namespace CommunityToolkit.App.Shared.Controls;
-
-public partial class TitleBar : Control
+internal static class NativeMethods
{
- [DllImport("Shcore.dll", SetLastError = true)]
- internal static extern int GetDpiForMonitor(IntPtr hmonitor, Monitor_DPI_Type dpiType, out uint dpiX, out uint dpiY);
+ public enum WindowMessage : int
+ {
+ WM_NCLBUTTONDOWN = 0x00A1,
+ WM_NCRBUTTONDOWN = 0x00A4,
+ WM_SYSCOMMAND = 0x0112,
+ WM_SYSMENU = 0x0313,
+ WM_GETMINMAXINFO = 0x0024
+ }
+ [Flags]
+ public enum WindowStyle : uint
+ {
+ WS_SYSMENU = 0x80000
+ }
- internal enum Monitor_DPI_Type : int
+ [Flags]
+ public enum WindowLongIndexFlags : int
{
- MDT_Effective_DPI = 0,
- MDT_Angular_DPI = 1,
- MDT_Raw_DPI = 2,
- MDT_Default = MDT_Effective_DPI
+ GWL_WNDPROC = -4,
+ GWL_STYLE = -16
}
- private double GetScaleAdjustment()
+ [Flags]
+ public enum SetWindowPosFlags : uint
+ {
+ ///
+ /// Retains the current position (ignores X and Y parameters).
+ ///
+ SWP_NOMOVE = 0x0002
+ }
+
+ public enum SystemCommand
+ {
+ SC_MOUSEMENU = 0xF090,
+ SC_KEYMENU = 0xF100
+ }
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLongW", SetLastError = false)]
+ public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLongPtrW", SetLastError = false)]
+ public static extern int GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static int GetWindowLongAuto(IntPtr hWnd, int nIndex)
{
- IntPtr hWnd = WindowNative.GetWindowHandle(this.Window);
- WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
- DisplayArea displayArea = DisplayArea.GetFromWindowId(wndId, DisplayAreaFallback.Primary);
- IntPtr hMonitor = Win32Interop.GetMonitorFromDisplayId(displayArea.DisplayId);
-
- // Get DPI.
- int result = GetDpiForMonitor(hMonitor, Monitor_DPI_Type.MDT_Default, out uint dpiX, out uint _);
- if (result != 0)
+ if (IntPtr.Size is 8)
{
- throw new Exception("Could not get DPI for monitor.");
+ return GetWindowLongPtr(hWnd, nIndex);
}
+ else
+ {
+ return GetWindowLong(hWnd, nIndex);
+ }
+ }
+
+ [DllImport("user32.dll", EntryPoint = "FindWindowExW", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow);
+
+
+ [DllImport("user32.dll", EntryPoint = "SetWindowLongW", SetLastError = false)]
+ public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+
+ [DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW", SetLastError = false)]
+ public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
- uint scaleFactorPercent = (uint)(((long)dpiX * 100 + (96 >> 1)) / 96);
- return scaleFactorPercent / 100.0;
+ public static IntPtr SetWindowLongAuto(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
+ {
+ if (IntPtr.Size is 8)
+ {
+ return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
+ }
+ else
+ {
+ return SetWindowLong(hWnd, nIndex, dwNewLong);
+ }
}
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, WindowMessage Msg, IntPtr wParam, IntPtr lParam);
}
#pragma warning restore CA1060
#endif
diff --git a/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.WASDK.cs b/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.WASDK.cs
index 41c10c2..9734a00 100644
--- a/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.WASDK.cs
+++ b/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.WASDK.cs
@@ -4,29 +4,21 @@
#if WINDOWS_WINAPPSDK
using Microsoft.UI;
+using Microsoft.UI.Input;
using Microsoft.UI.Windowing;
+using Microsoft.UI.Xaml.Media;
namespace CommunityToolkit.App.Shared.Controls;
-[TemplatePart(Name = nameof(PART_ButtonsHolderColumn), Type = typeof(ColumnDefinition))]
-[TemplatePart(Name = nameof(PART_IconColumn), Type = typeof(ColumnDefinition))]
-[TemplatePart(Name = nameof(PART_TitleColumn), Type = typeof(ColumnDefinition))]
-[TemplatePart(Name = nameof(PART_LeftDragColumn), Type = typeof(ColumnDefinition))]
-[TemplatePart(Name = nameof(PART_ContentColumn), Type = typeof(ColumnDefinition))]
-[TemplatePart(Name = nameof(PART_FooterColumn), Type = typeof(ColumnDefinition))]
-[TemplatePart(Name = nameof(PART_RightDragColumn), Type = typeof(ColumnDefinition))]
-[TemplatePart(Name = nameof(PART_TitleHolder), Type = typeof(StackPanel))]
+[TemplatePart(Name = nameof(PART_FooterPresenter), Type = typeof(ContentPresenter))]
+[TemplatePart(Name = nameof(PART_ContentPresenter), Type = typeof(ContentPresenter))]
public partial class TitleBar : Control
{
- ColumnDefinition? PART_ButtonsHolderColumn;
- ColumnDefinition? PART_IconColumn;
- ColumnDefinition? PART_TitleColumn;
- ColumnDefinition? PART_LeftDragColumn;
- ColumnDefinition? PART_ContentColumn;
- ColumnDefinition? PART_FooterColumn;
- ColumnDefinition? PART_RightDragColumn;
- StackPanel? PART_TitleHolder;
+ WndProcHelper WndProcHelper;
+ MenuFlyout MenuFlyout;
+ ContentPresenter? PART_ContentPresenter;
+ ContentPresenter? PART_FooterPresenter;
private void SetWASDKTitleBar()
{
@@ -39,6 +31,16 @@ private void SetWASDKTitleBar()
{
Window.AppWindow.TitleBar.ExtendsContentIntoTitleBar = true;
+ if (this.ContextFlyout != null && this.ContextFlyout is MenuFlyout menuFlyout)
+ {
+ this.MenuFlyout = menuFlyout;
+ WndProcHelper = new WndProcHelper(this.Window);
+ WndProcHelper.RegisterWndProc(WindowWndProc);
+ WndProcHelper.RegisterInputNonClientPointerSourceWndProc(InputNonClientPointerSourceWndProc);
+ }
+
+ this.Window.SizeChanged -= Window_SizeChanged;
+ this.Window.SizeChanged += Window_SizeChanged;
this.Window.Activated -= Window_Activated;
this.Window.Activated += Window_Activated;
@@ -51,15 +53,8 @@ private void SetWASDKTitleBar()
};
}
- // Set the width of padding columns in the UI.
- PART_ButtonsHolderColumn = GetTemplateChild(nameof(PART_ButtonsHolderColumn)) as ColumnDefinition;
- PART_IconColumn = GetTemplateChild(nameof(PART_IconColumn)) as ColumnDefinition;
- PART_TitleColumn = GetTemplateChild(nameof(PART_TitleColumn)) as ColumnDefinition;
- PART_LeftDragColumn = GetTemplateChild(nameof(PART_LeftDragColumn)) as ColumnDefinition;
- PART_ContentColumn = GetTemplateChild(nameof(PART_ContentColumn)) as ColumnDefinition;
- PART_RightDragColumn = GetTemplateChild(nameof(PART_RightDragColumn)) as ColumnDefinition;
- PART_FooterColumn = GetTemplateChild(nameof(PART_FooterColumn)) as ColumnDefinition;
- PART_TitleHolder = GetTemplateChild(nameof(PART_TitleHolder)) as StackPanel;
+ PART_ContentPresenter = GetTemplateChild(nameof(PART_ContentPresenter)) as ContentPresenter;
+ PART_FooterPresenter = GetTemplateChild(nameof(PART_FooterPresenter)) as ContentPresenter;
// Get caption button occlusion information.
int CaptionButtonOcclusionWidthRight = Window.AppWindow.TitleBar.RightInset;
@@ -83,6 +78,11 @@ private void SetWASDKTitleBar()
}
}
+ private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs args)
+ {
+ UpdateVisualStateAndDragRegion(args.Size);
+ }
+
private void UpdateCaptionButtons(FrameworkElement rootElement)
{
Window.AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
@@ -108,6 +108,7 @@ private void ResetWASDKTitleBar()
}
Window.AppWindow.TitleBar.ExtendsContentIntoTitleBar = false;
+ this.Window.SizeChanged -= Window_SizeChanged;
this.Window.Activated -= Window_Activated;
SizeChanged -= this.TitleBar_SizeChanged;
Window.AppWindow.TitleBar.ResetToDefault();
@@ -125,46 +126,119 @@ private void Window_Activated(object sender, WindowActivatedEventArgs args)
}
}
- private void SetDragRegionForCustomTitleBar()
+ public void SetDragRegionForCustomTitleBar()
+ {
+ if (AutoConfigureCustomTitleBar && Window != null)
+ {
+ ClearDragRegions(NonClientRegionKind.Passthrough);
+ SetDragRegion(NonClientRegionKind.Passthrough, PART_ContentPresenter, PART_FooterPresenter, PART_ButtonHolder);
+ }
+ }
+
+ public double GetRasterizationScaleForElement(UIElement element)
+ {
+ if (element.XamlRoot != null)
+ {
+ return element.XamlRoot.RasterizationScale;
+ }
+ return 0.0;
+ }
+
+ public void SetDragRegion(NonClientRegionKind nonClientRegionKind, params FrameworkElement[] frameworkElements)
+ {
+ var nonClientInputSrc = InputNonClientPointerSource.GetForWindowId(Window.AppWindow.Id);
+ List rects = new List();
+ var scale = GetRasterizationScaleForElement(this);
+
+ foreach (var frameworkElement in frameworkElements)
+ {
+ if (frameworkElement == null)
+ {
+ continue;
+ }
+ GeneralTransform transformElement = frameworkElement.TransformToVisual(null);
+ Windows.Foundation.Rect bounds = transformElement.TransformBounds(new Windows.Foundation.Rect(0, 0, frameworkElement.ActualWidth, frameworkElement.ActualHeight));
+ var transparentRect = new Windows.Graphics.RectInt32(
+ _X: (int)Math.Round(bounds.X * scale),
+ _Y: (int)Math.Round(bounds.Y * scale),
+ _Width: (int)Math.Round(bounds.Width * scale),
+ _Height: (int)Math.Round(bounds.Height * scale)
+ );
+ rects.Add(transparentRect);
+ }
+ if (rects.Count > 0)
+ {
+ nonClientInputSrc.SetRegionRects(nonClientRegionKind, rects.ToArray());
+ }
+ }
+
+ public void ClearDragRegions(NonClientRegionKind nonClientRegionKind)
+ {
+ var noninputsrc = InputNonClientPointerSource.GetForWindowId(Window.AppWindow.Id);
+ noninputsrc.ClearRegionRects(nonClientRegionKind);
+ }
+
+ private IntPtr InputNonClientPointerSourceWndProc(IntPtr hWnd, NativeMethods.WindowMessage Msg, IntPtr wParam, IntPtr lParam)
+ {
+ switch (Msg)
+ {
+ case NativeMethods.WindowMessage.WM_NCLBUTTONDOWN:
+ {
+ if (MenuFlyout.IsOpen)
+ {
+ MenuFlyout.Hide();
+ }
+ break;
+ }
+ case NativeMethods.WindowMessage.WM_NCRBUTTONDOWN:
+ {
+ PointInt32 pt = new PointInt32(lParam.ToInt32() & 0xFFFF, lParam.ToInt32() >> 16);
+ FlyoutShowOptions options = new FlyoutShowOptions();
+ options.ShowMode = FlyoutShowMode.Standard;
+ options.Position = InfoHelper.SystemVersion.Build >= 22000 ?
+ new Windows.Foundation.Point((pt.X - this.Window.AppWindow.Position.X - 8) / XamlRoot.RasterizationScale, (pt.Y - this.Window.AppWindow.Position.Y) / XamlRoot.RasterizationScale) :
+ new Windows.Foundation.Point(pt.X - this.Window.AppWindow.Position.X - 8, pt.Y - this.Window.AppWindow.Position.Y);
+
+ MenuFlyout.ShowAt(this, options);
+ return (IntPtr)0;
+ }
+ }
+ return WndProcHelper.CallInputNonClientPointerSourceWindowProc(hWnd, Msg, wParam, lParam);
+ }
+
+ private IntPtr WindowWndProc(IntPtr hWnd, NativeMethods.WindowMessage Msg, IntPtr wParam, IntPtr lParam)
{
- if (AutoConfigureCustomTitleBar && Window != null && PART_RightPaddingColumn != null && PART_LeftPaddingColumn != null)
+ switch (Msg)
{
- double scaleAdjustment = GetScaleAdjustment();
-
- PART_RightPaddingColumn.Width = new GridLength(Window.AppWindow.TitleBar.RightInset / scaleAdjustment);
- PART_LeftPaddingColumn.Width = new GridLength(Window.AppWindow.TitleBar.LeftInset / scaleAdjustment);
-
- List dragRectsList = new();
-
- Windows.Graphics.RectInt32 dragRectL;
- dragRectL.X = (int)((PART_LeftPaddingColumn.ActualWidth
- + PART_ButtonsHolderColumn!.ActualWidth)
- * scaleAdjustment);
- dragRectL.Y = 0;
- dragRectL.Height = (int)(this.ActualHeight * scaleAdjustment);
- dragRectL.Width = (int)((PART_IconColumn!.ActualWidth
- + PART_TitleColumn!.ActualWidth
- + PART_LeftDragColumn!.ActualWidth)
- * scaleAdjustment);
- dragRectsList.Add(dragRectL);
-
- Windows.Graphics.RectInt32 dragRectR;
- dragRectR.X = (int)((PART_LeftPaddingColumn.ActualWidth
- + PART_IconColumn.ActualWidth
- + PART_ButtonsHolderColumn!.ActualWidth
- + PART_TitleHolder!.ActualWidth
- + PART_LeftDragColumn.ActualWidth
- + PART_ContentColumn!.ActualWidth)
- * scaleAdjustment);
- dragRectR.Y = 0;
- dragRectR.Height = (int)(this.ActualHeight * scaleAdjustment);
- dragRectR.Width = (int)(PART_RightDragColumn!.ActualWidth * scaleAdjustment);
- dragRectsList.Add(dragRectR);
-
- Windows.Graphics.RectInt32[] dragRects = dragRectsList.ToArray();
-
- Window.AppWindow.TitleBar.SetDragRectangles(dragRects);
+ case NativeMethods.WindowMessage.WM_SYSMENU:
+ {
+ return (IntPtr)0;
+ }
+
+ case NativeMethods.WindowMessage.WM_SYSCOMMAND:
+ {
+ NativeMethods.SystemCommand sysCommand = (NativeMethods.SystemCommand)(wParam.ToInt32() & 0xFFF0);
+
+ if (sysCommand is NativeMethods.SystemCommand.SC_MOUSEMENU)
+ {
+ FlyoutShowOptions options = new FlyoutShowOptions();
+ options.Position = new Windows.Foundation.Point(0, 15);
+ options.ShowMode = FlyoutShowMode.Standard;
+ MenuFlyout.ShowAt(null, options);
+ return (IntPtr)0;
+ }
+ else if (sysCommand is NativeMethods.SystemCommand.SC_KEYMENU)
+ {
+ FlyoutShowOptions options = new FlyoutShowOptions();
+ options.Position = new Windows.Foundation.Point(0, 45);
+ options.ShowMode = FlyoutShowMode.Standard;
+ MenuFlyout.ShowAt(null, options);
+ return (IntPtr)0;
+ }
+ break;
+ }
}
+ return WndProcHelper.CallWindowProc(hWnd, Msg, wParam, lParam);
}
}
#endif
diff --git a/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.cs b/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.cs
index 0e19b45..7814cd4 100644
--- a/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.cs
+++ b/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.cs
@@ -24,6 +24,7 @@ namespace CommunityToolkit.App.Shared.Controls;
[TemplatePart(Name = PartPaneButton, Type = typeof(Button))]
[TemplatePart(Name = nameof(PART_LeftPaddingColumn), Type = typeof(ColumnDefinition))]
[TemplatePart(Name = nameof(PART_RightPaddingColumn), Type = typeof(ColumnDefinition))]
+[TemplatePart(Name = nameof(PART_ButtonHolder), Type = typeof(StackPanel))]
public partial class TitleBar : Control
{
@@ -64,6 +65,7 @@ public partial class TitleBar : Control
ColumnDefinition? PART_LeftPaddingColumn;
ColumnDefinition? PART_RightPaddingColumn;
+ StackPanel? PART_ButtonHolder;
public TitleBar()
{
@@ -74,6 +76,7 @@ protected override void OnApplyTemplate()
{
PART_LeftPaddingColumn = GetTemplateChild(nameof(PART_LeftPaddingColumn)) as ColumnDefinition;
PART_RightPaddingColumn = GetTemplateChild(nameof(PART_RightPaddingColumn)) as ColumnDefinition;
+ ConfigureButtonHolder();
Configure();
if (GetTemplateChild(PartBackButton) is Button backButton)
{
@@ -97,7 +100,12 @@ protected override void OnApplyTemplate()
private void TitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
{
- if (e.NewSize.Width <= CompactStateBreakpoint)
+ UpdateVisualStateAndDragRegion(e.NewSize);
+ }
+
+ private void UpdateVisualStateAndDragRegion(Windows.Foundation.Size size)
+ {
+ if (size.Width <= CompactStateBreakpoint)
{
if (Content != null || Footer != null)
{
@@ -109,7 +117,7 @@ private void TitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
VisualStateManager.GoToState(this, WideState, true);
}
-#if WINDOWS_WINAPPSDK
+#if WINAPPSDK
SetDragRegionForCustomTitleBar();
#endif
}
@@ -124,12 +132,34 @@ private void PaneButton_Click(object sender, RoutedEventArgs e)
PaneButtonClick?.Invoke(this, new RoutedEventArgs());
}
+ private void ConfigureButtonHolder()
+ {
+ if (PART_ButtonHolder != null)
+ {
+ PART_ButtonHolder.SizeChanged -= PART_ButtonHolder_SizeChanged;
+ }
+
+ PART_ButtonHolder = GetTemplateChild(nameof(PART_ButtonHolder)) as StackPanel;
+
+ if(PART_ButtonHolder != null)
+ {
+ PART_ButtonHolder.SizeChanged += PART_ButtonHolder_SizeChanged;
+ }
+ }
+
+ private void PART_ButtonHolder_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+#if WINAPPSDK
+ SetDragRegionForCustomTitleBar();
+#endif
+ }
+
private void Configure()
{
#if WINDOWS_UWP && !HAS_UNO
SetUWPTitleBar();
#endif
-#if WINDOWS_WINAPPSDK
+#if WINAPPSDK
SetWASDKTitleBar();
#endif
}
@@ -139,7 +169,7 @@ public void Reset()
#if WINDOWS_UWP && !HAS_UNO
ResetUWPTitleBar();
#endif
-#if WINDOWS_WINAPPSDK
+#if WINAPPSDK
ResetWASDKTitleBar();
#endif
}
@@ -185,7 +215,7 @@ private void Update()
VisualStateManager.GoToState(this, FooterCollapsedState, true);
}
-#if WINDOWS_WINAPPSDK
+#if WINAPPSDK
SetDragRegionForCustomTitleBar();
#endif
}
diff --git a/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.xaml b/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.xaml
index 820dcc2..ce7942e 100644
--- a/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.xaml
+++ b/CommunityToolkit.App.Shared/Controls/TitleBar/TitleBar.xaml
@@ -19,7 +19,7 @@
@@ -165,7 +165,7 @@
Grid.Column="2"
Grid.ColumnSpan="6"
Background="Transparent" />
-
-
@@ -278,8 +277,7 @@
win:AutomationProperties.AccessibilityView="Raw">
-
@@ -304,7 +302,6 @@
-
@@ -374,8 +371,7 @@
win:AutomationProperties.AccessibilityView="Raw">
-
diff --git a/CommunityToolkit.App.Shared/Controls/TitleBar/WndProcHelper.cs b/CommunityToolkit.App.Shared/Controls/TitleBar/WndProcHelper.cs
new file mode 100644
index 0000000..b1d0a87
--- /dev/null
+++ b/CommunityToolkit.App.Shared/Controls/TitleBar/WndProcHelper.cs
@@ -0,0 +1,51 @@
+#if WINDOWS_WINAPPSDK
+using System.Runtime.InteropServices;
+using WinRT.Interop;
+
+namespace CommunityToolkit.App.Shared.Controls;
+internal class WndProcHelper
+{
+ public delegate IntPtr WNDPROC(IntPtr hWnd, NativeMethods.WindowMessage Msg, IntPtr wParam, IntPtr lParam);
+
+ private IntPtr Handle { get; set; }
+ private WNDPROC newMainWindowWndProc = null;
+ private IntPtr oldMainWindowWndProc = IntPtr.Zero;
+
+ private WNDPROC newInputNonClientPointerSourceWndProc = null;
+ private IntPtr oldInputNonClientPointerSourceWndProc = IntPtr.Zero;
+
+ public WndProcHelper(Window window)
+ {
+ Handle = WindowNative.GetWindowHandle(window);
+ }
+
+ public IntPtr CallWindowProc(IntPtr hWnd, NativeMethods.WindowMessage Msg, IntPtr wParam, IntPtr lParam)
+ {
+ return NativeMethods.CallWindowProc(oldMainWindowWndProc, hWnd, Msg, wParam, lParam);
+ }
+
+ public IntPtr CallInputNonClientPointerSourceWindowProc(IntPtr hWnd, NativeMethods.WindowMessage Msg, IntPtr wParam, IntPtr lParam)
+ {
+ return NativeMethods.CallWindowProc(oldInputNonClientPointerSourceWndProc, hWnd, Msg, wParam, lParam);
+ }
+ public void RegisterWndProc(WNDPROC wndProc)
+ {
+ newMainWindowWndProc = wndProc;
+ oldMainWindowWndProc = NativeMethods.SetWindowLongAuto(Handle, (int)NativeMethods.WindowLongIndexFlags.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(newMainWindowWndProc));
+ }
+
+ public void RegisterInputNonClientPointerSourceWndProc(WNDPROC wndProc)
+ {
+ IntPtr inputNonClientPointerSourceHandle = NativeMethods.FindWindowEx(Handle, IntPtr.Zero, "InputNonClientPointerSource", null);
+
+ if (inputNonClientPointerSourceHandle != IntPtr.Zero)
+ {
+ int style = NativeMethods.GetWindowLongAuto(Handle, (int)NativeMethods.WindowLongIndexFlags.GWL_STYLE);
+ NativeMethods.SetWindowLongAuto(Handle, (int)NativeMethods.WindowLongIndexFlags.GWL_STYLE, (IntPtr)(style & ~(int)NativeMethods.WindowStyle.WS_SYSMENU));
+
+ newInputNonClientPointerSourceWndProc = wndProc;
+ oldInputNonClientPointerSourceWndProc = NativeMethods.SetWindowLongAuto(inputNonClientPointerSourceHandle, (int)NativeMethods.WindowLongIndexFlags.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(newInputNonClientPointerSourceWndProc));
+ }
+ }
+}
+#endif
\ No newline at end of file