Change:
return (toLowerCase ? text.toLowerCase() : text); } <ins> export class FocusNextCursor extends EditorAction { constructor() { super({ id: 'editor.action.focusNextCursor', label: nls.localize('mutlicursor.focusNextCursor', "Focus next cursor"), description: { description: nls.localize('mutlicursor.focusNextCursor.description', "Focuses the next cursor"), args: [], }, alias: 'Focus Next Cursor', precondition: undefined }); } public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { if (!editor.hasModel()) { return; } const viewModel = editor._getViewModel(); if (viewModel.cursorConfig.readOnly) { return; } viewModel.model.pushStackElement(); const previousCursorState = Array.from(viewModel.getCursorStates()); const firstCursor = previousCursorState.shift(); if (!firstCursor) { return; } previousCursorState.push(firstCursor); viewModel.setCursorStates(args.source, CursorChangeReason.Explicit, previousCursorState); viewModel.revealPrimaryCursor(args.source, true); announceCursorChange(previousCursorState, viewModel.getCursorStates()); } } export class FocusPreviousCursor extends EditorAction { constructor() { super({ id: 'editor.action.focusPreviousCursor', label: nls.localize('mutlicursor.focusPreviousCursor', "Focus previous cursor"), description: { description: nls.localize('mutlicursor.focusPreviousCursor.description', "Focuses the previous cursor"), args: [], }, alias: 'Focus Previous Cursor', precondition: undefined }); } public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { if (!editor.hasModel()) { return; } const viewModel = editor._getViewModel(); if (viewModel.cursorConfig.readOnly) { return; } viewModel.model.pushStackElement(); const previousCursorState = Array.from(viewModel.getCursorStates()); const firstCursor = previousCursorState.pop(); if (!firstCursor) { return; } previousCursorState.unshift(firstCursor); viewModel.setCursorStates(args.source, CursorChangeReason.Explicit, previousCursorState); viewModel.revealPrimaryCursor(args.source, true); announceCursorChange(previousCursorState, viewModel.getCursorStates()); } } </ins> registerEditorContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); registerEditorContribution(SelectionHighlighter.ID, SelectionHighlighter);

Discussion:
When a user adds multiple cursors we nicely announce the locations for each additional cursors. However the user can not check what is going on at the second / third cursor. I thought it would be nice if the user could change which one is the primary cursor using a command. That way the user could traverse each of the cursors and be able to read the line on each cursor for example. Since for screen reader reading we only respect the primary cursor. Now I am not sure if this is even possible from the implementation. Thus I am creating this issue for discussion. I am also open for ideas.
Currently, the primary cursor is always the first one, right?
Yes.
I like the suggestion, such a command ("focus next cursor") should be straight-forward to implement using editor API from an editor contrib.
Great. I like the "Focus Next Cursor" name. Maybe we also introduce "Focus Previous Cursor". I suggest no keybinding by default and then users can assign whatever they prefer. Maybe we assign this to November if it is low hanging fruit?
This feature could go well with to have clear visual feedback for when the primary cursor changes.
Thanks a lot for pushing this Once this is in insiders tomorrow I will do a push in our accessibility community for multi cursor, since I think with this it should be much more usable. So we get feedback. Did you verify if you change the focus of the cursor, does the screen reader read the new line (where the newly focused cursor is). I believe it should just work.
Verification steps: Launch nvda Set multiple cursors Use "Focus Next Cursor" / "Focus Previous Cursor" Verify that NVDA reads the text of the primary cursor and that the primary cursor rotates
Works great