Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AppWindow.Position, AppWindow.Move, and AppWindow.TitleBar.Height all are faulty and give wrong results. AppWindow.TitleBar.Title does not show up in Window (simple repro project included) #17679

Open
jonmdev opened this issue Sep 27, 2023 · 2 comments
Labels
area-controls-window Window platform/windows 🪟 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK)
Milestone

Comments

@jonmdev
Copy link

jonmdev commented Sep 27, 2023

Description

It is useful in UWP to be able to manage your own click events as if one uses an overlay (eg. similar to built in WindowOverlay) to catch clicks, there is no way to selectively pass those clicks on to objects that you wish to handle their own clicks for (like to text fields). Once an overlay catches the click it is "consumed" and it seems there is no way to create a new cloned event and introduce it into another part of the hierarchy.

It would be nice if we had some way to manually put in click events to parts of the hierarchy in UWP. Like in Android, we have Android.Views.View.DispatchTouchEvent(MotionEvent). In iOS we can build an overlay and override Hit Detection to select the View to take our clicks which accomplishes the same. But no similar function seems available in UWP (?).

Until such function is available, we must be able to get our clicks in Windows another way to not disrupt the natural function of complex objects underneath.

To gain access to the raw Windows clicks, one can use a package like SharpHook:
https://github.com/TolikPylypchuk/SharpHook
https://www.nuget.org/packages/SharpHook/

This integrates well but cannot provide accurate results as Maui has several glitches in getting window data:

  1. Microsoft.UI.Windowing.AppWindow.Move and Microsoft.UI.Windowing.AppWindow.Position both are off target in the x-dimension by a certain amount.
  2. Microsoft.UI.Windowing.AppWindow.TitleBar.Height returns zero always.
  3. Setting Microsoft.UI.Windowing.AppWindow.TitleBar.Title to any string does not actually change the Window title.

We need these glitches fixed in order to get accurate relative positions otherwise by the mouse hook. Given point #3, I suspect there is some disconnection in the internal wiring and we are not reaching the TitleBar at all.

Steps to Reproduce

Reproduction Steps:

  1. Create a new Maui file in Visual Studio 2022 using .NET 7.0 named "Windows Window Position Bug"

  2. Add nuget package for SharpHook: https://www.nuget.org/packages/SharpHook/

  3. Copy/paste to replace App.xaml.cs with the following code:

using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using SharpHook;
using System.Numerics;
using System.Diagnostics;
using Microsoft.Maui.Controls.Shapes;

namespace Windows_Window_Position_Bug {

    public partial class App : Application {
        Window window = null;
        TaskPoolGlobalHook hook = null;
        ContentPage mainPage;
        private IntPtr hWnd = IntPtr.Zero;
        Border clickPosBorder;

#if WINDOWS
        Microsoft.UI.Windowing.AppWindow appWindow = null;
        Microsoft.UI.WindowId windowId;
        Microsoft.UI.Xaml.Window windowPlatformView;
#endif
        public App() {
            InitializeComponent();
            mainPage = new();
            this.MainPage = mainPage;

            AbsoluteLayout abs = new();
            abs.BackgroundColor = Colors.Bisque;
            mainPage.Content = abs;

            //border should follow your clicks and be centered over them, but will instead be off by the x-deviation of the window position and y-deviation of the title bar
            clickPosBorder = new();
            clickPosBorder.WidthRequest = clickPosBorder.HeightRequest = 20;
            clickPosBorder.StrokeShape = new RoundRectangle() { CornerRadius = 10 };
            clickPosBorder.StrokeThickness = 2;
            clickPosBorder.Stroke = Colors.DarkCyan;
            clickPosBorder.BackgroundColor = Colors.Red;
            abs.Children.Add(clickPosBorder);
            
        }

        protected override Window CreateWindow(IActivationState activationState) {
            if (window != null) {
                window.HandlerChanged -= windowHandlerChanged;
            }
            window = base.CreateWindow(activationState);

            window.HandlerChanged += windowHandlerChanged;
            window.Destroying += windowDestroyed;
            return window;
        }

        private void windowDestroyed(object sender, EventArgs e) {
            if (hook != null) {
                hook.MousePressed -= hookMousePressed;
                hook.Dispose();
            }
        }

        public void windowHandlerChanged(object sender, EventArgs e) {
#if WINDOWS
            if (hook == null) {
                hook = new TaskPoolGlobalHook();
                hook.RunAsync();
                hook.MousePressed += hookMousePressed;
            }
            if (window != null && window.Handler !=null) {
                windowPlatformView = (window.Handler as WindowHandler).PlatformView;
                hWnd = WinRT.Interop.WindowNative.GetWindowHandle(windowPlatformView);
                windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);
                appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);

                //setting title name should show up in the title bar of the project but it does not, this will however show up in the name in the status bar
                appWindow.Title = "WINDOW TITLE";

