Compare commits

...

10 Commits

Author SHA1 Message Date
Yu Leng
0d68cd1ea4 merge main 2025-06-18 12:53:24 +08:00
Yu Leng
ce29b6706d format 2025-06-18 12:39:10 +08:00
Yu Leng
6aa7a76918 merge 2025-06-18 12:29:00 +08:00
Yu Leng
5289635c49 merge main 2025-06-18 12:13:30 +08:00
Yu Leng
3b99b2fc6e merge main 2025-06-18 12:06:13 +08:00
Yu Leng
26d21972ee merge main 2025-06-16 09:21:07 +08:00
Yu Leng
15e7b4ca00 merge main 2025-06-16 09:16:24 +08:00
Yu Leng
b34ab09716 merge main 2025-06-16 09:01:01 +08:00
Yu Leng
b3c533e4c4 update 2025-06-06 15:03:40 +08:00
Yu Leng
2bdb591ac8 init 2025-06-06 14:46:48 +08:00
19 changed files with 110 additions and 804 deletions

View File

@@ -633,8 +633,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Apps",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Bookmarks", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj", "{E09AA983-C755-474F-83D6-A5CDF528C070}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Calc", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj", "{6D56B64D-FF1F-488F-AFED-9B9854A5D399}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Registry", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj", "{92EC89E4-9972-453A-8A1A-3A9E230C146A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsServices", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj", "{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}"
@@ -723,6 +721,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesEditorUITest", "s
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorEngineCommon", "src\common\CalculatorEngineCommon\CalculatorEngineCommon.vcxproj", "{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Calc", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj", "{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -2299,14 +2299,6 @@ Global
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|ARM64.Build.0 = Release|ARM64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|x64.ActiveCfg = Release|x64
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|x64.Build.0 = Release|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|ARM64.Build.0 = Debug|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|x64.ActiveCfg = Debug|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|x64.Build.0 = Debug|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|ARM64.ActiveCfg = Release|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|ARM64.Build.0 = Release|ARM64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|x64.ActiveCfg = Release|x64
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|x64.Build.0 = Release|x64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|ARM64.Build.0 = Debug|ARM64
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|x64.ActiveCfg = Debug|x64
@@ -2649,6 +2641,14 @@ Global
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Release|ARM64.Build.0 = Release|ARM64
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Release|x64.ActiveCfg = Release|x64
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Release|x64.Build.0 = Release|x64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Debug|ARM64.Build.0 = Debug|ARM64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Debug|x64.ActiveCfg = Debug|x64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Debug|x64.Build.0 = Debug|x64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Release|ARM64.ActiveCfg = Release|ARM64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Release|ARM64.Build.0 = Release|ARM64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Release|x64.ActiveCfg = Release|x64
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2881,7 +2881,6 @@ Global
{ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{6CE438DF-C245-4997-A360-0A0939E4BA34} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{E09AA983-C755-474F-83D6-A5CDF528C070} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{6D56B64D-FF1F-488F-AFED-9B9854A5D399} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{92EC89E4-9972-453A-8A1A-3A9E230C146A} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{D1160404-D3D1-497A-883A-4059C07C2273} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
@@ -2926,6 +2925,7 @@ Global
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{E69B16BE-278F-3A09-394C-CCFF3F3ECE12} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -29,9 +29,7 @@ namespace ManagedCommon
* If you want to publish it with Native AOT enabled (or publish as a single file).
* You need to find another way to remove Assembly.Location usage.
*/
#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
private static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location).ProductVersion;
#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
private static readonly string Version = "2.0.0";
/// <summary>
/// Initializes the logger and sets the path for logging.

View File

@@ -37,17 +37,6 @@ namespace Microsoft.PowerToys.Telemetry
public void WriteEvent<T>(T telemetryEvent)
where T : EventBase, IEvent
{
if (DataDiagnosticsSettings.GetEnabledValue())
{
this.Write<T>(
telemetryEvent.EventName,
new EventSourceOptions()
{
Keywords = ProjectKeywordMeasure,
Tags = ProjectTelemetryTagProductAndServicePerformance,
},
telemetryEvent);
}
}
}
}

View File

