Skip to content

Commit 622b705

Browse files
authored
Code Quality: Fixed a number of focus related issues in Omnibar (#17239)
1 parent edb945b commit 622b705

File tree

7 files changed

+48
-49
lines changed

7 files changed

+48
-49
lines changed

src/Files.App.Controls/Omnibar/Omnibar.Events.cs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
// Copyright (c) Files Community
22
// Licensed under the MIT License.
33

4-
using Microsoft.UI.Input;
54
using Microsoft.UI.Xaml.Input;
65
using Windows.System;
7-
using Windows.UI.Core;
86

97
namespace Files.App.Controls
108
{
@@ -28,7 +26,7 @@ private void AutoSuggestBox_GettingFocus(UIElement sender, GettingFocusEventArgs
2826

2927
private void AutoSuggestBox_LosingFocus(UIElement sender, LosingFocusEventArgs args)
3028
{
31-
if (IsModeButtonPressed)
29+
if (args.NewFocusedElement is Button && IsModeButtonPressed)
3230
{
3331
IsModeButtonPressed = false;
3432
args.TryCancel();
@@ -47,12 +45,16 @@ private void AutoSuggestBox_GotFocus(object sender, RoutedEventArgs e)
4745
private void AutoSuggestBox_LostFocus(object sender, RoutedEventArgs e)
4846
{
4947
// TextBox still has focus if the context menu for selected text is open
50-
if (_textBox.ContextFlyout.IsOpen)
48+
var element = Microsoft.UI.Xaml.Input.FocusManager.GetFocusedElement(this.XamlRoot);
49+
if (element is FlyoutBase or Popup)
5150
return;
5251

5352
GlobalHelper.WriteDebugStringForOmnibar("The TextBox lost the focus.");
5453

5554
IsFocused = false;
55+
56+
// Reset to the default mode when Omnibar loses focus
57+
CurrentSelectedMode = Modes?.FirstOrDefault();
5658
}
5759

5860
private async void AutoSuggestBox_KeyDown(object sender, KeyRoutedEventArgs e)
@@ -112,16 +114,6 @@ private async void AutoSuggestBox_KeyDown(object sender, KeyRoutedEventArgs e)
112114
previouslyFocusedElement?.Focus(FocusState.Programmatic);
113115
}
114116
}
115-
else if (e.Key == VirtualKey.Tab && !InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down))
116-
{
117-
GlobalHelper.WriteDebugStringForOmnibar("The TextBox accepted the Tab key.");
118-
119-
// Focus on inactive content when pressing Tab instead of moving to the next control in the tab order
120-
e.Handled = true;
121-
IsFocused = false;
122-
await Task.Delay(15);
123-
CurrentSelectedMode?.ContentOnInactive?.Focus(FocusState.Keyboard);
124-
}
125117
else
126118
{
127119
_textChangeReason = OmnibarTextChangeReason.UserInput;
@@ -141,6 +133,8 @@ private void AutoSuggestBox_TextChanged(object sender, TextChangedEventArgs e)
141133
_textChangeReason = OmnibarTextChangeReason.UserInput;
142134
_userInput = _textBox.Text;
143135
}
136+
else if (_textChangeReason is OmnibarTextChangeReason.ProgrammaticChange)
137+
_textBox.SelectAll();
144138

145139
TextChanged?.Invoke(this, new(CurrentSelectedMode, _textChangeReason));
146140

src/Files.App.Controls/Omnibar/Omnibar.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ protected void ChangeMode(OmnibarMode? oldMode, OmnibarMode newMode)
128128
// Add the reposition transition to the all modes
129129
mode.Transitions = [new RepositionThemeTransition()];
130130
mode.UpdateLayout();
131-
mode.IsTabStop = true;
131+
mode.IsTabStop = false;
132132
}
133133

134134
var index = _modesHostGrid.Children.IndexOf(newMode);

src/Files.App.Controls/Omnibar/Omnibar.xaml

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -117,33 +117,28 @@
117117
<Setter Property="HorizontalContentAlignment" Value="Left" />
118118
<Setter Property="VerticalAlignment" Value="Stretch" />
119119

120-
<Setter Property="IsTabStop" Value="True" />
121-
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
122-
123120
<Setter Property="Template">
124121
<Setter.Value>
125122
<ControlTemplate TargetType="local:OmnibarMode">
126123
<Grid
127124
x:Name="PART_RootGrid"
128125
Height="{TemplateBinding Height}"
129126
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
130-
Background="{TemplateBinding Background}"
131-
TabFocusNavigation="Local">
127+
Background="{TemplateBinding Background}">
132128
<!-- Mode Button -->
133-
<Border
129+
<Button
134130
x:Name="PART_ModeButton"
135131
Width="{StaticResource OmnibarModeDefaultClickAreaWidth}"
136132
Margin="1"
137133
Background="{TemplateBinding Background}"
138134
BorderBrush="{TemplateBinding BorderBrush}"
139-
BorderThickness="{TemplateBinding BorderThickness}"
135+
BorderThickness="0"
140136
CornerRadius="{TemplateBinding CornerRadius}"
141-
IsTabStop="True"
142-
ToolTipService.ToolTip="{Binding ModeName, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
143-
UseSystemFocusVisuals="{StaticResource UseSystemFocusVisuals}">
144-
<Border.BackgroundTransition>
145-
<BrushTransition Duration="0:0:0.083" />
146-
</Border.BackgroundTransition>
137+
ToolTipService.ToolTip="{Binding ModeName, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}">
138+
<Button.Resources>
139+
<SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="{ThemeResource SubtleFillColorSecondary}" />
140+
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="{ThemeResource SubtleFillColorTertiary}" />
141+
</Button.Resources>
147142

148143
<Grid>
149144
<ContentPresenter
@@ -160,7 +155,7 @@
160155
Content="{Binding IconOnActive, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
161156
Visibility="Collapsed" />
162157
</Grid>
163-
</Border>
158+
</Button>
164159

165160
<ContentPresenter
166161
x:Name="PART_InactiveContent"
@@ -174,14 +169,9 @@
174169

175170
<VisualStateGroup x:Name="PointerStates">
176171
<VisualState x:Name="PointerNormal" />
177-
<VisualState x:Name="PointerOver">
178-
<VisualState.Setters>
179-
<Setter Target="PART_ModeButton.Background" Value="{ThemeResource SubtleFillColorSecondaryBrush}" />
180-
</VisualState.Setters>
181-
</VisualState>
172+
<VisualState x:Name="PointerOver" />
182173
<VisualState x:Name="PointerPressed">
183174
<VisualState.Setters>
184-
<Setter Target="PART_ModeButton.Background" Value="{ThemeResource SubtleFillColorTertiaryBrush}" />
185175
<Setter Target="PART_ModeButtonInactiveIconPresenter.Visibility" Value="Collapsed" />
186176
<Setter Target="PART_ModeButtonActiveIconPresenter.Visibility" Value="Visible" />
187177
</VisualState.Setters>

src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@ private void ModeButton_PointerReleased(object sender, PointerRoutedEventArgs e)
3535
GlobalHelper.WriteDebugStringForOmnibar($"The mouse pointer has been unpressed from the UI area of this Mode ({this})");
3636

3737
VisualStateManager.GoToState(this, "PointerOver", true);
38-
39-
owner.IsModeButtonPressed = true;
40-
41-
// Change the current mode
42-
owner.CurrentSelectedMode = this;
4338
}
4439

