Skip to content

Commit 9782b85

Browse files
Feature: Use the tab key to select the next file while renaming (#11063)
1 parent 3e490d6 commit 9782b85

File tree

7 files changed

+134
-32
lines changed

7 files changed

+134
-32
lines changed

src/Files.App/UserControls/SearchBox.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
GotFocus="{x:Bind SearchBoxViewModel.SearchRegion_GotFocus}"
7777
ItemTemplate="{StaticResource SuggestionTemplate}"
7878
ItemsSource="{x:Bind SearchBoxViewModel.Suggestions, Mode=OneWay}"
79+
KeyDown="SearchRegion_KeyDown"
7980
PlaceholderText="{helpers:ResourceString Name=NavigationToolbarSearchRegion/PlaceholderText}"
8081
QuerySubmitted="SearchRegion_QuerySubmitted"
8182
Text="{x:Bind SearchBoxViewModel.Query, Mode=TwoWay}"

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@ public SearchBoxViewModel SearchBoxViewModel
2020

2121
private void SearchRegion_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs e)
2222
=> SearchBoxViewModel.SearchRegion_TextChanged(sender, e);
23+
2324
private void SearchRegion_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs e)
2425
=> SearchBoxViewModel.SearchRegion_QuerySubmitted(sender, e);
26+
2527
private void SearchRegion_Escaped(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs e)
2628
=> SearchBoxViewModel.SearchRegion_Escaped(sender, e);
29+
30+
private void SearchRegion_KeyDown(object sender, KeyRoutedEventArgs e)
31+
=> SearchBoxViewModel.SearchRegion_KeyDown(sender, e);
2732
}
2833
}

src/Files.App/ViewModels/SearchBoxViewModel.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Collections.ObjectModel;
99
using System.Linq;
1010
using Windows.Foundation;
11+
using Windows.System;
1112

1213
namespace Files.App.ViewModels
1314
{
@@ -44,9 +45,7 @@ public void SetSuggestions(IEnumerable<SuggestionModel> suggestions)
4445

4546
var oldSuggestions = Suggestions.Except(items, suggestionComparer).ToList();
4647
foreach (var oldSuggestion in oldSuggestions)
47-
{
4848
Suggestions.Remove(oldSuggestion);
49-
}
5049

5150
var newSuggestions = items.Except(Suggestions, suggestionComparer).ToList();
5251
foreach (var newSuggestion in newSuggestions)
@@ -95,9 +94,7 @@ public void SearchRegion_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQue
9594

9695
// Limit to last 5 queries to improve performance
9796
if (oldQueries.Count > 5)
98-
{
9997
oldQueries.RemoveAt(5);
100-
}
10198
}
10299
}
103100

@@ -109,9 +106,14 @@ public void SearchRegion_Escaped(KeyboardAccelerator sender, KeyboardAccelerator
109106
public void SearchRegion_GotFocus(object sender, RoutedEventArgs e)
110107
{
111108
if (string.IsNullOrWhiteSpace(query))
112-
{
113109
AddRecentQueries();
114-
}
110+
}
111+
112+
public void SearchRegion_KeyDown(object sender, KeyRoutedEventArgs e)
113+
{
114+
e.Handled = e.Key is VirtualKey.Left ||
115+
e.Key is VirtualKey.Right ||
116+
((e.Key is VirtualKey.Up || e.Key is VirtualKey.Down) && Suggestions.Count == 0);
115117
}
116118

117119
public void AddRecentQueries()

src/Files.App/Views/LayoutModes/ColumnViewBase.xaml.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ protected override void ItemManipulationModel_FocusSelectedItemsInvoked(object?
9191

9292
protected override void ItemManipulationModel_AddSelectedItemInvoked(object? sender, ListedItem e)
9393
{
94+
if (NextRenameIndex != 0 && TryStartRenameNextItem(e))
95+
return;
96+
9497
FileList?.SelectedItems.Add(e);
9598
}
9699

@@ -369,7 +372,7 @@ private void HandleRightClick(object sender, HoldingRoutedEventArgs e)
369372
ItemManipulationModel.SetSelectedItem(objectPressed);
370373
}
371374

372-
private void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
375+
private async void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
373376
{
374377
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
375378
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
@@ -399,7 +402,7 @@ private void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
399402
if (FileList.ContainerFromItem(RenamingItem) is ListViewItem listViewItem
400403
&& listViewItem.FindDescendant("ListViewTextBoxItemName") is TextBox textBox)
401404
{
402-
CommitRename(textBox);
405+
await CommitRename(textBox);
403406
}
404407
}
405408
if (item is not null && item.PrimaryItemAttribute == StorageItemTypes.Folder &&

src/Files.App/Views/LayoutModes/DetailsLayoutBrowser.xaml.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public sealed partial class DetailsLayoutBrowser : StandardViewBase
3434

3535
private InputCursor resizeCursor = InputCursor.CreateFromCoreCursor(new CoreCursor(CoreCursorType.SizeWestEast, 1));
3636

37+
private ListedItem? _nextItemToSelect;
38+
3739
protected override uint IconSize => currentIconSize;
3840

3941
protected override ListViewBase ListViewBase => FileList;
@@ -95,8 +97,13 @@ protected override void ItemManipulationModel_FocusSelectedItemsInvoked(object?
9597

9698
protected override void ItemManipulationModel_AddSelectedItemInvoked(object? sender, ListedItem e)
9799
{
98-
if (FileList?.Items.Contains(e) ?? false)
99-
FileList.SelectedItems.Add(e);
100+
if (NextRenameIndex != 0)
101+
{
102+
_nextItemToSelect = e;
103+
FileList.LayoutUpdated += FileList_LayoutUpdated;
104+
}
105+
else if (FileList?.Items.Contains(e) ?? false)
106+
FileList!.SelectedItems.Add(e);
100107
}
101108

102109
protected override void ItemManipulationModel_RemoveSelectedItemInvoked(object? sender, ListedItem e)
@@ -173,6 +180,13 @@ protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
173180
ParentShellPageInstance.FilesystemViewModel.PageTypeUpdated -= FilesystemViewModel_PageTypeUpdated;
174181
}
175182

183+
private void FileList_LayoutUpdated(object? sender, object e)
184+
{
185+
FileList.LayoutUpdated -= FileList_LayoutUpdated;
186+
TryStartRenameNextItem(_nextItemToSelect!);
187+
_nextItemToSelect = null;
188+
}
189+
176190
private void FolderSettings_SortOptionPreferenceUpdated(object? sender, SortOption e)
177191
{
178192
UpdateSortIndicator();
@@ -401,7 +415,7 @@ private async void ReloadItemIcons()
401415
}
402416
}
403417

404-
private void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
418+
private async void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
405419
{
406420
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
407421
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
@@ -435,7 +449,7 @@ private void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
435449
if (listViewItem is not null)
436450
{
437451
var textBox = listViewItem.FindDescendant("ItemNameTextBox") as TextBox;
438-
CommitRename(textBox);
452+
await CommitRename(textBox);
439453
}
440454
}
441455
}

