Skip to content

Commit 7e2a93a

Browse files
Implement keyboard navigation between list find/filter matches (microsoft#180078)
* Implement keyboard navigation between list filter matches * support alt navigation to navigate to any list element --------- Co-authored-by: João Moreno <[email protected]>
1 parent bd2ec9f commit 7e2a93a

File tree

2 files changed

+68
-8
lines changed

2 files changed

+68
-8
lines changed

src/vs/base/browser/ui/tree/abstractTree.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { IDragAndDropData } from 'vs/base/browser/dnd';
7-
import { $, append, clearNode, createStyleSheet, getWindow, h, hasParentWithClass, isActiveElement } from 'vs/base/browser/dom';
7+
import { $, append, clearNode, createStyleSheet, getWindow, h, hasParentWithClass, isActiveElement, isKeyboardEvent } from 'vs/base/browser/dom';
88
import { DomEmitter } from 'vs/base/browser/event';
99
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
1010
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
@@ -1148,7 +1148,7 @@ class FindController<T, TFilterData> implements IDisposable {
11481148
}
11491149

11501150
shouldAllowFocus(node: ITreeNode<T, TFilterData>): boolean {
1151-
if (!this.widget || !this.pattern || this._mode === TreeFindMode.Filter) {
1151+
if (!this.widget || !this.pattern) {
11521152
return true;
11531153
}
11541154

@@ -2391,27 +2391,27 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
23912391
this.view.setFocus(indexes, browserEvent, true);
23922392
}
23932393

2394-
focusNext(n = 1, loop = false, browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
2394+
focusNext(n = 1, loop = false, browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {
23952395
this.view.focusNext(n, loop, browserEvent, filter);
23962396
}
23972397

2398-
focusPrevious(n = 1, loop = false, browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
2398+
focusPrevious(n = 1, loop = false, browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {
23992399
this.view.focusPrevious(n, loop, browserEvent, filter);
24002400
}
24012401

2402-
focusNextPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): Promise<void> {
2402+
focusNextPage(browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): Promise<void> {
24032403
return this.view.focusNextPage(browserEvent, filter);
24042404
}
24052405

2406-
focusPreviousPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): Promise<void> {
2406+
focusPreviousPage(browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): Promise<void> {
24072407
return this.view.focusPreviousPage(browserEvent, filter);
24082408
}
24092409

2410-
focusLast(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
2410+
focusLast(browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {
24112411
this.view.focusLast(browserEvent, filter);
24122412
}
24132413

2414-
focusFirst(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
2414+
focusFirst(browserEvent?: UIEvent, filter = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {
24152415
this.view.focusFirst(browserEvent, filter);
24162416
}
24172417

src/vs/workbench/browser/actions/listCommands.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,40 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
102102
}
103103
});
104104

105+
KeybindingsRegistry.registerCommandAndKeybindingRule({
106+
id: 'list.focusAnyDown',
107+
weight: KeybindingWeight.WorkbenchContrib,
108+
when: WorkbenchListFocusContextKey,
109+
primary: KeyMod.Alt | KeyCode.DownArrow,
110+
mac: {
111+
primary: KeyMod.Alt | KeyCode.DownArrow,
112+
secondary: [KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyN]
113+
},
114+
handler: (accessor, arg2) => {
115+
navigate(accessor.get(IListService).lastFocusedList, async widget => {
116+
const fakeKeyboardEvent = new KeyboardEvent('keydown', { altKey: true });
117+
await widget.focusNext(typeof arg2 === 'number' ? arg2 : 1, false, fakeKeyboardEvent);
118+
});
119+
}
120+
});
121+
122+
KeybindingsRegistry.registerCommandAndKeybindingRule({
123+
id: 'list.focusAnyUp',
124+
weight: KeybindingWeight.WorkbenchContrib,
125+
when: WorkbenchListFocusContextKey,
126+
primary: KeyMod.Alt | KeyCode.UpArrow,
127+
mac: {
128+
primary: KeyMod.Alt | KeyCode.UpArrow,
129+
secondary: [KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyP]
130+
},
131+
handler: (accessor, arg2) => {
132+
navigate(accessor.get(IListService).lastFocusedList, async widget => {
133+
const fakeKeyboardEvent = new KeyboardEvent('keydown', { altKey: true });
134+
await widget.focusPrevious(typeof arg2 === 'number' ? arg2 : 1, false, fakeKeyboardEvent);
135+
});
136+
}
137+
});
138+
105139
KeybindingsRegistry.registerCommandAndKeybindingRule({
106140
id: 'list.focusPageDown',
107141
weight: KeybindingWeight.WorkbenchContrib,
@@ -154,6 +188,32 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
154188
}
155189
});
156190

191+
KeybindingsRegistry.registerCommandAndKeybindingRule({
192+
id: 'list.focusAnyFirst',
193+
weight: KeybindingWeight.WorkbenchContrib,
194+
when: WorkbenchListFocusContextKey,
195+
primary: KeyMod.Alt | KeyCode.Home,
196+
handler: (accessor) => {
197+
navigate(accessor.get(IListService).lastFocusedList, async widget => {
198+
const fakeKeyboardEvent = new KeyboardEvent('keydown', { altKey: true });
199+
await widget.focusFirst(fakeKeyboardEvent);
200+
});
201+
}
202+
});
203+
204+
KeybindingsRegistry.registerCommandAndKeybindingRule({
205+
id: 'list.focusAnyLast',
206+
weight: KeybindingWeight.WorkbenchContrib,
207+
when: WorkbenchListFocusContextKey,
208+
primary: KeyMod.Alt | KeyCode.End,
209+
handler: (accessor) => {
210+
navigate(accessor.get(IListService).lastFocusedList, async widget => {
211+
const fakeKeyboardEvent = new KeyboardEvent('keydown', { altKey: true });
212+
await widget.focusLast(fakeKeyboardEvent);
213+
});
214+
}
215+
});
216+
157217
function expandMultiSelection(focused: WorkbenchListWidget, previousFocus: unknown): void {
158218

159219
// List

0 commit comments

Comments
 (0)