@@ -3,11 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using AdaptiveCards.ObjectModel.WinUI3;
using AdaptiveCards.Templating;
using CommunityToolkit.Mvvm.Messaging;
using ManagedCommon;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Windows.Data.Json;
@@ -27,145 +22,14 @@ public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPag
public string DataJson { get; protected set; } = "{}";
public AdaptiveCardParseResult? Card { get; private set; }
private static string Serialize(string? s) =>
JsonSerializer.Serialize(s, JsonSerializationContext.Default.String);
private static bool TryBuildCard(
string templateJson,
string dataJson,
out AdaptiveCardParseResult? card,
out Exception? error)
{
card = null;
error = null;
try
{
var template = new AdaptiveCardTemplate(templateJson);
var cardJson = template.Expand(dataJson);
card = AdaptiveCard.FromJsonString(cardJson);
return true;
}
catch (Exception ex)
{
Logger.LogError("Error building card from template: {Message}", ex.Message);
error = ex;
return false;
}
}
public override void InitializeProperties()
{
var model = _formModel.Unsafe;
if (model is null)
{
return;
}
}
TemplateJson = model.TemplateJson;
StateJson = model.StateJson;
DataJson = model.DataJson;
if (TryBuildCard(TemplateJson, DataJson, out var builtCard, out var renderingError))
{
Card = builtCard;
UpdateProperty(nameof(Card));
return;
}
var errorPayload = $$"""
public void HandleSubmit()
{
"error_message": {{Serialize(renderingError!.Message)}},
"error_stack": {{Serialize(renderingError.StackTrace)}},
"inner_exception": {{Serialize(renderingError.InnerException?.Message)}},
"template_json": {{Serialize(TemplateJson)}},
"data_json": {{Serialize(DataJson)}}
}
""";
if (TryBuildCard(ErrorCardJson, errorPayload, out var errorCard, out var _))
{
Card = errorCard;
UpdateProperty(nameof(Card));
return;
}
UpdateProperty(nameof(Card));
}
public void HandleSubmit(IAdaptiveActionElement action, JsonObject inputs)
{
if (action is AdaptiveOpenUrlAction openUrlAction)
{
WeakReferenceMessenger.Default.Send<LaunchUriMessage>(new(openUrlAction.Url));
return;
}
if (action is AdaptiveSubmitAction or AdaptiveExecuteAction)
{
// Get the data and inputs
var dataString = (action as AdaptiveSubmitAction)?.DataJson.Stringify() ?? string.Empty;
var inputString = inputs.Stringify();
_ = Task.Run(() =>
{
try
{
var model = _formModel.Unsafe!;
if (model != null)
{
var result = model.SubmitForm(inputString, dataString);
WeakReferenceMessenger.Default.Send<HandleCommandResultMessage>(new(new(result)));
}
}
catch (Exception ex)
{
ShowException(ex);
}
});
}
}
private static readonly string ErrorCardJson = """
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "TextBlock",
"text": "Error parsing form from extension",
"wrap": true,
"style": "heading",
"size": "ExtraLarge",
"weight": "Bolder",
"color": "Attention"
},
{
"type": "TextBlock",
"wrap": true,
"text": "${error_message}",
"color": "Attention"
},
{
"type": "TextBlock",
"text": "${error_stack}",
"fontType": "Monospace"
},
{
"type": "TextBlock",
"wrap": true,
"text": "Inner exception:"
},
{
"type": "TextBlock",
"wrap": true,
"text": "${inner_exception}",
"color": "Attention"
}
]
}
""";
}

View File

@@ -17,8 +17,6 @@
<ItemGroup>
<PackageReference Include="CommunityToolkit.Common" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="AdaptiveCards.Templating" />
<PackageReference Include="AdaptiveCards.ObjectModel.WinUI3" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Windows.CsWin32">
<PrivateAssets>all</PrivateAssets>

View File