4540
private void ModeButton_PointerExited(object sender, PointerRoutedEventArgs e)
@@ -48,5 +43,14 @@ private void ModeButton_PointerExited(object sender, PointerRoutedEventArgs e)
4843

4944
VisualStateManager.GoToState(this, "PointerNormal", true);
5045
}
46+
47+
private void ModeButton_Click(object sender, RoutedEventArgs e)
48+
{
49+
if (_ownerRef is null || _ownerRef.TryGetTarget(out var owner) is false || owner.CurrentSelectedMode == this)
50+
return;
51+
52+
owner.IsModeButtonPressed = true;
53+
owner.CurrentSelectedMode = this;
54+
}
5155
}
52-
}
56+
}

src/Files.App.Controls/Omnibar/OmnibarMode.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public partial class OmnibarMode : ItemsControl
1616

1717
private WeakReference<Omnibar>? _ownerRef;
1818

19-
private Border _modeButton = null!;
19+
private Button _modeButton = null!;
2020

2121
// Constructor
2222

@@ -33,14 +33,15 @@ protected override void OnApplyTemplate()
3333
{
3434
base.OnApplyTemplate();
3535

36-
_modeButton = GetTemplateChild(TemplatePartName_ModeButton) as Border
36+
_modeButton = GetTemplateChild(TemplatePartName_ModeButton) as Button
3737
?? throw new MissingFieldException($"Could not find {TemplatePartName_ModeButton} in the given {nameof(OmnibarMode)}'s style.");
3838

3939
Loaded += OmnibarMode_Loaded;
4040
_modeButton.PointerEntered += ModeButton_PointerEntered;
4141
_modeButton.PointerPressed += ModeButton_PointerPressed;
4242
_modeButton.PointerReleased += ModeButton_PointerReleased;
4343
_modeButton.PointerExited += ModeButton_PointerExited;
44+
_modeButton.Click += ModeButton_Click;
4445

4546
GlobalHelper.WriteDebugStringForOmnibar($"The template and the events of the Omnibar Mode ({this}) have been initialized.");
4647
}

