From ca1a289e39b48caa88f1ba2d5ca6a5e453ea004f Mon Sep 17 00:00:00 2001 From: Michael Jolley Date: Sat, 20 Jun 2026 21:00:46 -0500 Subject: [PATCH] cmdpal: Support Enter key to submit FormContent inputs When a user presses Enter inside a single-line TextBox within an Adaptive Card form, find the first Submit or Execute action on the card and trigger form submission with the current input values. This enables keyboard-only form workflows (e.g. login/unlock forms in extensions) without requiring users to click the submit button. Multiline text inputs (AcceptsReturn=true) are excluded so that Enter still inserts newlines in those fields. Fixes #46003 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Controls/ContentFormControl.xaml.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) 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..0a7ca23fc4b3 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,35 @@ 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; + ViewModel?.HandleSubmit(submitAction, _renderedCard.UserInputs.AsJson()); + } + } + } + private void Rendered_Action(RenderedAdaptiveCard sender, AdaptiveActionEventArgs args) => ViewModel?.HandleSubmit(args.Action, args.Inputs.AsJson()); }