@@ -1,342 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using AdaptiveCards.Rendering.WinUI3;
namespace Microsoft.CmdPal.UI.Controls;
public sealed class AdaptiveCardsConfig
{
public static AdaptiveHostConfig Light { get; }
public static AdaptiveHostConfig Dark { get; }
static AdaptiveCardsConfig()
{
Light = AdaptiveHostConfig.FromJsonString(LightHostConfigString).HostConfig;
Dark = AdaptiveHostConfig.FromJsonString(DarkHostConfigString).HostConfig;
}
public static readonly string DarkHostConfigString = """
{
"spacing": {
"small": 4,
"default": 8,
"medium": 20,
"large": 30,
"extraLarge": 40,
"padding": 8
},
"separator": {
"lineThickness": 0,
"lineColor": "#C8FFFFFF"
},
"supportsInteractivity": true,
"fontTypes": {
"default": {
"fontFamily": "'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
"fontSizes": {
"small": 12,
"default": 12,
"medium": 14,
"large": 20,
"extraLarge": 26
},
"fontWeights": {
"lighter": 200,
"default": 400,
"bolder": 600
}
},
"monospace": {
"fontFamily": "'Courier New', Courier, monospace",
"fontSizes": {
"small": 12,
"default": 12,
"medium": 14,
"large": 18,
"extraLarge": 26
},
"fontWeights": {
"lighter": 200,
"default": 400,
"bolder": 600
}
}
},
"containerStyles": {
"default": {
"backgroundColor": "#00000000",
"borderColor": "#00000000",
"foregroundColors": {
"default": {
"default": "#FFFFFF",
"subtle": "#C8FFFFFF"
},
"accent": {
"default": "#0063B1",
"subtle": "#880063B1"
},
"attention": {
"default": "#FF5555",
"subtle": "#DDFF5555"
},
"good": {
"default": "#54a254",
"subtle": "#DD54a254"
},
"warning": {
"default": "#c3ab23",
"subtle": "#DDc3ab23"
}
}
},
"emphasis": {
"backgroundColor": "#09FFFFFF",
"borderColor": "#09FFFFFF",
"foregroundColors": {
"default": {
"default": "#FFFFFF",
"subtle": "#C8FFFFFF"
},
"accent": {
"default": "#2E89FC",
"subtle": "#882E89FC"
},
"attention": {
"default": "#FF5555",
"subtle": "#DDFF5555"
},
"good": {
"default": "#54a254",
"subtle": "#DD54a254"
},
"warning": {
"default": "#c3ab23",
"subtle": "#DDc3ab23"
}
}
}
},
"imageSizes": {
"small": 16,
"medium": 24,
"large": 32
},
"actions": {
"maxActions": 5,
"spacing": "default",
"buttonSpacing": 8,
"showCard": {
"actionMode": "inline",
"inlineTopMargin": 8
},
"actionsOrientation": "horizontal",
"actionAlignment": "stretch"
},
"adaptiveCard": {
"allowCustomStyle": false
},
"imageSet": {
"imageSize": "medium",
"maxImageHeight": 100
},
"factSet": {
"title": {
"color": "default",
"size": "default",
"isSubtle": false,
"weight": "bolder",
"wrap": true,
"maxWidth": 150
},
"value": {
"color": "default",
"size": "default",
"isSubtle": false,
"weight": "default",
"wrap": true
},
"spacing": 8
},
"textStyles": {
"heading": {
"size": "large",
"weight": "bolder",
"color": "default",
"isSubtle": false,
"fontType": "default"
},
"columnHeader": {
"size": "medium",
"weight": "bolder",
"color": "default",
"isSubtle": false,
"fontType": "default"
}
}
}
""";
public static readonly string LightHostConfigString = """
{
"spacing": {
"small": 4,
"default": 8,
"medium": 20,
"large": 30,
"extraLarge": 40,
"padding": 8
},
"separator": {
"lineThickness": 0,
"lineColor": "#606060"
},
"supportsInteractivity": true,
"fontTypes": {
"default": {
"fontFamily": "'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
"fontSizes": {
"small": 12,
"default": 12,
"medium": 14,
"large": 20,
"extraLarge": 26
},
"fontWeights": {
"lighter": 200,
"default": 400,
"bolder": 600
}
},
"monospace": {
"fontFamily": "'Courier New', Courier, monospace",
"fontSizes": {
"small": 12,
"default": 12,
"medium": 14,
"large": 18,
"extraLarge": 26
},
"fontWeights": {
"lighter": 200,
"default": 400,
"bolder": 600
}
}
},
"containerStyles": {
"default": {
"backgroundColor": "#00000000",
"borderColor": "#00000000",
"foregroundColors": {
"default": {
"default": "#E6000000",
"subtle": "#99000000"
},
"accent": {
"default": "#0063B1",
"subtle": "#880063B1"
},
"attention": {
"default": "#C00000",
"subtle": "#DDC00000"
},
"good": {
"default": "#54a254",
"subtle": "#DD54a254"
},
"warning": {
"default": "#c3ab23",
"subtle": "#DDc3ab23"
}
}
},
"emphasis": {
"backgroundColor": "#80F6F6F6",
"borderColor": "#80F6F6F6",
"foregroundColors": {
"default": {
"default": "#E6000000",
"subtle": "#99000000"
},
"accent": {
"default": "#2E89FC",
"subtle": "#882E89FC"
},
"attention": {
"default": "#C00000",
"subtle": "#DDC00000"
},
"good": {
"default": "#54a254",
"subtle": "#DD54a254"
},
"warning": {
"default": "#c3ab23",
"subtle": "#DDc3ab23"
}
}
}
},
"imageSizes": {
"small": 16,
"medium": 24,
"large": 32
},
"actions": {
"maxActions": 5,
"spacing": "default",
"buttonSpacing": 8,
"showCard": {
"actionMode": "inline",
"inlineTopMargin": 8
},
"actionsOrientation": "horizontal",
"actionAlignment": "stretch"
},
"adaptiveCard": {
"allowCustomStyle": false
},
"imageSet": {
"imageSize": "medium",
"maxImageHeight": 100
},
"factSet": {
"title": {
"color": "default",
"size": "default",
"isSubtle": false,
"weight": "bolder",
"wrap": true,
"maxWidth": 150
},
"value": {
"color": "default",
"size": "default",
"isSubtle": false,
"weight": "default",
"wrap": true
},
"spacing": 8
},
"textStyles": {
"heading": {
"size": "large",
"weight": "bolder",
"color": "default",
"isSubtle": false,
"fontType": "default"
},
"columnHeader": {
"size": "medium",
"weight": "bolder",
"color": "default",
"isSubtle": false,
"fontType": "default"
}
}
}
""";
}

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="Microsoft.CmdPal.UI.Controls.ContentFormControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.CmdPal.UI.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:CommunityToolkit.WinUI"
xmlns:viewmodels="using:Microsoft.CmdPal.UI.ViewModels"
Background="Transparent"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary x:Name="CardOverrideStyles">
<Style x:Key="Adaptive.TextBlock" TargetType="TextBlock">
<Setter Property="IsTextSelectionEnabled" Value="True" />
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="ContentGrid" />
</UserControl>

