Skip to content

Prototype screen reader support #4854

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

andyleejordan
Copy link
Member

@andyleejordan andyleejordan commented Jul 19, 2025

A work-in-progress that utilizes a SafeRender abstraction that relies on ANSI control codes when a screen reader is enabled. Passes tests locally, handles all basic editing movements (including revert line, forward delete, and case-changing), up/down arrow history, incremental history search (needs more testing), completions (almost coincedentally), and undo/redo (tested across characters and strings, insertions and deletions. Predictions are disabled, and Vi mode has not fixed.

Specifically tested with NVDA on Windows and VoiceOver on macOS within VS Code's integrated terminal, with shell integration loaded, and Code's screen reader optimizations enabled. Is probably not going to work in the old Windows Console.

Not yet tested with Windows PowerShell 5.1, nor multi-line input.

@andyleejordan andyleejordan force-pushed the screenreader branch 4 times, most recently from 8b8a080 to 9ba544b Compare July 23, 2025 17:56
@andyleejordan andyleejordan changed the title WIP: Prototype screen reader support Prototype screen reader support Jul 23, 2025
@andyleejordan andyleejordan marked this pull request as ready for review July 23, 2025 18:39
@andyleejordan andyleejordan requested a review from Copilot July 23, 2025 18:58
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces prototype screen reader support by implementing a SafeRender abstraction that uses ANSI control codes when screen reader mode is enabled. The changes modify rendering behavior throughout the application to provide better accessibility for screen reader users.

Key changes:

  • Introduces SafeRender method that outputs ANSI escape sequences instead of full re-rendering when screen reader support is enabled
  • Adds screen reader detection for Windows (including Narrator) and macOS VoiceOver
  • Replaces many Render() calls with SafeRender() calls across editing operations, undo/redo, history, and completion functionality

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
PSReadLine/Accessibility.cs Enhanced screen reader detection for Windows and macOS platforms
PSReadLine/Cmdlets.cs Added ScreenReader option with automatic detection as default
PSReadLine/Options.cs Added logic to disable predictions when screen reader is enabled
PSReadLine/Render.cs Implemented SafeRender method using ANSI control codes
PSReadLine/UndoRedo.cs Replaced Render calls with SafeRender for undo/redo operations
PSReadLine/PublicAPI.cs Updated Insert and Replace methods to use SafeRender
PSReadLine/BasicEditing.cs Modified editing operations to use SafeRender with appropriate ANSI codes
PSReadLine/History.cs Updated history navigation and search to use SafeRender
PSReadLine/KillYank.cs Modified kill operations to use SafeRender
PSReadLine/Completion.cs Added TODO for menu completion screen reader testing
PSReadLine/KeyBindings.cs Added TODO for WhatIsKey screen reader evaluation
PSReadLine/ReadLine.cs Added TODOs for screen reader evaluation in various render calls
PSReadLine/PlatformWindows.cs Added IsMutexPresent method for detecting Windows Narrator

try
{
using var mutex = new System.Threading.Mutex(false, name);
return Marshal.GetLastWin32Error() == 183; // ERROR_ALREADY_EXISTS
Copy link
Preview

Copilot AI Jul 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic number 183 should be extracted to a named constant for ERROR_ALREADY_EXISTS.

Suggested change
return Marshal.GetLastWin32Error() == 183; // ERROR_ALREADY_EXISTS
return Marshal.GetLastWin32Error() == ERROR_ALREADY_EXISTS;

Copilot uses AI. Check for mistakes.

Copy link
Member

@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review in progress. Need to stop here today and want to share my comments so far.

@andyleejordan andyleejordan force-pushed the screenreader branch 2 times, most recently from 175096b to d89f7ca Compare August 1, 2025 03:01
That should default to enabled when one is detected on startup,
but also allows the support to be forcibly enabled.
Borrows the "better" algorithm from Electron, with attribution.
Spawns a quick `defaults` process since in .NET
using the macOS events is difficult, but this is
quick and easy.
That algorithm doesn't work for a non-windowed app like PowerShell.
Because they'll be rendered and it's useless noise.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants