diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml b/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml index b471b67d5d..3ac3519cb4 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml @@ -216,7 +216,6 @@ @@ -225,7 +224,6 @@ Click="SettingsCard_Click" DataContext="{x:Bind}" Description="{x:Bind ExtensionSubtext, Mode=OneWay}" - GotFocus="SettingsCard_GotFocus" Header="{x:Bind DisplayName, Mode=OneWay}" IsClickEnabled="True"> diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml.cs index bfa73c8a20..952b9ffee5 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/ExtensionsPage.xaml.cs @@ -19,7 +19,6 @@ public sealed partial class ExtensionsPage : Page private readonly TaskScheduler _mainTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); private readonly SettingsViewModel? viewModel; - private int _lastFocusedIndex; public ExtensionsPage() { @@ -59,157 +58,4 @@ public sealed partial class ExtensionsPage : Page Logger.LogError("Error when showing FallbackRankerDialog", ex); } } - - private void SettingsCard_GotFocus(object sender, RoutedEventArgs e) - { - // Track focus whenever any part of the card gets focus (including children like ToggleSwitch) - if (sender is SettingsCard card && viewModel is not null) - { - var dataContext = card.DataContext as ProviderSettingsViewModel; - if (dataContext is not null) - { - var filteredProviders = viewModel.Extensions.FilteredProviders; - var index = filteredProviders.IndexOf(dataContext); - if (index >= 0) - { - _lastFocusedIndex = index; - } - } - } - } - - private void ProvidersRepeater_GettingFocus(UIElement sender, GettingFocusEventArgs args) - { - if (viewModel is null || ProvidersRepeater is null) - { - return; - } - - // Only intervene when focus is coming into the ItemsRepeater from outside - if (args.OldFocusedElement != null && IsElementInsideRepeater(args.OldFocusedElement)) - { - return; - } - - var filteredProviders = viewModel.Extensions.FilteredProviders; - - if (filteredProviders.Count == 0) - { - return; - } - - // Get the last focused index, defaulting to 0 - var index = _lastFocusedIndex; - if (index < 0 || index >= filteredProviders.Count) - { - index = 0; - } - - // Check if WinUI is trying to focus something other than our target - var shouldIntervene = false; - - // If direction is Previous (Shift+Tab), we need to intervene - if (args.Direction == FocusNavigationDirection.Previous || args.Direction == FocusNavigationDirection.Up) - { - shouldIntervene = true; - } - - // Also intervene if the NewFocusedElement is not at our target index - else if (args.NewFocusedElement is DependencyObject newFocus) - { - // Check if the new focus element is inside our target card - var targetCard = ProvidersRepeater.TryGetElement(index) as SettingsCard; - if (targetCard != null && !IsElementInsideCard(newFocus, targetCard)) - { - shouldIntervene = true; - } - } - - if (shouldIntervene) - { - // Ensure the target element is realized before trying to focus it - ProvidersRepeater.GetOrCreateElement(index); - - // Get the target card - var targetCard = ProvidersRepeater.TryGetElement(index) as SettingsCard; - - if (targetCard != null) - { - // For shift-tab or wrong target, cancel and manually set focus - args.TryCancel(); - args.Handled = true; - - // Set focus asynchronously to the target card and scroll it into view - _ = targetCard.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => - { - targetCard.Focus(FocusState.Keyboard); - BringCardIntoView(targetCard); - }); - } - } - else - { - // For normal Tab forward, just redirect - ProvidersRepeater.GetOrCreateElement(index); - var targetCard = ProvidersRepeater.TryGetElement(index) as SettingsCard; - - if (targetCard != null) - { - args.TrySetNewFocusedElement(targetCard); - args.Handled = true; - - // Set focus asynchronously to the target card and scroll it into view - _ = targetCard.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Low, () => - { - BringCardIntoView(targetCard); - }); - } - } - } - - private void BringCardIntoView(SettingsCard card) - { - card.StartBringIntoView(new BringIntoViewOptions - { - AnimationDesired = true, - VerticalAlignmentRatio = 0.5, // Center vertically - }); - } - - private bool IsElementInsideCard(DependencyObject element, SettingsCard card) - { - var parent = element; - while (parent != null) - { - if (ReferenceEquals(parent, card)) - { - return true; - } - - parent = Microsoft.UI.Xaml.Media.VisualTreeHelper.GetParent(parent); - } - - return false; - } - - private bool IsElementInsideRepeater(object element) - { - if (element is not DependencyObject depObj) - { - return false; - } - - var parent = depObj; - while (parent != null) - { - if (ReferenceEquals(parent, ProvidersRepeater)) - { - return true; - } - - parent = Microsoft.UI.Xaml.Media.VisualTreeHelper.GetParent(parent); - } - - return false; - } }