View File

@@ -1,162 +1,32 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using AdaptiveCards.ObjectModel.WinUI3;
using AdaptiveCards.Rendering.WinUI3;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
namespace Microsoft.CmdPal.UI.Controls;
public sealed partial class ContentFormControl : UserControl
{
private static readonly AdaptiveCardRenderer _renderer;
#pragma warning disable CS0649
private ContentFormViewModel? _viewModel;
// LOAD-BEARING: if you don't hang onto a reference to the RenderedAdaptiveCard
// then the GC might clean it up sometime, even while the card is in the UI
// tree. If this gets GC'ed, then it'll revoke our Action handler, and the
// form will do seemingly nothing.
private RenderedAdaptiveCard? _renderedCard;
#pragma warning restore CS0649
public ContentFormViewModel? ViewModel { get => _viewModel; set => AttachViewModel(value); }
static ContentFormControl()
{
// We can't use `CardOverrideStyles` here yet, because we haven't called InitializeComponent once.
// But also, the default value isn't `null` here. It's... some other default empty value.
// So clear it out so that we know when the first time we get created is
_renderer = new AdaptiveCardRenderer()
{
OverrideStyles = null,
};
}
public ContentFormControl()
{
this.InitializeComponent();
var lightTheme = ActualTheme == Microsoft.UI.Xaml.ElementTheme.Light;
_renderer.HostConfig = lightTheme ? AdaptiveCardsConfig.Light : AdaptiveCardsConfig.Dark;
// 5% BODGY: if we set this multiple times over the lifetime of the app,
// then the second call will explode, because "CardOverrideStyles is already the child of another element".
// SO only set this once.
if (_renderer.OverrideStyles == null)
{
_renderer.OverrideStyles = CardOverrideStyles;
}
// TODO in the future, we should handle ActualThemeChanged and replace
// our rendered card with one for that theme. But today is not that day
}
private void AttachViewModel(ContentFormViewModel? vm)
{
if (_viewModel != null)
{
_viewModel.PropertyChanged -= ViewModel_PropertyChanged;
}
_viewModel = vm;
if (_viewModel != null)
{
_viewModel.PropertyChanged += ViewModel_PropertyChanged;
var c = _viewModel.Card;
if (c != null)
{
DisplayCard(c);
}
}
}
private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (ViewModel == null)
{
return;
}
if (e.PropertyName == nameof(ViewModel.Card))
{
var c = ViewModel.Card;
if (c != null)
{
DisplayCard(c);
}
}
}
private void DisplayCard(AdaptiveCardParseResult result)
{
_renderedCard = _renderer.RenderAdaptiveCard(result.AdaptiveCard);
ContentGrid.Children.Clear();
if (_renderedCard.FrameworkElement != null)
{
ContentGrid.Children.Add(_renderedCard.FrameworkElement);
// Use the Loaded event to ensure we focus after the card is in the visual tree
_renderedCard.FrameworkElement.Loaded += OnFrameworkElementLoaded;
}
_renderedCard.Action += Rendered_Action;
}
private void OnFrameworkElementLoaded(object sender, RoutedEventArgs e)
{
// Unhook the event handler to avoid multiple registrations
if (sender is FrameworkElement element)
{
element.Loaded -= OnFrameworkElementLoaded;
if (!ViewModel?.OnlyControlOnPage ?? true)
{
return;
}
// Focus on the first focusable element asynchronously to ensure the visual tree is fully built
element.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
{
var focusableElement = FindFirstFocusableElement(element);
focusableElement?.Focus(FocusState.Programmatic);
});
}
}
private Control? FindFirstFocusableElement(DependencyObject parent)
{
var childCount = VisualTreeHelper.GetChildrenCount(parent);
// Process children first (depth-first search)
for (var i = 0; i < childCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is a focusable control like TextBox, ComboBox, etc.
if (child is Control control &&
control.IsEnabled &&
control.IsTabStop &&
control.Visibility == Visibility.Visible &&
control.AllowFocusOnInteraction)
{
return control;
}
// Recursively check children
var result = FindFirstFocusableElement(child);
if (result != null)
{
return result;
}
}
return null;
}
private void Rendered_Action(RenderedAdaptiveCard sender, AdaptiveActionEventArgs args) =>
ViewModel?.HandleSubmit(args.Action, args.Inputs.AsJson());
}

