Skip to content

Commit 2987f34

Browse files
committed
Improved accessibility with keyboard
1 parent c8ebd5c commit 2987f34

File tree

7 files changed

+134
-39
lines changed

7 files changed

+134
-39
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
namespace Files.App.Controls
5+
{
6+
public record class OmnibarQuerySubmittedEventArgs(OmnibarMode Mode, object? Item, string Text);
7+
8+
public record class OmnibarSuggestionChosenEventArgs(OmnibarMode Mode, object SelectedItem);
9+
10+
public record class OmnibarTextChangedEventArgs(OmnibarMode Mode, OmnibarTextChangeReason Reason);
11+
}

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

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

4+
using Microsoft.UI.Xaml.Input;
45
using Windows.System;
56

67
namespace Files.App.Controls
@@ -40,45 +41,75 @@ private void AutoSuggestBox_LostFocus(object sender, RoutedEventArgs e)
4041
TryToggleIsSuggestionsPopupOpen(false);
4142
}
4243

43-
private void AutoSuggestBox_KeyDown(object sender, Microsoft.UI.Xaml.Input.KeyRoutedEventArgs e)
44+
private void AutoSuggestBox_KeyDown(object sender, KeyRoutedEventArgs e)
4445
{
4546
if (e.Key is VirtualKey.Enter)
4647
{
4748
e.Handled = true;
4849

49-
// TODO
50+
SubmitQuery(_textBoxSuggestionsPopup.IsOpen && _textBoxSuggestionsListView.SelectedIndex is not -1 ? _textBoxSuggestionsListView.SelectedItem : null);
5051
}
5152
else if ((e.Key == VirtualKey.Up || e.Key == VirtualKey.Down) && _textBoxSuggestionsPopup.IsOpen)
5253
{
5354
e.Handled = true;
5455

55-
// TODO
56+
var currentIndex = _textBoxSuggestionsListView.SelectedIndex;
57+
var nextIndex = currentIndex;
58+
var suggestionsCount = _textBoxSuggestionsListView.Items.Count;
59+
60+
if (e.Key is VirtualKey.Up)
61+
{
62+
nextIndex--;
63+
}
64+
else if (e.Key is VirtualKey.Down)
65+
{
66+
nextIndex++;
67+
}
68+
69+
if (0 > nextIndex || nextIndex >= suggestionsCount)
70+
{
71+
RevertTextToUserInput();
72+
}
73+
else
74+
{
75+
_textBoxSuggestionsListView.SelectedIndex = nextIndex;
76+
77+
ChooseSuggestionItem(_textBoxSuggestionsListView.SelectedItem);
78+
}
5679
}
5780
else if (e.Key == VirtualKey.Escape && _textBoxSuggestionsPopup.IsOpen)
5881
{
5982
e.Handled = true;
6083

61-
// TODO
84+
RevertTextToUserInput();
85+
_textBoxSuggestionsPopup.IsOpen = false;
6286
}
6387
else
6488
{
65-
// TODO
89+
_textChangeReason = OmnibarTextChangeReason.UserInput;
6690
}
6791
}
6892

6993
private void AutoSuggestBox_TextChanged(object sender, TextChangedEventArgs e)
7094
{
71-
// After a suggestion item was chosen, text will be changed but we don't want to show suggestions again
72-
if (_suggestionWasClicked)
95+
CurrentSelectedMode!.Text = _textBox.Text;
96+
97+
// UpdateSuggestionListView();
98+
99+
if (_textChangeReason is not OmnibarTextChangeReason.SuggestionChosen and
100+
not OmnibarTextChangeReason.ProgrammaticChange)
73101
{
74-
_suggestionWasClicked = false;
75-
return;
102+
_textChangeReason = OmnibarTextChangeReason.UserInput;
103+
_userInput = _textBox.Text;
76104
}
77105

78-
TryToggleIsSuggestionsPopupOpen(true);
106+
TextChanged?.Invoke(this, new(CurrentSelectedMode, _textChangeReason));
107+
108+
// Reset
109+
_textChangeReason = OmnibarTextChangeReason.None;
79110
}
80111

81-
private void AutoSuggestBoxSuggestionsPopup_GettingFocus(UIElement sender, Microsoft.UI.Xaml.Input.GettingFocusEventArgs args)
112+
private void AutoSuggestBoxSuggestionsPopup_GettingFocus(UIElement sender, GettingFocusEventArgs args)
82113
{
83114
args.TryCancel();
84115
}
@@ -88,21 +119,8 @@ private void AutoSuggestBoxSuggestionsListView_ItemClick(object sender, ItemClic
88119
if (CurrentSelectedMode is null)
89120
return;
90121

91-
// Get the text to put into the text box from the chosen suggestion item
92-
if (e.ClickedItem is string text)
93-
{
94-
CurrentSelectedMode.Text = text;
95-
}
96-
else
97-
{
98-
CurrentSelectedMode.Text = CurrentSelectedMode.DisplayMemberPath is null
99-
? e.ClickedItem.ToString()
100-
: e.ClickedItem.GetType().GetProperty(CurrentSelectedMode.DisplayMemberPath)?.GetValue(e.ClickedItem)?.ToString();
101-
}
102-
103-
TryToggleIsSuggestionsPopupOpen(false);
104-
105-
_suggestionWasClicked = true;
122+
ChooseSuggestionItem(e.ClickedItem);
123+
SubmitQuery(e.ClickedItem);
106124
}
107125
}
108126
}

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

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.UI.Xaml.Markup;
66
using Microsoft.UI.Xaml.Media.Animation;
77
using Windows.Foundation;
8+
using static System.Net.Mime.MediaTypeNames;
89

