nvda
5344d4bd - LiveText: announce large bursts via a pumped generator (#20177)

Commit
58 days ago
LiveText: announce large bursts via a pumped generator (#20177) Fixes #6291. Partially addresses #15786, #15850, #11002, and #14189. All of these describe the same general class of "NVDA stops responding during console flood" problem but also include symptoms (UIA event flooding, NVDA crashes destroying the console window, etc.) that are out of scope for this PR and were partly addressed in #14888 and #14067 anyway. Related to #2977 and #875. Most of these are already closed, but the underlying root cause (which is the main thread blocking during line announcement) was never actually addressed. Summary of the issue: When a live-text region (such as a terminal) produces a large burst of new text in a short window, NVDA's main thread blocks announcing every line sequentially, becoming unresponsive to keyboard input until the burst finishes. In some cases this lasts tens of seconds. In other (more drastic) cases, it can last so long that the user has to sign out, restart, or force-kill NVDA. Description of user facing changes: NVDA no longer freezes when large bursts of text are reported in a live region. Description of developer facing changes: LiveText._reportNewLines is no longer guaranteed to report lines synchronously. Internally, it now registers a generator with queueHandler which yields between batches of lines so the main thread can service input during long announcements. A new class attribute LiveText.MAX_LINES caps the number of lines announced per burst. We drop everything before that on the floor. When a new burst arrives while a previous one is still being announced, the previous generator is cancelled and the new burst supersedes it. Description of development approach: Live-text regions announce new text via LiveText._reportNewLines, which was invoked synchronously from the main thread's event queue. For workloads producing substantial amounts of new lines in a short window, every line traverses the full speech pipeline sequentially without yielding, which can leave the main thread unresponsive to keyboard input for tens of seconds or longer. This PR addresses the responsiveness problem at the announcement layer rather than at the diff or event-source layer, which were previously addressed by #14888 and #14067. Specifically: (1) Bursts larger than MAX_LINES are truncated to the most recent N lines. Skipping the oldest lines was chosen over skipping the newest because most flooding scenarios carry their actionable content at the end. (2) Reporting now happens via a generator registered with queueHandler.registerGeneratorObject, yielding every 5 lines. This is the same primitive previously used by speech.speakSpelling and the original sayAll. Between yields, the main thread services the event queue, which keeps NVDA responsive. (3) A handler is registered with pre_speechCanceled so that pressing control (or any other speech-cancel trigger) also cancels the in-flight generator. Perceptibly this may not cancel immediately and up to 5 lines may still be announced past the cancel, but internally the generator won't proceed past that iteration.
Author
Parents
Loading