View File

@@ -12,7 +12,7 @@ public delegate bool IsActive();
public delegate bool FilterAccessibleKeyboardEvents(int key, UIntPtr extraInfo);
public class HotkeySettingsControlHook : IDisposable
public partial class HotkeySettingsControlHook : IDisposable
{
private const int WmKeyDown = 0x100;
private const int WmKeyUp = 0x101;

View File

@@ -5,82 +5,81 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.PowerToys.Settings.UI.Helpers
namespace Microsoft.PowerToys.Settings.UI.Helpers;
internal static class NativeKeyboardHelper
{
internal static class NativeKeyboardHelper
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct INPUT
{
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct INPUT
{
internal INPUTTYPE type;
internal InputUnion data;
internal INPUTTYPE type;
internal InputUnion data;
internal static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
}
}
[StructLayout(LayoutKind.Explicit)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct InputUnion
internal static int Size
{
[FieldOffset(0)]
internal MOUSEINPUT mi;
[FieldOffset(0)]
internal KEYBDINPUT ki;
[FieldOffset(0)]
internal HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct MOUSEINPUT
{
internal int dx;
internal int dy;
internal int mouseData;
internal uint dwFlags;
internal uint time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct KEYBDINPUT
{
internal short wVk;
internal short wScan;
internal uint dwFlags;
internal int time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct HARDWAREINPUT
{
internal int uMsg;
internal short wParamL;
internal short wParamH;
}
internal enum INPUTTYPE : uint
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}
[Flags]
internal enum KeyEventF
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008,
get { return Marshal.SizeOf<INPUT>(); }
}
}
[StructLayout(LayoutKind.Explicit)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct InputUnion
{
[FieldOffset(0)]
internal MOUSEINPUT mi;
[FieldOffset(0)]
internal KEYBDINPUT ki;
[FieldOffset(0)]
internal HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct MOUSEINPUT
{
internal int dx;
internal int dy;
internal int mouseData;
internal uint dwFlags;
internal uint time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct KEYBDINPUT
{
internal short wVk;
internal short wScan;
internal uint dwFlags;
internal int time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
internal struct HARDWAREINPUT
{
internal int uMsg;
internal short wParamL;
internal short wParamH;
}
internal enum INPUTTYPE : uint
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}
[Flags]
internal enum KeyEventF
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008,
}
}

View File

@@ -7,7 +7,7 @@ using System.Text;
namespace Microsoft.PowerToys.Settings.UI.Helpers;
public static class NativeMethods
public static partial class NativeMethods
{
private const int WS_POPUP = 1 << 31; // 0x80000000
internal const int GWL_STYLE = -16;
@@ -26,11 +26,11 @@ public static class NativeMethods
[DllImport("user32.dll")]
internal static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize);
[LibraryImport("user32.dll")]
internal static partial uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern short GetAsyncKeyState(int vKey);
[LibraryImport("user32.dll")]
internal static partial short GetAsyncKeyState(int vKey);
[DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

View File

@@ -66,11 +66,6 @@
IsTabStop="{Binding ElementName=ShortcutContentControl, Path=IsWarningAltGr, Mode=OneWay}"
Severity="Warning" />
</Grid>
<tk7controls:MarkdownTextBlock
x:Uid="InvalidShortcutWarningLabel"
Background="Transparent"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -36,10 +36,5 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<tk7controls:MarkdownTextBlock
Grid.Column="1"
VerticalAlignment="Center"
Background="Transparent"
Text="{x:Bind Text}" />
</Grid>
</UserControl>

View File

@@ -41,36 +41,12 @@
</Grid>
</DataTemplate>
<DataTemplate x:Key="MarkdownContentTemplate" x:DataType="viewmodels:ContentMarkdownViewModel">
<Grid Margin="0,4,4,4" Padding="12,8,8,8">
<toolkit:MarkdownTextBlock
Background="Transparent"
Header3FontSize="12"
Header3FontWeight="Normal"
Header3Foreground="{ThemeResource TextFillColorSecondaryBrush}"
IsTextSelectionEnabled="True"
Text="{x:Bind Body, Mode=OneWay}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="NestedFormContentTemplate" x:DataType="viewmodels:ContentFormViewModel">
<Grid>
<cmdPalControls:ContentFormControl ViewModel="{x:Bind}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="NestedMarkdownContentTemplate" x:DataType="viewmodels:ContentMarkdownViewModel">
<Grid>
<toolkit:MarkdownTextBlock
Background="Transparent"
Header3FontSize="12"
Header3FontWeight="Normal"
Header3Foreground="{ThemeResource TextFillColorSecondaryBrush}"
IsTextSelectionEnabled="True"
Text="{x:Bind Body, Mode=OneWay}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="TreeContentTemplate" x:DataType="viewmodels:ContentTreeViewModel">
<StackPanel
Margin="0,4,4,4"

View File

@@ -72,7 +72,7 @@ internal sealed partial class TrayIconService
_largeIcon = GetAppIconHandle();
_trayIconData = new NOTIFYICONDATAW()
{
cbSize = (uint)Marshal.SizeOf(typeof(NOTIFYICONDATAW)),
cbSize = (uint)Marshal.SizeOf<NOTIFYICONDATAW>(),
hWnd = _hwnd,
uID = MY_NOTIFY_ID,
uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_MESSAGE | NOTIFY_ICON_DATA_FLAGS.NIF_ICON | NOTIFY_ICON_DATA_FLAGS.NIF_TIP,
@@ -133,7 +133,7 @@ internal sealed partial class TrayIconService
private DestroyIconSafeHandle GetAppIconHandle()
{
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
var exePath = Path.Combine(AppContext.BaseDirectory, "Microsoft.CmdPal.UI.exe");
DestroyIconSafeHandle largeIcon;
PInvoke.ExtractIconEx(exePath, 0, out largeIcon, out _, 1);
return largeIcon;

View File

@@ -23,6 +23,16 @@
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<PropertyGroup>
<SelfContained>true</SelfContained>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>false</PublishSingleFile>
<DisableRuntimeMarshalling>false</DisableRuntimeMarshalling>
<PublishAot>true</PublishAot>
<EnableMsixTooling>true</EnableMsixTooling>
</PropertyGroup>
<PropertyGroup>
<GenerateAppxPackageOnBuild>true</GenerateAppxPackageOnBuild>
</PropertyGroup>
@@ -71,7 +81,6 @@
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
<PackageReference Include="CommunityToolkit.WinUI.Animations" />
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Markdown" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
@@ -90,9 +99,6 @@
<PackageReference Include="System.Text.Json" />
<!-- LOAD BEARING: GeneratePathProperty=true on BOTH the AC dependencies. Don't forget the AdaptiveCardsWorkaround below -->
<PackageReference Include="AdaptiveCards.ObjectModel.WinUI3" GeneratePathProperty="true" />
<PackageReference Include="AdaptiveCards.Rendering.WinUI3" GeneratePathProperty="True" />
<PackageReference Include="AdaptiveCards.Templating" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
@@ -185,10 +191,6 @@
<PropertyGroup>
<AdaptiveCardsNative>runtimes\win10-$(Platform)\native</AdaptiveCardsNative>
</PropertyGroup>
<ItemGroup>
<Content Include="$(PkgAdaptiveCards_ObjectModel_WinUI3)\$(AdaptiveCardsNative)\AdaptiveCards.ObjectModel.WinUI3.dll" Link="AdaptiveCards.ObjectModel.WinUI3.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(PkgAdaptiveCards_Rendering_WinUI3)\$(AdaptiveCardsNative)\AdaptiveCards.Rendering.WinUI3.dll" Link="AdaptiveCards.Rendering.WinUI3.dll" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<Content Update="..\Microsoft.CmdPal.UI.ViewModels\Assets\template.zip">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@@ -1,7 +1,6 @@
GetPhysicallyInstalledSystemMemory
GlobalMemoryStatusEx
GetSystemInfo
CoCreateInstance
GetForegroundWindow
SetForegroundWindow
GetWindowRect
@@ -21,10 +20,7 @@ SetActiveWindow
MonitorFromWindow
GetMonitorInfo
GetDpiForMonitor
SHCreateStreamOnFileEx
CoAllowSetForegroundWindow
SHCreateStreamOnFileEx
SHLoadIndirectString
WM_HOTKEY
WM_NCLBUTTONDBLCLK
@@ -33,7 +29,6 @@ LoadIcon
WM_USER
WM_WINDOWPOSCHANGING
RegisterWindowMessageW
GetModuleHandleW
ExtractIconEx
TRACK_POPUP_MENU_FLAGS
WM_COMMAND

View File

@@ -10,7 +10,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls"
xmlns:toolkit="using:CommunityToolkit.WinUI.Controls"
xmlns:ui="using:CommunityToolkit.WinUI"
xmlns:viewModels="using:Microsoft.CmdPal.UI.ViewModels"
Background="Transparent"
@@ -408,16 +408,6 @@
TextWrapping="WrapWholeWords"
Visibility="{x:Bind ViewModel.Details.Title, Converter={StaticResource StringNotEmptyToVisibilityConverter}, Mode=OneWay}" />
<toolkit:MarkdownTextBlock
Grid.Row="2"
Margin="0,12,0,24"
Background="Transparent"
Header3FontSize="12"
Header3FontWeight="Normal"
Header3Foreground="{ThemeResource TextFillColorSecondaryBrush}"
IsTextSelectionEnabled="True"
Text="{x:Bind ViewModel.Details.Body, Mode=OneWay}" />
<ItemsRepeater
Grid.Row="3"
ItemTemplate="{StaticResource DetailsDataTemplateSelector}"
@@ -444,7 +434,8 @@
FontWeight="SemiBold"
Foreground="{ThemeResource SystemErrorTextColor}"
Text="Error(s) on page:" />
<LineBreak /><Run Text="{x:Bind ViewModel.CurrentPage.ErrorMessage, Mode=OneWay}" />
<LineBreak />
<Run Text="{x:Bind ViewModel.CurrentPage.ErrorMessage, Mode=OneWay}" />
</TextBlock>
</ScrollView>
</Grid>

View File

@@ -13,7 +13,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">True</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
</PropertyGroup>
</Project>