diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/ContentFormControl.xaml.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/ContentFormControl.xaml.cs index 59044f34a549..9e648cf6dad6 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/ContentFormControl.xaml.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/ContentFormControl.xaml.cs @@ -8,7 +8,9 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Automation; using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; +using Windows.System; namespace Microsoft.CmdPal.UI.Controls; @@ -22,6 +24,7 @@ public sealed partial class ContentFormControl : UserControl // tree. If this gets GC'ed, then it'll revoke our Action handler, and the // form will do seemingly nothing. private RenderedAdaptiveCard? _renderedCard; + private AdaptiveCard? _adaptiveCard; public ContentFormViewModel? ViewModel { get => _viewModel; set => AttachViewModel(value); } @@ -95,9 +98,11 @@ private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.Pro private void DisplayCard(AdaptiveCardParseResult result) { _renderedCard = _renderer.RenderAdaptiveCard(result.AdaptiveCard); + _adaptiveCard = result.AdaptiveCard; ContentGrid.Children.Clear(); if (_renderedCard.FrameworkElement is not null) { + _renderedCard.FrameworkElement.KeyDown += OnFormKeyDown; ContentGrid.Children.Add(_renderedCard.FrameworkElement); // Use the Loaded event to ensure we focus after the card is in the visual tree @@ -276,6 +281,44 @@ private static void FixToggleAccessibilityNames(DependencyObject root) return null; } + private void OnFormKeyDown(object sender, KeyRoutedEventArgs e) + { + if (e.Key != VirtualKey.Enter || _renderedCard == null || _adaptiveCard == null) + { + return; + } + + // Only submit when Enter is pressed inside a single-line TextBox + if (e.OriginalSource is TextBox textBox && !textBox.AcceptsReturn) + { + // Find the first Submit or Execute action on the card + IAdaptiveActionElement? submitAction = null; + foreach (var action in _adaptiveCard.Actions) + { + if (action is AdaptiveSubmitAction or AdaptiveExecuteAction) + { + submitAction = action; + break; + } + } + + if (submitAction != null) + { + e.Handled = true; + + // Validate (and gather) the inputs before submitting. AsJson() only + // returns the values cached by a successful ValidateInputs() call, so + // skipping this would submit an empty payload. This mirrors what the + // renderer does internally when a submit button is clicked. + var inputs = _renderedCard.UserInputs; + if (inputs.ValidateInputs(submitAction)) + { + ViewModel?.HandleSubmit(submitAction, inputs.AsJson()); + } + } + } + } + private void Rendered_Action(RenderedAdaptiveCard sender, AdaptiveActionEventArgs args) => ViewModel?.HandleSubmit(args.Action, args.Inputs.AsJson()); }