src/Files.App/UserControls/NavigationToolbar.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@
351351
x:Load="{x:Bind ViewModel.EnableOmnibar, Mode=OneWay}"
352352
CurrentSelectedModeName="{x:Bind ViewModel.OmnibarCurrentSelectedModeName, Mode=TwoWay}"
353353
IsFocused="{x:Bind ViewModel.IsOmnibarFocused, Mode=TwoWay}"
354-
LostFocus="Omnibar_LostFocus"
354+
ModeChanged="Omnibar_ModeChanged"
355355
PreviewKeyDown="Omnibar_PreviewKeyDown"
356356
QuerySubmitted="Omnibar_QuerySubmitted"
357357
TextChanged="Omnibar_TextChanged">

src/Files.App/UserControls/NavigationToolbar.xaml.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.UI.Xaml.Navigation;
1313
using Windows.AI.Actions.Hosting;
1414
using Windows.System;
15+
using Windows.UI.Core;
1516

1617
namespace Files.App.UserControls
1718
{
@@ -427,22 +428,31 @@ private void BreadcrumbBar_ItemDropDownFlyoutClosed(object sender, BreadcrumbBar
427428
e.Flyout.Items.Clear();
428429
}
429430

430-
private void Omnibar_LostFocus(object sender, RoutedEventArgs e)
431+
private void Omnibar_ModeChanged(object sender, OmnibarModeChangedEventArgs e)
431432
{
433+
// Reset the command palette text when switching modes
432434
if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode)
433-
{
434-
Omnibar.CurrentSelectedMode = OmnibarPathMode;
435435
ViewModel.OmnibarCommandPaletteModeText = string.Empty;
436-
}
437436
}
438437

439-
private void Omnibar_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
438+
private async void Omnibar_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
440439
{
441440
if (e.Key is VirtualKey.Escape)
442441
{
443442
Omnibar.IsFocused = false;
444443
(MainPageViewModel.SelectedTabItem?.TabItemContent as Control)?.Focus(FocusState.Programmatic);
445444
}
445+
else if (e.Key is VirtualKey.Tab && Omnibar.IsFocused && !InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down))
446+
{
447+
var currentSelectedMode = Omnibar.CurrentSelectedMode;
448+
Omnibar.IsFocused = false;
449+
await Task.Delay(15);
450+
451+
if (currentSelectedMode == OmnibarPathMode)
452+
BreadcrumbBar.Focus(FocusState.Keyboard);
453+
else if (currentSelectedMode == OmnibarCommandPaletteMode)
454+
OmnibarCommandPaletteMode.Focus(FocusState.Keyboard);
455+
}
446456
}
447457

448458
private void NavigationButtonOverflowFlyoutButton_LosingFocus(UIElement sender, LosingFocusEventArgs args)

0 commit comments

Comments
 (0)