[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
21 changed files with 386 additions and 193 deletions

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;