910
namespace Files.App.Controls
1011
{
@@ -29,11 +30,14 @@ public partial class Omnibar : Control
2930
private ListView _textBoxSuggestionsListView = null!;
3031

3132
private bool _isFocused;
32-
private bool _suggestionWasClicked;
33+
private string _userInput = string.Empty;
34+
private OmnibarTextChangeReason _textChangeReason = OmnibarTextChangeReason.None;
3335

3436
// Events
3537

3638
public event TypedEventHandler<Omnibar, OmnibarQuerySubmittedEventArgs>? QuerySubmitted;
39+
public event TypedEventHandler<Omnibar, OmnibarSuggestionChosenEventArgs>? SuggestionChosen;
40+
public event TypedEventHandler<Omnibar, OmnibarTextChangedEventArgs>? TextChanged;
3741

3842
// Constructor
3943

@@ -184,5 +188,59 @@ public bool TryToggleIsSuggestionsPopupOpen(bool wantToOpen)
184188

185189
return false;
186190
}
191+
192+
public void ChooseSuggestionItem(object obj)
193+
{
194+
if (CurrentSelectedMode is null)
195+
return;
196+
197+
if (CurrentSelectedMode.UpdateTextOnSelect)
198+
{
199+
_textChangeReason = OmnibarTextChangeReason.SuggestionChosen;
200+
CurrentSelectedMode.Text = GetObjectText(obj);
201+
}
202+
203+
SuggestionChosen?.Invoke(this, new(CurrentSelectedMode, obj));
204+
205+
// Move the cursor to the end of the TextBox
206+
_textBox?.Select(_textBox.Text.Length, 0);
207+
}
208+
209+
private void SubmitQuery(object? item)
210+
{
211+
if (CurrentSelectedMode is null)
212+
return;
213+
214+
QuerySubmitted?.Invoke(this, new OmnibarQuerySubmittedEventArgs(CurrentSelectedMode, item, _textBox.Text));
215+
216+
_textBoxSuggestionsPopup.IsOpen = false;
217+
}
218+
219+
private string GetObjectText(object obj)
220+
{
221+
if (CurrentSelectedMode is null)
222+
return string.Empty;
223+
224+
// Get the text to put into the text box from the chosen suggestion item
225+
return obj is string text
226+
? text
227+
: CurrentSelectedMode.DisplayMemberPath is null
228+
? obj.ToString() ?? string.Empty
229+
: obj.GetType().GetProperty(CurrentSelectedMode.DisplayMemberPath)?.GetValue(obj)?.ToString() ?? string.Empty;
230+
}
231+
232+
private void RevertTextToUserInput()
233+
{
234+
if (CurrentSelectedMode is null)
235+
return;
236+
237+
_textBoxSuggestionsListView.SelectedIndex = -1;
238+
_textChangeReason = OmnibarTextChangeReason.ProgrammaticChange;
239+
240+
CurrentSelectedMode.Text = _userInput ?? "";
241+
242+
// Move the cursor to the end of the TextBox
243+
_textBox?.Select(_textBox.Text.Length, 0);
244+
}
187245
}
188246
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
IsItemClickEnabled="True"
9898
ItemTemplate="{Binding CurrentSelectedMode.SuggestionItemTemplate, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
9999
ItemsSource="{Binding CurrentSelectedMode.SuggestionItemsSource, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
100-
SelectionMode="None">
100+
SelectionMode="Single">
101101
<ListView.ItemContainerTransitions />
102102
</ListView>
103103
</Border>

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

Lines changed: 0 additions & 11 deletions
This file was deleted.

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,8 @@ public partial class OmnibarMode
3636

3737
[GeneratedDependencyProperty]
3838
public partial string? DisplayMemberPath { get; set; }
39+
40+
[GeneratedDependencyProperty(DefaultValue = true)]
41+
public partial bool UpdateTextOnSelect { get; set; }
3942
}
4043
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
namespace Files.App.Controls
5+
{
6+
public enum OmnibarTextChangeReason
7+
{
8+
UserInput,
9+
10+
SuggestionChosen,
11+
12+
ProgrammaticChange,
13+
14+
None,
15+
}
16+
}

0 commit comments

Comments
 (0)