src/Files.App/Views/LayoutModes/GridViewBrowser.xaml.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ protected override void ItemManipulationModel_FocusSelectedItemsInvoked(object?
7878

7979
protected override void ItemManipulationModel_AddSelectedItemInvoked(object? sender, ListedItem e)
8080
{
81-
if (FileList?.Items.Contains(e) ?? false)
82-
FileList.SelectedItems.Add(e);
81+
if ((NextRenameIndex != 0 && TryStartRenameNextItem(e)) || (!FileList?.Items.Contains(e) ?? true))
82+
return;
83+
84+
FileList!.SelectedItems.Add(e);
8385
}
8486

8587
protected override void ItemManipulationModel_RemoveSelectedItemInvoked(object? sender, ListedItem e)
@@ -374,7 +376,7 @@ private async void ReloadSelectedItemsIcon()
374376
}
375377
}
376378

377-
private void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
379+
private async void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
378380
{
379381
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
380382
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
@@ -409,12 +411,12 @@ private void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
409411
{
410412
Popup popup = gridViewItem.FindDescendant("EditPopup") as Popup;
411413
var textBox = popup.Child as TextBox;
412-
CommitRename(textBox);
414+
await CommitRename(textBox);
413415
}
414416
else
415417
{
416418
var textBox = gridViewItem.FindDescendant("TileViewTextBoxItemName") as TextBox;
417-
CommitRename(textBox);
419+
await CommitRename(textBox);
418420
}
419421
}
420422
}

src/Files.App/Views/LayoutModes/StandardLayoutMode.cs

Lines changed: 90 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,19 @@
1313
using System;
1414
using System.Collections.Generic;
1515
using System.Linq;
16+
using System.Runtime.InteropServices;
17+
using System.Threading.Tasks;
1618
using Windows.System;
1719
using Windows.UI.Core;
1820

