Skip to content

Accessibility: Add screen reader support to the editor via QAccessibleTextInterface#4557

Open
sunderme with Copilot wants to merge 4 commits into
masterfrom
copilot/improve-nvda-screen-reader-support
Open

Accessibility: Add screen reader support to the editor via QAccessibleTextInterface#4557
sunderme with Copilot wants to merge 4 commits into
masterfrom
copilot/improve-nvda-screen-reader-support

Conversation

Copilot AI commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Blind and low-vision users could not use TeXstudio's editor with screen readers (NVDA, JAWS, Narrator) because the custom QEditor widget—based on QAbstractScrollArea with custom painting—exposed no accessibility tree, so AT tools had no way to read text content, track the caret, or detect changes.

New: QEditorAccessible (qeditoraccessible.h/.cpp)

Implements QAccessibleWidget + QAccessibleTextInterface for QEditor, wiring the editor into Qt's platform accessibility bridge (IAccessible2 on Windows):

  • Role/state: EditableText, reflects readOnly and selection state
  • Text content: QAccessible::Value returns the full document text; text(start, end) supports range queries
  • Cursor & selection: cursorPosition(), setCursorPosition(), selection(), setSelection() — all convert between (line, column) and absolute offsets using \n-separated line counting
  • Navigation support: textAtOffset/Before/After() with Char/Word/Line/Sentence/Paragraph boundary types via QTextBoundaryFinder
  • Hit testing: characterRect(offset) maps document coordinates to screen-space; offsetAtPoint() does the reverse
  • Factory: QEditorAccessible::factory() registered with QAccessible::installFactory() — Qt's bridge calls this to instantiate the interface on demand

Modified: qeditor.cpp/.h

  • documentOffsetFromPosition(line, col) — converts (line, column) to absolute offset (used by both the accessible interface and event firing)
  • emitCursorPositionChanged() fires QAccessibleTextCursorEvent with the current absolute offset when the caret moves
  • updateContent() fires QAccessible::ValueChanged when document content changes
  • Factory registered in QEditor::init(); events guarded by QAccessible::isActive() to avoid overhead when no AT is running
// Cursor movement notification example
if (QAccessible::isActive()) {
    const int cursorOffset = documentOffsetFromPosition(m_cursor.lineNumber(), m_cursor.columnNumber());
    QAccessible::updateAccessibility(new QAccessibleTextCursorEvent(this, cursorOffset));
}

Copilot AI added 2 commits July 17, 2026 15:52
Implement QAccessibleInterface + QAccessibleTextInterface for QEditor
so that NVDA, JAWS, Narrator and other screen readers can access the
editor content via the platform accessibility APIs.

Changes:
- New qeditoraccessible.h/cpp: QEditorAccessible class implementing
  QAccessibleWidget + QAccessibleTextInterface
  * role() returns QAccessible::EditableText
  * state() reflects read-only and selection state
  * text(QAccessible::Value) returns full document text
  * Full QAccessibleTextInterface: text(), cursorPosition(),
    selection(), characterCount(), characterRect(), offsetAtPoint(),
    textAtOffset/Before/After(), scrollToSubstring(), attributes()
  * Offset helpers: line+column <-> absolute char offset
  * Factory function registered via QAccessible::installFactory()
- qeditor.cpp:
  * Include qeditoraccessible.h and QAccessible
  * Call QAccessible::installFactory in init()
  * Add documentOffsetFromPosition() helper
  * Fire QAccessibleTextCursorEvent in emitCursorPositionChanged()
  * Fire QAccessible::ValueChanged event in updateContent()
- qeditor.h: declare documentOffsetFromPosition()
- CMakeLists.txt: add new source/header files

Closes #4556
- Remove unused viewportPos variable from characterRect()
- Clarify attributes() run-expansion logic for punctuation characters
- Remove unnecessary queryAccessibleInterface() call before firing cursor event
Copilot AI changed the title [WIP] Improve NVDA and screen reader support in the editor Accessibility: Add screen reader support to the editor via QAccessibleTextInterface Jul 17, 2026
Copilot AI requested a review from sunderme July 17, 2026 15:54
@sunderme

Copy link
Copy Markdown
Member

@copilot fix compilation error

Copilot AI commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix compilation error

Fixed in the latest commit. The methods were named textBeforeCursor / textAfterCursor but Qt5's QAccessibleTextInterface uses textBeforeOffset / textAfterOffset. Renamed both declarations in the header and definitions in the implementation file.

@sunderme
sunderme marked this pull request as ready for review July 19, 2026 16:42
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.

Accessibility: Improve NVDA and Screen Reader Support in the Editor

2 participants