                //this should move the window to 0,0 but there will be an x-deviation away from this position (glitch)
                appWindow.Move(new Windows.Graphics.PointInt32((int)0, (int)0));
                Debug.WriteLine("INITIALIZED WINDOW TO POINT: " + appWindow.Position.X + " " + appWindow.Position.Y);
            }
#endif
        }

        void hookMousePressed(object sender, MouseHookEventArgs e) {
#if WINDOWS
            MainThread.BeginInvokeOnMainThread(() => {
                if (appWindow != null) {

                    //find window position
                    Vector2 windowPos = new Vector2(appWindow.Position.X, appWindow.Position.Y); //find window position in raw piels
                    Vector2 windowPosMinusTitleBar = windowPos - new Vector2(0, appWindow.TitleBar.Height);

                    //find relative position of click
                    Vector2 rawHookClickPos = new Vector2(e.RawEvent.Mouse.X, e.RawEvent.Mouse.Y); // get raw click from mouse hook in raw pixels
                    double rasterizationScale = mainPage.ToPlatform(mainPage.Handler.MauiContext).XamlRoot.RasterizationScale; //get percent screen scaling
                    Vector2 clickRelative = rawHookClickPos - windowPosMinusTitleBar;
                    clickRelative *= 1f /(float)rasterizationScale;

                    if (clickPosBorder != null) {
                        clickPosBorder.TranslationX = clickRelative.X - clickPosBorder.Width * 0.5;
                        clickPosBorder.TranslationY = clickRelative.Y - clickPosBorder.Height * 0.5;
                    }

                    //debug output
                    string debugText = "MOUSE PRESSED";
                    debugText += "\n- windowPos: " + windowPos;
                    debugText += "\n- rawHookClickPos: " + rawHookClickPos;
                    debugText += "\n- clickRelative: " + clickRelative;
                    debugText += "\n- TitleBar.Height: " + appWindow.TitleBar.Height; //title bar height will always debug out as zero although it is clearly not zero
                    Debug.WriteLine(debugText);
                }
            });
#endif
        }
    }
}
  1. This should initialize the app with the window at screen (0,0), and while the app will claim to have done so, it will actually have a left screen gap (setting x position to 0 does not put screen aligned with zero left position).

  2. AppWindow.TitleBar.Height will debug out on clicking as zero height, so one cannot subtract the height of the title bar from raw click positions to get the true "in app" window click position.

  3. Clicking anywhere on screen should put the red ring around your cursor, but the position will be off by the x-deviation of the left window gap, and the y-deviation of the height of the title bar.

  4. The window title should be set to "WINDOW TITLE" and it will show this in the status bar. However, the title bar itself will still have no name showing.

window glitch 2

What Should Happen:

  • App.Window.TitleBar.Height should return the height of the grey title bar (top application bar with the maximize minimize buttons) so we can compensate for it with the click position.
  • Setting AppWindow.Position.Move to (0,0) should put the window perfectly aligned to x=0, y=0 so AppWindow.Position returns accurate X & Y results at any given window position.
  • Setting App.Window.Title should show up in the title bar and not just the status bar

Link to public reproduction project repository

https://github.com/jonmdev/Windows-Window-Position-Bug

Version with bug

10.0.92

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Windows

Affected platform versions

Windows 10/11, .NET 7.0, .NET 8.0

Did you find any workaround?

No workaround except manually guessing or estimating size of x-gap and expected height of title bar and compensating accordingly.

Relevant log output

See above

@jonmdev jonmdev added the t/bug Something isn't working label Sep 27, 2023
@XamlTest XamlTest added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed labels Oct 7, 2023
@XamlTest
Copy link

XamlTest commented Oct 7, 2023

Verified this on Visual Studio Enterprise 17.8.0 Preview 2.0(8.0.0-rc.1.9171). Repro on Windows 11 with below Project:
17679.zip

@jonmdev jonmdev changed the title AppWindow.Position, AppWindow.Move, and AppWindow.TitleBar all are faulty and give wrong results (simple code to reproduce included) AppWindow.Position, AppWindow.Move, and AppWindow.TitleBar.Height all are faulty and give wrong results. AppWindow.TitleBar.Title does not show up in Window (simple repro project included) Oct 9, 2023
@jonmdev
Copy link
Author

jonmdev commented Oct 9, 2023

I updated the project code and posted a GitHub repository demonstrating it. Now you can click anywhere in window and see the deviation that is resulting from the x-gap and titlebar height returning 0.

I also noticed setting AppWindow.TitleBar.Title is broken too and only shows up in the status bar not the Window itself. So this whole AppWindow.TitleBar seems pretty broken unfortunately. I added that to the OP as well.

@Eilon Eilon added the legacy-area-desktop Windows / WinUI / Project Reunion & Mac Catalyst / macOS specifics (Menus & other Controls)) label Oct 25, 2023
@Eilon Eilon added t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK) and removed legacy-area-desktop Windows / WinUI / Project Reunion & Mac Catalyst / macOS specifics (Menus & other Controls)) labels May 10, 2024
@mattleibow mattleibow added this to the Backlog milestone May 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-window Window platform/windows 🪟 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK)
Projects
None yet
Development

No branches or pull requests

5 participants