1921
namespace Files.App
2022
{
2123
public abstract class StandardViewBase : BaseLayout
2224
{
25+
private const int KEY_DOWN_MASK = 0x8000;
26+
27+
protected int NextRenameIndex = 0;
28+
2329
protected abstract ListViewBase ListViewBase
2430
{
2531
get;
@@ -130,6 +136,7 @@ protected virtual void ZoomIn(object? sender, GroupOption option)
130136
protected virtual async void FileList_SelectionChanged(object sender, SelectionChangedEventArgs e)
131137
{
132138
SelectedItems = ListViewBase.SelectedItems.Cast<ListedItem>().Where(x => x is not null).ToList();
139+
133140
if (SelectedItems.Count == 1 && App.AppModel.IsQuickLookAvailable)
134141
await QuickLookHelpers.ToggleQuickLook(ParentShellPageInstance, true);
135142
}
@@ -167,48 +174,113 @@ protected virtual void StartRenameItem(string itemNameTextBox)
167174
textBox.KeyDown += RenameTextBox_KeyDown;
168175

169176
int selectedTextLength = SelectedItem.Name.Length;
177+
170178
if (!SelectedItem.IsShortcut && UserSettingsService.FoldersSettingsService.ShowFileExtensions)
171179
selectedTextLength -= extensionLength;
180+
172181
textBox.Select(0, selectedTextLength);
173182
IsRenamingItem = true;
174183
}
175184

176185
protected abstract void EndRename(TextBox textBox);
177186

178-
protected virtual async void CommitRename(TextBox textBox)
187+
protected virtual async Task CommitRename(TextBox textBox)
179188
{
180189
EndRename(textBox);
181190
string newItemName = textBox.Text.Trim().TrimEnd('.');
182191
await UIFilesystemHelpers.RenameFileItemAsync(RenamingItem, newItemName, ParentShellPageInstance);
183192
}
184193

185-
protected virtual void RenameTextBox_LostFocus(object sender, RoutedEventArgs e)
194+
protected virtual async void RenameTextBox_LostFocus(object sender, RoutedEventArgs e)
186195
{
187196
// This check allows the user to use the text box context menu without ending the rename
188197
if (!(FocusManager.GetFocusedElement(XamlRoot) is AppBarButton or Popup))
189198
{
190199
TextBox textBox = (TextBox)e.OriginalSource;
191-
CommitRename(textBox);
200+
await CommitRename(textBox);
192201
}
193202
}
194203

195-
protected void RenameTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
204+
protected async void RenameTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
196205
{
197-
if (e.Key == VirtualKey.Escape)
206+
var textBox = (TextBox)sender;
207+
switch (e.Key)
198208
{
199-
TextBox textBox = (TextBox)sender;
200-
textBox.LostFocus -= RenameTextBox_LostFocus;
201-
textBox.Text = OldItemName;
202-
EndRename(textBox);
203-
e.Handled = true;
209+
case VirtualKey.Escape:
210+
textBox.LostFocus -= RenameTextBox_LostFocus;
211+
textBox.Text = OldItemName;
212+
EndRename(textBox);
213+
e.Handled = true;
214+
break;
215+
case VirtualKey.Enter:
216+
textBox.LostFocus -= RenameTextBox_LostFocus;
217+
await CommitRename(textBox);
218+
e.Handled = true;
219+
break;
220+
case VirtualKey.Up:
221+
textBox.SelectionStart = 0;
222+
e.Handled = true;
223+
break;
224+
case VirtualKey.Down:
225+
textBox.SelectionStart = textBox.Text.Length;
226+
e.Handled = true;
227+
break;
228+
case VirtualKey.Left:
229+
e.Handled = textBox.SelectionStart == 0;
230+
break;
231+
case VirtualKey.Right:
232+
e.Handled = (textBox.SelectionStart + textBox.SelectionLength) == textBox.Text.Length;
233+
break;
234+
case VirtualKey.Tab:
235+
textBox.LostFocus -= RenameTextBox_LostFocus;
236+
237+
var isShiftPressed = (GetKeyState((int)VirtualKey.Shift) & KEY_DOWN_MASK) != 0;
238+
NextRenameIndex = isShiftPressed ? -1 : 1;
239+
240+
if (textBox.Text != OldItemName)
241+
{
242+
await CommitRename(textBox);
243+
}
244+
else
245+
{
246+
var newIndex = ListViewBase.SelectedIndex + NextRenameIndex;
247+
NextRenameIndex = 0;
248+
EndRename(textBox);
249+
250+
if
251+
(
252+
newIndex >= 0 &&
253+
newIndex < ListViewBase.Items.Count
254+
)
255+
{
256+
ListViewBase.SelectedIndex = newIndex;
257+
StartRenameItem();
258+
}
259+
}
260+
261+
e.Handled = true;
262+
break;
204263
}
205-
else if (e.Key == VirtualKey.Enter)
264+
}
265+
266+
protected bool TryStartRenameNextItem(ListedItem item)
267+
{
268+
var nextItemIndex = ListViewBase.Items.IndexOf(item) + NextRenameIndex;
269+
NextRenameIndex = 0;
270+
271+
if
272+
(
273+
nextItemIndex >= 0 &&
274+
nextItemIndex < ListViewBase.Items.Count
275+
)
206276
{
207-
TextBox textBox = (TextBox)sender;
208-
textBox.LostFocus -= RenameTextBox_LostFocus;
209-
CommitRename(textBox);
210-
e.Handled = true;
277+
ListViewBase.SelectedIndex = nextItemIndex;
278+
StartRenameItem();
279+
280+
return true;
211281
}
282+
283+
return false;
212284
}
213285

214286
protected override void Page_CharacterReceived(UIElement sender, CharacterReceivedRoutedEventArgs args)
@@ -237,5 +309,8 @@ public override void Dispose()
237309
UnhookEvents();
238310
CommandsViewModel?.Dispose();
239311
}
312+
313+
[DllImport("User32.dll")]
314+
private extern static short GetKeyState(int n);
240315
}
241316
}

0 commit comments

Comments
 (0)