From a1ea69133e5a5c04076901dce47cd54683c4ca2e Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Wed, 4 Mar 2026 15:23:55 +0100 Subject: [PATCH 7/9] doc: add VoiceOver section to macOS appendix * doc/emacs/macos.texi (VoiceOver Accessibility): New node between 'Mac / GNUstep Events' and 'GNUstep Support'. Document screen reader usage, keyboard navigation, completion announcements, ns-accessibility- enabled, and known limitations. Use @xref for cross-reference at sentence start. Correct description of ns-accessibility-enabled default: initial value is nil, set automatically at startup. --- doc/emacs/macos.texi | 77 ++++++++++++++++++++++++++++++++++++++++++++ src/nsterm.m | 10 ++++-- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/doc/emacs/macos.texi b/doc/emacs/macos.texi index 6bd334f48e..72ac3a9aa9 100644 --- a/doc/emacs/macos.texi +++ b/doc/emacs/macos.texi @@ -36,6 +36,7 @@ Support}), but we hope to improve it in the future. * Mac / GNUstep Basics:: Basic Emacs usage under GNUstep or macOS. * Mac / GNUstep Customization:: Customizations under GNUstep or macOS. * Mac / GNUstep Events:: How window system events are handled. +* VoiceOver Accessibility:: Screen reader support on macOS. * GNUstep Support:: Details on status of GNUstep support. @end menu @@ -272,6 +273,82 @@ and return the result as a string. You can also use the Lisp function services and receive the results back. Note that you may need to restart Emacs to access newly-available services. +@node VoiceOver Accessibility +@section VoiceOver Accessibility (macOS) +@cindex VoiceOver +@cindex accessibility (macOS) +@cindex screen reader (macOS) +@cindex Zoom, cursor tracking (macOS) + + When built with the Cocoa interface on macOS, Emacs exposes buffer +content, cursor position, mode lines, and interactive elements to the +macOS accessibility subsystem. This enables use with VoiceOver, +Apple's built-in screen reader, and with other assistive technology +such as macOS Zoom. + + Toggle VoiceOver with @kbd{Cmd-F5} (or via System Settings, +Accessibility, VoiceOver). When Emacs is focused, VoiceOver announces +the buffer name and current line. Standard Emacs navigation produces +speech feedback: + +@itemize @bullet +@item +Arrow keys read individual characters (left/right) or full lines +(up/down). +@item +@kbd{M-f} and @kbd{M-b} announce words. +@item +@kbd{C-n} and @kbd{C-p} read the destination line. +@item +Shift-modified movement announces selected or deselected text. +@item +@key{TAB} and @kbd{S-@key{TAB}} navigate interactive elements +(buttons, links, completion candidates) within a buffer. +@end itemize + + The @file{*Completions*} buffer announces each completion candidate +as you navigate, even while keyboard focus remains in the minibuffer. + + macOS Zoom (System Settings, Accessibility, Zoom) tracks the Emacs +cursor automatically when set to follow keyboard focus. The cursor +position is communicated via @code{UAZoomChangeFocus} and the +@code{AXBoundsForRange} accessibility attribute. + +@vindex ns-accessibility-enabled + To disable the accessibility interface entirely (for instance, to +eliminate overhead on systems where assistive technology is not in +use), set @code{ns-accessibility-enabled} to @code{nil}. Emacs +detects the presence of assistive technology at startup and sets this +variable automatically; the initial value is @code{nil}. + +@subheading Known Limitations + +@itemize @bullet +@item +Very large buffers (tens of megabytes) may cause slow initial +accessibility text extraction. Once cached, subsequent queries +are fast. +@item +Mode-line text extraction handles only character glyphs. Mode lines +using icon fonts (e.g., icon-based mode-lines) +produce incomplete accessibility text. +@item +The accessibility virtual element tree is rebuilt automatically on +window configuration changes (splits, deletions, new buffers). +@item +Right-to-left (bidi) text is exposed correctly as buffer content, +but @code{accessibilityRangeForPosition} hit-testing assumes +left-to-right glyph layout. +@item +Block-style cursors are handled correctly: character navigation +announces the character at the cursor position, not the character +before it. +@end itemize + + This support is available only on the Cocoa build. GNUstep has a +different accessibility model and is not yet supported. + + @node GNUstep Support @section GNUstep Support diff --git a/src/nsterm.m b/src/nsterm.m index e003bca5bd..705c3ece06 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -14745,9 +14745,13 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with DEFVAR_BOOL ("ns-accessibility-enabled", ns_accessibility_enabled, doc: /* Non-nil enables Zoom cursor tracking and VoiceOver support. -Emacs sets this automatically at startup when macOS Zoom is active or -any assistive technology (VoiceOver, Switch Control, etc.) is connected, -and updates it whenever that state changes. You can override manually: +Emacs detects at startup whether macOS Zoom is active or an assistive +technology (VoiceOver, Switch Control, etc.) is connected, and sets +this variable accordingly. It updates automatically when accessibility +state changes. The initial value is nil; it becomes non-nil only when +an AT is detected. + +You can override the auto-detection: (setq ns-accessibility-enabled t) ; always on (setq ns-accessibility-enabled nil) ; always off -- 2.43.0