diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index fbfdd418c5..b05ffcc32f 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -174,6 +174,7 @@ BTNFACE Bto buf bugreport +BUILDARCH BUILDNUMBER buildtask buildtransitive @@ -1055,6 +1056,7 @@ majortype MAJORVERSION makecab MAKEINTRESOURCE +MAKEINTRESOURCEA MAKEINTRESOURCEW makepri manifestdependency @@ -1182,10 +1184,12 @@ msrc msstore mst msvc +msvcp MTND Mul MULTIPLEUSE multizone +muxc mvvm mwb MWBEx @@ -1251,6 +1255,8 @@ NOCOPYBITS nodeca nodiscard nodoc +NODRAWCAPTION +NODRAWICON NOINHERITLAYOUT NOINTERFACE NOLINKINFO @@ -2094,6 +2100,7 @@ VCINSTALLDIR vcm Vcpkg VCRT +vcruntime vcvars VDesktop vdi @@ -2276,6 +2283,8 @@ wsl wss wstr wsz +WTA +WTNCA wtoi WTS wtsapi diff --git a/.pipelines/versionAndSignCheck.ps1 b/.pipelines/versionAndSignCheck.ps1 index 8cc31f7567..42b66ed8bc 100644 --- a/.pipelines/versionAndSignCheck.ps1 +++ b/.pipelines/versionAndSignCheck.ps1 @@ -25,7 +25,11 @@ $nullVersionExceptions = @( "codicon.ttf", "e_sqlite3.dll", "vcamp140_app.dll", + "vcruntime140_app.dll", + "vcruntime140_1_app.dll", + "msvcp140_app.dll", "marshal.dll", + "Microsoft.Toolkit.Win32.UI.XamlHost.dll", "Microsoft.UI.Composition.OSSupport.dll", "Microsoft.UI.Windowing.dll", "Microsoft.UI.Xaml.Internal.dll", diff --git a/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md b/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md index 1f55198b4b..a94c9f0b36 100644 --- a/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md +++ b/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md @@ -1,10 +1,7 @@ # Keyboard Manager UI ## Table of Contents: -1. [C++ XAML Islands](#c-xaml-islands) - 1. [Debugging exceptions in XAML Islands](#debugging-exceptions-in-xaml-islands) - 2. [Build times](#build-times) - 3. [Setting custom backgrounds for Xaml Controls using brushes](#setting-custom-backgrounds-for-xaml-controls-using-brushes) +1. [XAML Implementation](#xaml-implementation) 2. [UI Structure](#ui-structure) 3. [EditKeyboardWindow / EditShortcutsWindow](#editkeyboardwindow--editshortcutswindow) 1. [OK and Cancel button](#ok-and-cancel-button) @@ -17,28 +14,18 @@ 2. [Single Key ComboBox Selection Handler](#single-key-combobox-selection-handler) 3. [Shortcut ComboBox Selection Handler](#shortcut-combobox-selection-handler) -## C++ XAML Islands -The KBM UI is implemented as a C++ XAML Island, but all the controls are implemented in code behind rather than .xaml and .xaml.cs files. This was done as per a XAML Island Code sample and it didn't require a separate UWP project, which could be limited in terms of using hooks. There is a [tech debt item](https://github.com/microsoft/PowerToys/issues/2027) for moving this to XAML. The reason it wasn't implemented in the C# Settings was because it required communication with the low level hook thread, which could be too slow if IPC is used, since the UI needs to update on every key event. +## XAML Implementation +The KBM UI was originally implemented as a XAML Island, but in order to easily support Mica, which is [still an issue](https://github.com/microsoft/microsoft-ui-xaml/issues/5319), the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp) was rewritten to use a [`FrameworkView`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L47C11-L49) object which is how a traditional UWP app behaves: +1. A `CoreWindow` is created by [calling a function inside of `Windows.UI.dll` with an ordinal number of `1500`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L35-L42). +2. A [stubbed implementation of `CoreApplicationView`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L10-L18) was created. +3. Then [both objects are passed on to the `FrameworkView`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L47-L49) to initialize the XAML framework. +4. Lastly, the `CoreWindow` is [attached to the editor window](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L54-L61) and its `HWND` is used in-place of `DesktopWindowXamlSource`'s. -**Note:** For functions which take a XAML component as argument, pass it by value and not by reference. This is because `winrt` WinUI classes store their own internal references, so they are supposed to be passed by value (and internally ref counts are incremented). Passing by reference can lead to weird behavior where the object is `null`. +Mica is then achieved by calling [`BackdropMaterial::SetApplyToRootOrPageBackground()`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp#L388-L400) in both of the editor windows, or falls back to the `ApplicationPageBackgroundThemeBrush` background if Mica isn't available. -The windows are [created as C++ windows](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L128-L140) and the window sizes are set to default by [scaling them as per DPI](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L120-L126) using the `DPIAware::Convert` API from common lib. Since the UI is launched on a new thread, the window may not be in the foreground, so [we call `SetForegroundWindow`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L146-L150). +The UI was also updated to use WinUI 2.8 to match the look and feel of the Fluent design language of Windows 11 and the rest of PowerToys. There has been talk about [migrating the implementation to XAML files instead of code-behind](https://github.com/microsoft/PowerToys/issues/2027) and [utilizing WinUI 3 going forward](https://github.com/microsoft/PowerToys/issues/15870). More about the update can be read in [here](https://github.com/microsoft/PowerToys/pull/28473). -`DesktopWindowXamlSource` has to be declared and [it is initialized](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L159-L162) using the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/XamlBridge.cpp), and [a second window handle](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L161-L162) is generated for the internal Xaml Island window. Most of the code was based on the [Xaml Island Sample](https://github.com/microsoft/Xaml-Islands-Samples/blob/master/Samples/Win32/SampleCppApp/XamlBridge.cpp). The `XamlBridge` class contains code which handles initializing the Xaml Island containers as well as handling special messages like keyboard navigation, and focus between islands and between the C++ window and the island. It also has methods for clearing the xaml islands and closing the window. - -Once the UI controls are created, the parent container is set as the content for the `DesktopWindowXamlSource` and the `XamlBridge.MessageLoop` is executed. Messages are processed by the C++ window handler like [`EditKeyboardWindowProc`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L364-L404). The general structure we use for this is, for any `WM_PAINT` or `WM_SIZE` message we resize the Xaml Island window. For `WM_GETMINMAXINFO` we set minimum widths so that the window cannot be resized beyond a minimum height and width. This is done to prevent the WinUI elements from overlapping and getting cropped. If it is neither of these cases we send the message to the [`XamlBridge.MessageHandler`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/XamlBridge.cpp#L291-L301) which handles Destroy, Activation and Focus. If `WM_NCDESTROY` is received when the `XamlBridge` is `nullptr`, the window thread is terminated. - -**Note:** `ContentDialog` in Xaml Islands requires manually settings a `XamlRoot`. This can generally be done by passing the XamlRoot from a component in the main window, such as the button used to open the dialog ([`sender.as