[KeyboardManager]Modernize the editor UI (#28473)

* Fix dark title bar for shortcuts window

* Adjust editor sizes

* Fetch accent button style from resources instead

* Modernize the editor UI
Reimplemented the XAML bridge to support Mica

* Use fluent icons

* Modernize the preview key visuals

* Implement teaching tips for key drop-down messages

* Fix spelling

* Fix delete button alignment in keys editor

* Remove trace log from bridge message handler

* Add WinUI depends to installer script

* Hide icon and caption from editor title bar

* Update remap entries to look like cards

* Use built-in content dialog buttons

* Update add button

* Fix spelling

* Fix installer script for ARM64

* Fix spelling AGAIN

* Update dev documentation

* Prevent white flash on dark mode

* Revert 3-key layout but make window wider

* f: align webview versions

* f: add pipeline exceptions for Microsoft DLLs that are not versioned

* f: add vcruntime140_1_app.dll to the exception list

* f: update webview versions
This commit is contained in:
Dylan Briedis 2023-11-07 07:26:19 -07:00 committed by GitHub
parent 35b0f71317
commit 97a8aeb118
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 386 additions and 193 deletions

View File

@ -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

View File

@ -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",

View File

@ -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<Button>().XamlRoot()`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.cpp#L31-L32)). [These docs]((https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)) have more details about this.
### Debugging exceptions in XAML Islands
Sometimes if an exception occurs in XAML Islands, the stack trace may not always point to the correct code causing the exception and instead it will point to the Xaml Island message loop. In these cases the output window in VS will generally show the correct exception.
### Build times
C++ Xaml Islands generally take several minutes to build because the `pch` which contains the WinUI headers takes longer to build and compiles to a file of several GBs. To minimize the build times, multi-processor compilation within the projects have been enabled (files are distributed for compilation to the processors), and references to the Xaml headers have been removed from the .h headers files as much as possible. Since several classes of ours had class members with UI controls like `StackPanel` (which requires definitions of the classes in order to compile), we worked around this by declaring them as `IInspectable` (the equivalent of an object pointer in winrt), and initializing them to the actual control like `StackPanel` in the constructor and accessing all their member functions by inline typecasting (for `IInspectable x;` we do `x = StackPanel();` and `x.as<StackPanel>().MemberFunction()`). Check [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.cpp#L19-L25) for this type of usage in `ShortcutControl`.
### Setting custom backgrounds for Xaml Controls using brushes
To access the brushes available on C# Xaml, it has to be done with the `Resources.Lookup` syntax:
`primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());`
[**Link to the original documentation**](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md#c-xaml-islands)
## UI Structure
The KBM UI consists of a [`Grid` with several columns](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L200-L218). Rows are added dynamically when [the add button is pressed](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L305-L309). [A vector of vector of unique pointers to `SingleKeyRemapControl`/`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L248-L249) is created so that references to the UI components and their data are not lost until the window is closed. [`SingleKeyRemapControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp) is the UI class for each row of the Remap keys table, and [`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/ShortcutControl.cpp) is the UI class for each row of the Remap shortcuts table. [`KeyDropDownControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp) is used for handling the ComboBox operations. Each of these two classes [have vectors of unique pointers to the `KeyDropDownControl` objects](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L44-L45) so that references to the objects are active until the control is deleted.

View File

@ -17,6 +17,14 @@
<RegistryValue Type="string" Name="Module_KeyboardManager_Editor" Value="" KeyPath="yes"/>
</RegistryKey>
<File Source="$(var.BinDir)KeyboardManagerEditor\PowerToys.KeyboardManagerEditor.exe" />
<File Source="$(var.BinDir)KeyboardManagerEditor\Microsoft.Toolkit.Win32.UI.XamlHost.dll" />
<File Source="$(var.BinDir)KeyboardManagerEditor\Microsoft.UI.Xaml.dll" />
<File Source="$(var.BinDir)KeyboardManagerEditor\msvcp140_app.dll" />
<File Source="$(var.BinDir)KeyboardManagerEditor\resources.pri" />
<File Source="$(var.BinDir)KeyboardManagerEditor\vcruntime140_app.dll" />
<?if $(sys.BUILDARCH) = x64 ?>
<File Source="$(var.BinDir)KeyboardManagerEditor\vcruntime140_1_app.dll" />
<?endif ?>
</Component>
</DirectoryRef>

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Project configurations -->
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup>
<NoWarn>81010002</NoWarn>
@ -98,7 +100,7 @@
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
@ -109,7 +111,7 @@
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
@ -160,6 +162,10 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" />
</ImportGroup>
<Import Project="..\..\..\..\deps\spdlog.props" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
@ -171,5 +177,15 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Target Name="FakeResourcesPriMerge" BeforeTargets="FinalizeBuildStatus" DependsOnTargets="CopyFilesToOutputDirectory">
<Message Text="Renaming Microsoft.UI.Xaml.pri to resources.pri" />
<Move SourceFiles="$(OutDir)\Microsoft.UI.Xaml.pri" DestinationFiles="$(OutDir)\resources.pri" />
</Target>
</Project>

View File

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.2-prerelease.220830001" targetFramework="native" />
<package id="Microsoft.VCRTForwarders.140" version="1.0.7" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.2088.41" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" />
</packages>

View File

@ -15,7 +15,7 @@
#include "EditKeyboardWindow.h"
#include "SingleKeyRemapControl.h"
#include "KeyDropDownControl.h"
#include "XamlBridge.h"
#include "XamlBridge2.h"
#include "Styles.h"
#include "Dialog.h"
#include "LoadingAndSavingRemappingHelper.h"
@ -41,12 +41,12 @@ HWND hwndEditKeyboardNativeWindow = nullptr;
std::mutex editKeyboardWindowMutex;
// Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure
static XamlBridge* xamlBridgePtr = nullptr;
static XamlBridge2* xamlBridgePtr = nullptr;
// Theming
ThemeListener theme_listener{};
static ThemeListener theme_listener{};
void handleTheme()
static void handleTheme()
{
auto theme = theme_listener.AppTheme;
auto isDark = theme == AppTheme::Dark;
@ -137,7 +137,7 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
windowClass.lpfnWndProc = EditKeyboardWindowProc;
windowClass.hInstance = hInst;
windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == AppTheme::Dark) ? 0x00000000 : 0x00FFFFFF);
windowClass.hIcon = static_cast<HICON>(LoadImageW(
windowClass.hInstance,
MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON),
@ -196,17 +196,19 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
hwndEditKeyboardNativeWindow = _hWndEditKeyboardWindow;
hwndLock.unlock();
// Hide icon and caption from title bar
const DWORD windowThemeOptionsMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
WTA_OPTIONS windowThemeOptions{ windowThemeOptionsMask, windowThemeOptionsMask };
SetWindowThemeAttribute(_hWndEditKeyboardWindow, WTA_NONCLIENT, &windowThemeOptions, sizeof(windowThemeOptions));
handleTheme();
theme_listener.AddChangedHandler(handleTheme);
// Create the xaml bridge object
XamlBridge xamlBridge(_hWndEditKeyboardWindow);
// DesktopSource needs to be declared before the RelativePanel xamlContainer object to avoid errors
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource desktopSource;
XamlBridge2 xamlBridge(_hWndEditKeyboardWindow);
// Create the desktop window xaml source object and set its content
hWndXamlIslandEditKeyboardWindow = xamlBridge.InitDesktopWindowsXamlSource(desktopSource);
hWndXamlIslandEditKeyboardWindow = xamlBridge.InitBridge();
// Set the pointer to the xaml bridge object
xamlBridgePtr = &xamlBridge;
@ -322,11 +324,8 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
// Add remap key button
Windows::UI::Xaml::Controls::Button addRemapKey;
FontIcon plusSymbol;
plusSymbol.FontFamily(Media::FontFamily(L"Segoe MDL2 Assets"));
plusSymbol.Glyph(L"\xE710");
addRemapKey.Content(plusSymbol);
addRemapKey.Margin({ 10, 10, 0, 25 });
addRemapKey.Style(AccentButtonStyle());
addRemapKey.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects);
@ -337,14 +336,19 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
UIHelpers::SetFocusOnTypeButtonInLastRow(keyRemapTable, EditorConstants::RemapTableColCount);
});
// Remap key button content
StackPanel addRemapKeyContent;
addRemapKeyContent.Orientation(Orientation::Horizontal);
addRemapKeyContent.Spacing(10);
addRemapKeyContent.Children().Append(SymbolIcon(Symbol::Add));
TextBlock addRemapKeyText;
addRemapKeyText.Text(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON));
addRemapKeyContent.Children().Append(addRemapKeyText);
addRemapKey.Content(addRemapKeyContent);
// Set accessible name for the addRemapKey button
addRemapKey.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON)));
// Add tooltip for add button which would appear on hover
ToolTip addRemapKeytoolTip;
addRemapKeytoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON)));
ToolTipService::SetToolTip(addRemapKey, addRemapKeytoolTip);
// Header and example text at the top of the window
StackPanel helperText;
helperText.Children().Append(keyRemapInfoHeader);
@ -381,7 +385,20 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
{
}
desktopSource.Content(xamlContainer);
UserControl xamlContent;
xamlContent.Content(xamlContainer);
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent(L"Windows.UI.Composition.ICompositionSupportsSystemBackdrop"))
{
// Apply Mica
muxc::BackdropMaterial::SetApplyToRootOrPageBackground(xamlContent, true);
}
else
{
// Mica isn't available
xamlContainer.Background(Application::Current().Resources().Lookup(box_value(L"ApplicationPageBackgroundThemeBrush")).as<Media::SolidColorBrush>());
}
Window::Current().Content(xamlContent);
////End XAML Island section
if (_hWndEditKeyboardWindow)
{
@ -400,9 +417,6 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
hwndEditKeyboardNativeWindow = nullptr;
keyboardManagerState.ResetUIState();
keyboardManagerState.ClearRegisteredKeyDelays();
// Cannot be done in WM_DESTROY because that causes crashes due to fatal app exit
xamlBridge.ClearXamlIslands();
}
void CreateEditKeyboardWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)

View File

@ -13,9 +13,10 @@
#include "ShortcutControl.h"
#include "Styles.h"
#include "UIHelpers.h"
#include "XamlBridge.h"
#include "XamlBridge2.h"
#include "ShortcutErrorType.h"
#include "EditorConstants.h"
#include <common/Themes/theme_listener.h>
using namespace winrt::Windows::Foundation;
@ -34,7 +35,21 @@ HWND hwndEditShortcutsNativeWindow = nullptr;
std::mutex editShortcutsWindowMutex;
// Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure
static XamlBridge* xamlBridgePtr = nullptr;
static XamlBridge2* xamlBridgePtr = nullptr;
// Theming
static ThemeListener theme_listener{};
static void handleTheme()
{
auto theme = theme_listener.AppTheme;
auto isDark = theme == AppTheme::Dark;
Logger::info(L"Theme is now {}", isDark ? L"Dark" : L"Light");
if (hwndEditShortcutsNativeWindow != nullptr)
{
ThemeHelpers::SetImmersiveDarkMode(hwndEditShortcutsNativeWindow, isDark);
}
}
static IAsyncAction OnClickAccept(
KBMEditor::KeyboardManagerState& keyboardManagerState,
@ -75,7 +90,7 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
windowClass.lpfnWndProc = EditShortcutsWindowProc;
windowClass.hInstance = hInst;
windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == AppTheme::Dark) ? 0x00000000 : 0x00FFFFFF);
windowClass.hIcon = static_cast<HICON>(LoadImageW(
windowClass.hInstance,
MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON),
@ -132,14 +147,19 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
hwndEditShortcutsNativeWindow = _hWndEditShortcutsWindow;
hwndLock.unlock();
// Hide icon and caption from title bar
const DWORD windowThemeOptionsMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
WTA_OPTIONS windowThemeOptions{ windowThemeOptionsMask, windowThemeOptionsMask };
SetWindowThemeAttribute(_hWndEditShortcutsWindow, WTA_NONCLIENT, &windowThemeOptions, sizeof(windowThemeOptions));
handleTheme();
theme_listener.AddChangedHandler(handleTheme);
// Create the xaml bridge object
XamlBridge xamlBridge(_hWndEditShortcutsWindow);
// DesktopSource needs to be declared before the RelativePanel xamlContainer object to avoid errors
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource desktopSource;
XamlBridge2 xamlBridge(_hWndEditShortcutsWindow);
// Create the desktop window xaml source object and set its content
hWndXamlIslandEditShortcutsWindow = xamlBridge.InitDesktopWindowsXamlSource(desktopSource);
hWndXamlIslandEditShortcutsWindow = xamlBridge.InitBridge();
// Set the pointer to the xaml bridge object
xamlBridgePtr = &xamlBridge;
@ -276,11 +296,8 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
// Add shortcut button
Windows::UI::Xaml::Controls::Button addShortcut;
FontIcon plusSymbol;
plusSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
plusSymbol.Glyph(L"\xE710");
addShortcut.Content(plusSymbol);
addShortcut.Margin({ 10, 10, 0, 25 });
addShortcut.Style(AccentButtonStyle());
addShortcut.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ShortcutControl::AddNewShortcutControlRow(shortcutTable, keyboardRemapControlObjects);
@ -291,14 +308,19 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
UIHelpers::SetFocusOnTypeButtonInLastRow(shortcutTable, EditorConstants::ShortcutTableColCount);
});
// Remap shortcut button content
StackPanel addShortcutContent;
addShortcutContent.Orientation(Orientation::Horizontal);
addShortcutContent.Spacing(10);
addShortcutContent.Children().Append(SymbolIcon(Symbol::Add));
TextBlock addShortcutText;
addShortcutText.Text(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON));
addShortcutContent.Children().Append(addShortcutText);
addShortcut.Content(addShortcutContent);
// Set accessible name for the add shortcut button
addShortcut.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON)));
// Add tooltip for add button which would appear on hover
ToolTip addShortcuttoolTip;
addShortcuttoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON)));
ToolTipService::SetToolTip(addShortcut, addShortcuttoolTip);
// Header and example text at the top of the window
StackPanel helperText;
helperText.Children().Append(shortcutRemapInfoHeader);
@ -334,7 +356,19 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
{
}
desktopSource.Content(xamlContainer);
UserControl xamlContent;
xamlContent.Content(xamlContainer);
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent(L"Windows.UI.Composition.ICompositionSupportsSystemBackdrop"))
{
// Apply Mica
muxc::BackdropMaterial::SetApplyToRootOrPageBackground(xamlContent, true);
}
else
{
// Mica isn't available
xamlContainer.Background(Application::Current().Resources().Lookup(box_value(L"ApplicationPageBackgroundThemeBrush")).as<Media::SolidColorBrush>());
}
Window::Current().Content(xamlContent);
////End XAML Island section
if (_hWndEditShortcutsWindow)
@ -353,9 +387,6 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
hwndEditShortcutsNativeWindow = nullptr;
keyboardManagerState.ResetUIState();
keyboardManagerState.ClearRegisteredKeyDelays();
// Cannot be done in WM_DESTROY because that causes crashes due to fatal app exit
xamlBridge.ClearXamlIslands();
}
void CreateEditShortcutsWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)

View File

@ -3,12 +3,12 @@
namespace EditorConstants
{
// Default window sizes
inline const int DefaultEditKeyboardWindowWidth = 800;
inline const int DefaultEditKeyboardWindowWidth = 960;
inline const int DefaultEditKeyboardWindowHeight = 600;
inline const int MinimumEditKeyboardWindowWidth = 500;
inline const int MinimumEditKeyboardWindowHeight = 450;
inline const int EditKeyboardTableMinWidth = 700;
inline const int DefaultEditShortcutsWindowWidth = 1050;
inline const int DefaultEditShortcutsWindowWidth = 1410;
inline const int DefaultEditShortcutsWindowHeight = 600;
inline const int MinimumEditShortcutsWindowWidth = 500;
inline const int MinimumEditShortcutsWindowHeight = 500;
@ -21,7 +21,9 @@ namespace EditorConstants
inline const long RemapTableArrowColIndex = 1;
inline const long RemapTableNewColIndex = 2;
inline const long RemapTableRemoveColIndex = 3;
inline const DWORD64 RemapTableDropDownWidth = 110;
inline const DWORD64 RemapTableDropDownWidth = 160;
inline const DWORD64 RemapTableDropDownSpacing = 10;
inline const long RemapTargetColumnWidth = 3 * RemapTableDropDownWidth + 3 * RemapTableDropDownSpacing + 65;
// Shortcut table constants
inline const long ShortcutTableColCount = 5;
@ -32,14 +34,14 @@ namespace EditorConstants
inline const long ShortcutTableTargetAppColIndex = 3;
inline const long ShortcutTableRemoveColIndex = 4;
inline const long ShortcutArrowColumnWidth = 90;
inline const DWORD64 ShortcutTableDropDownWidth = 110;
inline const DWORD64 ShortcutTableDropDownWidth = 160;
inline const DWORD64 ShortcutTableDropDownSpacing = 10;
inline const long ShortcutOriginColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing;
inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing + 15;
// Drop down height used for both Edit Keyboard and Edit Shortcuts
inline const DWORD64 TableDropDownHeight = 200;
inline const DWORD64 TableArrowColWidth = 230;
inline const DWORD64 TableArrowColWidth = 130;
inline const DWORD64 TableRemoveColWidth = 20;
inline const DWORD64 TableWarningColWidth = 20;
inline const DWORD64 TableTargetAppColWidth = ShortcutTableDropDownWidth + TableRemoveColWidth * 2;

View File

@ -51,8 +51,10 @@ std::vector<std::pair<DWORD, std::wstring>> KeyDropDownControl::GetKeyList(bool
void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisable)
{
dropDown = ComboBox();
#ifndef USE_NEW_DROPDOWN_WARNING_TIP
warningFlyout = Flyout();
warningMessage = TextBlock();
#endif
if (!isShortcut)
{
@ -77,6 +79,19 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
CheckAndUpdateKeyboardLayout(currentDropDown, isShortcut, renderDisable);
});
#ifdef USE_NEW_DROPDOWN_WARNING_TIP
// Attach the tip to the drop down
warningTip.Target(dropDown.as<ComboBox>());
dropDown.as<ComboBox>().Loaded([&](winrt::Windows::Foundation::IInspectable const& sender, auto args) {
Media::VisualTreeHelper::GetChild(dropDown.as<ComboBox>(), 0).as<Grid>().Children().Append(warningTip);
});
// Tip properties
muxc::SymbolIconSource warningIcon;
warningIcon.Symbol(Symbol::Important);
warningTip.IconSource(warningIcon);
warningTip.IsLightDismissEnabled(true);
#else
// Attach flyout to the drop down
warningFlyout.as<Flyout>().Content(warningMessage.as<TextBlock>());
@ -86,6 +101,7 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
style.Setters().Append(Setter(Windows::UI::Xaml::Controls::Control::TabNavigationProperty(), winrt::box_value(Windows::UI::Xaml::Input::KeyboardNavigationMode::Cycle)));
warningFlyout.as<Flyout>().FlyoutPresenterStyle(style);
dropDown.as<ComboBox>().ContextFlyout().SetAttachedFlyout((FrameworkElement)dropDown.as<ComboBox>(), warningFlyout.as<Flyout>());
#endif
// To set the accessible name of the combo-box (by default index 1)
SetAccessibleNameForComboBox(dropDown.as<ComboBox>(), 1);
@ -376,6 +392,11 @@ void KeyDropDownControl::ValidateShortcutFromDropDownList(StackPanel table, Stac
void KeyDropDownControl::SetDropDownError(ComboBox currentDropDown, hstring message)
{
currentDropDown.SelectedIndex(-1);
#ifdef USE_NEW_DROPDOWN_WARNING_TIP
warningTip.Title(message);
warningTip.IsOpen(true);
#else
warningMessage.as<TextBlock>().Text(message);
try
{
@ -386,6 +407,7 @@ void KeyDropDownControl::SetDropDownError(ComboBox currentDropDown, hstring mess
// If it's loading and some remaps are invalid from previous configs, avoid crashing when flyouts can't be showed yet.
Logger::error(L"Failed to show dropdown error flyout: {}", message);
}
#endif
}
// Function to add a shortcut to the UI control as combo boxes

View File

@ -2,6 +2,9 @@
#include <keyboardmanager/common/Shortcut.h>
// Enables the WinUI teaching tip to show as the new warning flyout
#define USE_NEW_DROPDOWN_WARNING_TIP
namespace KBMEditor
{
class KeyboardManagerState;
@ -38,11 +41,16 @@ private:
// Stores the previous layout
HKL previousLayout = 0;
#ifdef USE_NEW_DROPDOWN_WARNING_TIP
// Stores the teaching tip attached to the current drop down
muxc::TeachingTip warningTip;
#else
// Stores the flyout warning message
winrt::Windows::Foundation::IInspectable warningMessage;
// Stores the flyout attached to the current drop down
winrt::Windows::Foundation::IInspectable warningFlyout;
#endif
// Stores whether a key to shortcut warning has to be ignored
bool ignoreKeyToShortcutWarning;

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
@ -53,6 +55,7 @@
<ClInclude Include="trace.h" />
<ClInclude Include="UIHelpers.h" />
<ClInclude Include="XamlBridge.h" />
<ClInclude Include="XamlBridge2.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BufferValidationHelpers.cpp" />
@ -74,6 +77,7 @@
<ClCompile Include="trace.cpp" />
<ClCompile Include="UIHelpers.cpp" />
<ClCompile Include="XamlBridge.cpp" />
<ClCompile Include="XamlBridge2.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@ -95,6 +99,9 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" />
</ImportGroup>
<Import Project="..\..\..\..\deps\spdlog.props" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
@ -103,6 +110,11 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory)\..\KeyboardManagerEditor\ resource.base.h resource.h KeyboardManagerEditor.base.rc KeyboardManagerEditor.rc" />

View File

@ -75,6 +75,9 @@
<ClInclude Include="EditorConstants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="XamlBridge2.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -128,6 +131,9 @@
<ClCompile Include="KeyDelay.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XamlBridge2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -118,8 +118,15 @@ void KeyboardManagerState::AddKeyToLayout(const StackPanel& panel, const hstring
border.Padding({ 20, 10, 20, 10 });
border.Margin({ 0, 0, 10, 0 });
// Use the base low brush to be consistent with the theme
border.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());
// Based on settings-ui\Settings.UI\SettingsXAML\Controls\KeyVisual\KeyVisual.xaml
border.Background(Application::Current().Resources().Lookup(box_value(L"ButtonBackground")).as<Media::Brush>());
border.BorderBrush(Application::Current().Resources().Lookup(box_value(L"ButtonBorderBrush")).as<Media::Brush>());
border.BorderThickness(unbox_value<Thickness>(Application::Current().Resources().Lookup(box_value(L"ButtonBorderThemeThickness"))));
border.CornerRadius(unbox_value<CornerRadius>(Application::Current().Resources().Lookup(box_value(L"ControlCornerRadius"))));
remapKey.Foreground(Application::Current().Resources().Lookup(box_value(L"ButtonForeground")).as<Media::Brush>());
remapKey.FontWeight(Text::FontWeights::SemiBold());
remapKey.FontSize(20);
border.HorizontalAlignment(HorizontalAlignment::Left);
border.Child(remapKey);

View File

@ -90,13 +90,12 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
newrow.emplace_back(std::make_unique<ShortcutControl>(parent, row, 1, targetAppTextBox));
keyboardRemapControlObjects.push_back(std::move(newrow));
row.Padding({ 10, 10, 10, 10 });
row.Padding({ 10, 15, 10, 5 });
row.Margin({ 0, 0, 0, 2 });
row.Orientation(Orientation::Horizontal);
auto brush = Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundListLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>();
if (keyboardRemapControlObjects.size() % 2)
{
row.Background(brush);
}
row.Background(Application::Current().Resources().Lookup(box_value(L"CardBackgroundFillColorDefaultBrush")).as<Media::Brush>());
row.BorderBrush(Application::Current().Resources().Lookup(box_value(L"CardStrokeColorDefaultBrush")).as<Media::Brush>());
row.BorderThickness({ 0, 1, 0, 1 });
// ShortcutControl for the original shortcut
auto origin = keyboardRemapControlObjects.back()[0]->GetShortcutControl();
@ -104,14 +103,13 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
row.Children().Append(origin);
// Arrow icon
FontIcon arrowIcon;
arrowIcon.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
arrowIcon.Glyph(L"\xE72A");
SymbolIcon arrowIcon(Symbol::Forward);
arrowIcon.VerticalAlignment(VerticalAlignment::Center);
arrowIcon.HorizontalAlignment(HorizontalAlignment::Center);
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::ShortcutArrowColumnWidth).as<StackPanel>();
arrowIconContainer.Orientation(Orientation::Vertical);
arrowIconContainer.VerticalAlignment(VerticalAlignment::Center);
arrowIconContainer.Margin({ 0, 0, 0, 10 });
row.Children().Append(arrowIconContainer);
// ShortcutControl for the new shortcut
@ -122,6 +120,7 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
targetAppTextBox.Width(EditorConstants::ShortcutTableDropDownWidth);
targetAppTextBox.PlaceholderText(KeyboardManagerEditorStrings::DefaultAppName());
targetAppTextBox.Text(targetAppName);
targetAppTextBox.Margin({ 0, 0, 0, 10 });
// GotFocus handler will be called whenever the user tabs into or clicks on the textbox
targetAppTextBox.GotFocus([targetAppTextBox](auto const& sender, auto const& e) {
@ -194,13 +193,11 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
// Delete row button
Windows::UI::Xaml::Controls::Button deleteShortcut;
FontIcon deleteSymbol;
deleteSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
deleteSymbol.Glyph(L"\xE74D");
deleteShortcut.Content(deleteSymbol);
deleteShortcut.Content(SymbolIcon(Symbol::Delete));
deleteShortcut.Background(Media::SolidColorBrush(Colors::Transparent()));
deleteShortcut.HorizontalAlignment(HorizontalAlignment::Center);
deleteShortcut.Click([&, parent, row, brush, deleteShortcut](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
deleteShortcut.Margin({ 0, 0, 0, 10 });
deleteShortcut.Click([&, parent, row, deleteShortcut](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
Button currentButton = sender.as<Button>();
uint32_t rowIndex;
// Get index of delete button
@ -216,7 +213,6 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
for (uint32_t i = rowIndex + 1; i < children.Size(); i++)
{
StackPanel row = children.GetAt(i).as<StackPanel>();
row.Background(i % 2 ? brush : Media::SolidColorBrush(Colors::Transparent()));
StackPanel sourceCol = row.Children().GetAt(0).as<StackPanel>();
StackPanel targetCol = row.Children().GetAt(2).as<StackPanel>();
TextBox targetApp = row.Children().GetAt(3).as<StackPanel>().Children().GetAt(0).as<StackPanel>().Children().GetAt(0).as<TextBox>();
@ -294,8 +290,6 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
// ContentDialog requires manually setting the XamlRoot (https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)
detectShortcutBox.XamlRoot(xamlRoot);
detectShortcutBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPESHORTCUT_TITLE)));
detectShortcutBox.IsPrimaryButtonEnabled(false);
detectShortcutBox.IsSecondaryButtonEnabled(false);
// Get the linked stack panel for the "Type shortcut" button that was clicked
VariableSizedWrapGrid linkedShortcutVariableSizedWrapGrid = UIHelpers::GetSiblingElement(sender).as<VariableSizedWrapGrid>();
@ -359,16 +353,13 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
onReleaseEnter();
};
TextBlock primaryButtonText;
primaryButtonText.Text(GET_RESOURCE_STRING(IDS_OK_BUTTON));
Button primaryButton;
primaryButton.HorizontalAlignment(HorizontalAlignment::Stretch);
primaryButton.Margin({ 2, 2, 2, 2 });
primaryButton.Content(primaryButtonText);
// OK button
primaryButton.Click([onAccept](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
detectShortcutBox.DefaultButton(ContentDialogButton::Primary);
detectShortcutBox.PrimaryButtonText(GET_RESOURCE_STRING(IDS_OK_BUTTON));
detectShortcutBox.PrimaryButtonClick([onAccept](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
onAccept();
});
@ -376,12 +367,10 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
keyboardManagerState.RegisterKeyDelay(
VK_RETURN,
selectDetectedShortcutAndResetKeys,
[primaryButton, onPressEnter, detectShortcutBox](DWORD) {
[onPressEnter, detectShortcutBox](DWORD) {
detectShortcutBox.Dispatcher().RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
[primaryButton, onPressEnter] {
// Use the base medium low brush to be consistent with the theme
primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());
[onPressEnter] {
onPressEnter();
});
},
@ -393,9 +382,6 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
});
});
TextBlock cancelButtonText;
cancelButtonText.Text(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
auto onCancel = [&keyboardManagerState,
detectShortcutBox,
unregisterKeys,
@ -418,12 +404,12 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
unregisterKeys();
};
Button cancelButton;
cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch);
cancelButton.Margin({ 2, 2, 2, 2 });
cancelButton.Content(cancelButtonText);
// Cancel button
cancelButton.Click([onCancel](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
detectShortcutBox.CloseButtonText(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
detectShortcutBox.CloseButtonClick([onCancel](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
onCancel();
});
@ -474,21 +460,6 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
holdEnterInfo.Margin({ 0, 0, 0, 0 });
stackPanel.Children().Append(holdEnterInfo);
ColumnDefinition primaryButtonColumn;
ColumnDefinition cancelButtonColumn;
Grid buttonPanel;
buttonPanel.Margin({ 0, 20, 0, 0 });
buttonPanel.HorizontalAlignment(HorizontalAlignment::Stretch);
buttonPanel.ColumnDefinitions().Append(primaryButtonColumn);
buttonPanel.ColumnDefinitions().Append(cancelButtonColumn);
buttonPanel.SetColumn(primaryButton, 0);
buttonPanel.SetColumn(cancelButton, 1);
buttonPanel.Children().Append(primaryButton);
buttonPanel.Children().Append(cancelButton);
stackPanel.Children().Append(buttonPanel);
try
{
// If a layout update has been triggered by other methods (e.g.: adapting to zoom level), this may throw an exception.

View File

@ -84,33 +84,31 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
newrow.emplace_back(std::make_unique<SingleKeyRemapControl>(parent, row, 1));
keyboardRemapControlObjects.push_back(std::move(newrow));
row.Padding({ 10, 10, 10, 10 });
row.Padding({ 10, 15, 10, 5 });
row.Margin({ 0, 0, 0, 2 });
row.Orientation(Orientation::Horizontal);
auto brush = Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundListLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>();
if (keyboardRemapControlObjects.size() % 2)
{
row.Background(brush);
}
row.Background(Application::Current().Resources().Lookup(box_value(L"CardBackgroundFillColorDefaultBrush")).as<Media::Brush>());
row.BorderBrush(Application::Current().Resources().Lookup(box_value(L"CardStrokeColorDefaultBrush")).as<Media::Brush>());
row.BorderThickness({ 0, 1, 0, 1 });
// SingleKeyRemapControl for the original key.
auto originalElement = keyboardRemapControlObjects.back()[0]->getSingleKeyRemapControl();
originalElement.Width(EditorConstants::RemapTableDropDownWidth + EditorConstants::ShortcutTableDropDownSpacing);
originalElement.Width(EditorConstants::RemapTableDropDownWidth + EditorConstants::RemapTableDropDownSpacing);
row.Children().Append(originalElement);
// Arrow icon
FontIcon arrowIcon;
arrowIcon.FontFamily(Media::FontFamily(L"Segoe MDL2 Assets"));
arrowIcon.Glyph(L"\xE72A");
SymbolIcon arrowIcon(Symbol::Forward);
arrowIcon.VerticalAlignment(VerticalAlignment::Center);
arrowIcon.HorizontalAlignment(HorizontalAlignment::Center);
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::TableArrowColWidth).as<StackPanel>();
arrowIconContainer.Orientation(Orientation::Vertical);
arrowIconContainer.VerticalAlignment(VerticalAlignment::Center);
arrowIconContainer.Margin({ 0, 0, 0, 10 });
row.Children().Append(arrowIconContainer);
// SingleKeyRemapControl for the new remap key
auto targetElement = keyboardRemapControlObjects.back()[1]->getSingleKeyRemapControl();
targetElement.Width(EditorConstants::ShortcutTargetColumnWidth);
targetElement.Width(EditorConstants::RemapTargetColumnWidth);
row.Children().Append(targetElement);
// Set the key text if the two keys are not null (i.e. default args)
@ -135,13 +133,11 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
// Delete row button
Windows::UI::Xaml::Controls::Button deleteRemapKeys;
FontIcon deleteSymbol;
deleteSymbol.FontFamily(Media::FontFamily(L"Segoe MDL2 Assets"));
deleteSymbol.Glyph(L"\xE74D");
deleteRemapKeys.Content(deleteSymbol);
deleteRemapKeys.Content(SymbolIcon(Symbol::Delete));
deleteRemapKeys.Background(Media::SolidColorBrush(Colors::Transparent()));
deleteRemapKeys.HorizontalAlignment(HorizontalAlignment::Center);
deleteRemapKeys.Click([&, parent, row, brush, deleteRemapKeys](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
deleteRemapKeys.Margin({ 0, 0, 0, 10 });
deleteRemapKeys.Click([&, parent, row, deleteRemapKeys](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
uint32_t rowIndex;
// Get index of delete button
UIElementCollection children = parent.Children();
@ -157,7 +153,6 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
for (uint32_t i = rowIndex + 1; i < children.Size(); i++)
{
StackPanel row = children.GetAt(i).as<StackPanel>();
row.Background(i % 2 ? brush : Media::SolidColorBrush(Colors::Transparent()));
StackPanel sourceCol = row.Children().GetAt(0).as<StackPanel>();
StackPanel targetCol = row.Children().GetAt(2).as<StackPanel>();
Button delButton = row.Children().GetAt(3).as<Button>();
@ -224,8 +219,6 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
// ContentDialog requires manually setting the XamlRoot (https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)
detectRemapKeyBox.XamlRoot(xamlRoot);
detectRemapKeyBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPEKEY_TITLE)));
detectRemapKeyBox.IsPrimaryButtonEnabled(false);
detectRemapKeyBox.IsSecondaryButtonEnabled(false);
// Get the linked text block for the "Type Key" button that was clicked
ComboBox linkedRemapDropDown = UIHelpers::GetSiblingElement(sender).as<ComboBox>();
@ -269,14 +262,13 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
onReleaseEnter();
};
TextBlock primaryButtonText;
primaryButtonText.Text(GET_RESOURCE_STRING(IDS_OK_BUTTON));
// OK button
detectRemapKeyBox.DefaultButton(ContentDialogButton::Primary);
detectRemapKeyBox.PrimaryButtonText(GET_RESOURCE_STRING(IDS_OK_BUTTON));
detectRemapKeyBox.PrimaryButtonClick([onAccept](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
Button primaryButton;
primaryButton.HorizontalAlignment(HorizontalAlignment::Stretch);
primaryButton.Margin({ 2, 2, 2, 2 });
primaryButton.Content(primaryButtonText);
primaryButton.Click([onAccept](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
onAccept();
});
@ -284,12 +276,10 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
keyboardManagerState.RegisterKeyDelay(
VK_RETURN,
std::bind(&KBMEditor::KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
[primaryButton, onPressEnter, detectRemapKeyBox](DWORD) {
[onPressEnter, detectRemapKeyBox](DWORD) {
detectRemapKeyBox.Dispatcher().RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
[primaryButton, onPressEnter] {
// Use the base medium low brush to be consistent with the theme
primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());
[onPressEnter] {
onPressEnter();
});
},
@ -301,9 +291,6 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
});
});
TextBlock cancelButtonText;
cancelButtonText.Text(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
auto onCancel = [&keyboardManagerState,
detectRemapKeyBox,
unregisterKeys] {
@ -317,13 +304,12 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
unregisterKeys();
};
Button cancelButton;
cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch);
cancelButton.Margin({ 2, 2, 2, 2 });
cancelButton.Content(cancelButtonText);
// Cancel button
cancelButton.Click([onCancel](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
detectRemapKeyBox.CloseButtonText(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
detectRemapKeyBox.CloseButtonClick([onCancel](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
onCancel();
});
@ -367,21 +353,6 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
holdEnterInfo.Margin({ 0, 0, 0, 0 });
stackPanel.Children().Append(holdEnterInfo);
ColumnDefinition primaryButtonColumn;
ColumnDefinition cancelButtonColumn;
Grid buttonPanel;
buttonPanel.Margin({ 0, 20, 0, 0 });
buttonPanel.HorizontalAlignment(HorizontalAlignment::Stretch);
buttonPanel.ColumnDefinitions().Append(primaryButtonColumn);
buttonPanel.ColumnDefinitions().Append(cancelButtonColumn);
buttonPanel.SetColumn(primaryButton, 0);
buttonPanel.SetColumn(cancelButton, 1);
buttonPanel.Children().Append(primaryButton);
buttonPanel.Children().Append(cancelButton);
stackPanel.Children().Append(buttonPanel);
try
{
// If a layout update has been triggered by other methods (e.g.: adapting to zoom level), this may throw an exception.

View File

@ -1,15 +1,7 @@
#include "pch.h"
#include "Styles.h"
#include <common/themes/windows_colors.h>
Style AccentButtonStyle()
{
Style style{ winrt::xaml_typename<Controls::Button>() };
style.Setters().Append(Setter{
Controls::Control::BackgroundProperty(),
winrt::Windows::UI::Xaml::Media::SolidColorBrush{ WindowsColors::get_accent_color() } });
style.Setters().Append(Setter{
Controls::Control::ForegroundProperty(),
winrt::Windows::UI::Xaml::Media::SolidColorBrush{ winrt::Windows::UI::Colors::White() } });
return style;
return Application::Current().Resources().Lookup(box_value(L"AccentButtonStyle")).as<Style>();
}

View File

@ -0,0 +1,76 @@
#include "pch.h"
#include "XamlBridge2.h"
#include <CoreWindow.h> // ICoreWindowInterop
#include <winrt/Microsoft.Toolkit.Win32.UI.XamlHost.h>
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
namespace wac = Windows::ApplicationModel::Core;
// Stubbed implementation for frameworkView.Initialize()
struct XamlBridgeCoreAppViewImpl : implements<XamlBridgeCoreAppViewImpl, wac::ICoreApplicationView>
{
auto CoreWindow() { return Core::CoreWindow::GetForCurrentThread(); }
auto Activated(Windows::Foundation::TypedEventHandler<wac::CoreApplicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs> const&) { return event_token(); }
auto Activated(event_token const&) {}
auto IsMain() { return true; }
auto IsHosted() { return false; }
};
// Function to run the message loop for the xaml window
void XamlBridge2::MessageLoop()
{
Logger::trace("XamlBridge2::MessageLoop()");
frameworkView.Run();
Logger::trace("XamlBridge2::MessageLoop() stopped");
}
// Function to initialize the xaml bridge
HWND XamlBridge2::InitBridge()
{
Logger::trace("XamlBridge2::InitBridge()");
HRESULT hr = S_OK;
winrt::init_apartment(apartment_type::single_threaded);
auto windowsUIHandle = LoadLibrary(TEXT("Windows.UI.dll"));
auto pfnPrivateCreateCoreWindow = reinterpret_cast<fnPrivateCreateCoreWindow>(GetProcAddress(windowsUIHandle, MAKEINTRESOURCEA(1500)));
// Create the core window to host the XAML content
void* pCoreWindow;
hr = pfnPrivateCreateCoreWindow(IMMERSIVE_HOSTED, L"", 0, 0, 0, 0, 0, parentWindow, winrt::guid_of<Core::ICoreWindow>(), &pCoreWindow);
winrt::check_hresult(hr);
coreWindow = Core::CoreWindow(pCoreWindow, winrt::take_ownership_from_abi);
// Prep for the WinUI resources
auto app = Microsoft::Toolkit::Win32::UI::XamlHost::XamlApplication({ Microsoft::UI::Xaml::XamlTypeInfo::XamlControlsXamlMetaDataProvider() });
// Initialize the XAML framework
frameworkView.Initialize(*reinterpret_cast<wac::CoreApplicationView*>(&make<XamlBridgeCoreAppViewImpl>()));
frameworkView.SetWindow(coreWindow);
// Add the WinUI resources
app.Resources().MergedDictionaries().Append(muxc::XamlControlsResources());
auto coreWindowInterop = coreWindow.as<ICoreWindowInterop>();
hr = coreWindowInterop->get_WindowHandle(&coreWindowHwnd);
winrt::check_hresult(hr);
SetParent(coreWindowHwnd, parentWindow);
SetWindowLong(coreWindowHwnd, GWL_STYLE, WS_CHILD | WS_VISIBLE);
return coreWindowHwnd;
}
// Message Handler function for Xaml windows
LRESULT XamlBridge2::MessageHandler(UINT const message, WPARAM const wParam, LPARAM const lParam) noexcept
{
switch (message)
{
case WM_ACTIVATE:
case WM_MOVE:
SendMessage(coreWindowHwnd, message, wParam, lParam);
break;
}
return DefWindowProc(parentWindow, message, wParam, lParam);
}

View File

@ -0,0 +1,46 @@
#pragma once
// This class is used for handling XAML operations
class XamlBridge2
{
public:
// Function to run the message loop for the xaml window
void MessageLoop();
// Constructor
XamlBridge2(HWND parent) : parentWindow(parent) {}
// Function to initialize the xaml bridge
HWND InitBridge();
// Message Handler function for Xaml windows
LRESULT MessageHandler(UINT const message, WPARAM const wParam, LPARAM const lParam) noexcept;
private:
// Defines the window types for core windows
enum WINDOW_TYPE
{
IMMERSIVE_BODY = 0x0,
IMMERSIVE_DOCK = 0x1,
IMMERSIVE_HOSTED = 0x2,
IMMERSIVE_TEST = 0x3,
IMMERSIVE_BODY_ACTIVE = 0x4,
IMMERSIVE_DOCK_ACTIVE = 0x5,
NOT_IMMERSIVE = 0x6,
};
// Function signature for PrivateCreateCoreWindow
typedef HRESULT(CDECL* fnPrivateCreateCoreWindow)(WINDOW_TYPE WindowType, LPCWSTR pWindowTitle, INT X, INT Y, UINT uWidth, UINT uHeight, DWORD dwAttributes, HWND hOwnerWindow, REFIID riid, void** ppv);
// Stores the handle of the parent native window
HWND parentWindow = nullptr;
// Stores the core window for the UI thread
Core::CoreWindow coreWindow = nullptr;
// Stores the handle of the core window
HWND coreWindowHwnd = nullptr;
// Stores the xaml framework view for the UI thread
FrameworkView frameworkView;
};

View File

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.2-prerelease.220830001" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.2088.41" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" />
</packages>

View File

@ -10,8 +10,10 @@
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.Text.h>
#include <winrt/Windows.ApplicationModel.Core.h>
#pragma push_macro("GetCurrentTime")
#undef GetCurrentTime
@ -21,6 +23,7 @@
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Windows.ui.xaml.media.h>
#include <winrt/Microsoft.UI.Xaml.Controls.h>
#pragma pop_macro("GetCurrentTime")
#include <common/logger/logger.h>
@ -37,4 +40,5 @@ using namespace Windows::UI::Composition;
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls;
namespace muxc = Microsoft::UI::Xaml::Controls;