patches: update TESTING.txt + README.txt for 0007/0008
TESTING: sections 14 (overlay completion) + 15 (child frame completion) README: patch series listing, overlay/child frame architecture, textDidChange flag, focus restoration, new limitations
This commit is contained in:
@@ -1,14 +1,26 @@
|
|||||||
EMACS NS VOICEOVER ACCESSIBILITY PATCH
|
EMACS NS VOICEOVER ACCESSIBILITY PATCH
|
||||||
========================================
|
========================================
|
||||||
patch: 0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch
|
patch: 0001-0008 (8 patches, see PATCH SERIES below)
|
||||||
0002-doc-add-VoiceOver-accessibility-section-to-macOS-app.patch
|
|
||||||
author: Martin Sukany <martin@sukany.cz>
|
author: Martin Sukany <martin@sukany.cz>
|
||||||
files: src/nsterm.h (+119 lines)
|
files: src/nsterm.h (+124 lines)
|
||||||
src/nsterm.m (+3024 ins, -147 del, +2877 net)
|
src/nsterm.m (+3577 ins, -185 del, +3392 net)
|
||||||
doc/emacs/macos.texi (+53 lines)
|
doc/emacs/macos.texi (+53 lines)
|
||||||
etc/NEWS (+13 lines)
|
etc/NEWS (+13 lines)
|
||||||
|
|
||||||
|
|
||||||
|
PATCH SERIES
|
||||||
|
------------
|
||||||
|
|
||||||
|
0001 ns: add accessibility base classes and text extraction
|
||||||
|
0002 ns: implement buffer accessibility element (core protocol)
|
||||||
|
0003 ns: add buffer notification dispatch and mode-line element
|
||||||
|
0004 ns: add interactive span elements for Tab navigation
|
||||||
|
0005 ns: integrate accessibility with EmacsView and redisplay
|
||||||
|
0006 doc: add VoiceOver accessibility section to macOS appendix
|
||||||
|
0007 ns: announce overlay completion candidates for VoiceOver
|
||||||
|
0008 ns: announce child frame completion candidates for VoiceOver
|
||||||
|
|
||||||
|
|
||||||
OVERVIEW
|
OVERVIEW
|
||||||
--------
|
--------
|
||||||
|
|
||||||
@@ -517,6 +529,104 @@ KEY DESIGN DECISIONS
|
|||||||
bottom, even though more buffer content exists below.
|
bottom, even though more buffer content exists below.
|
||||||
|
|
||||||
|
|
||||||
|
OVERLAY COMPLETION ANNOUNCEMENTS (Patch 0007)
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
Overlay-based completion frameworks (Vertico, Icomplete, Ivy, etc.)
|
||||||
|
render candidates as overlay strings in the minibuffer. VoiceOver
|
||||||
|
does not see overlay content changes automatically. This patch
|
||||||
|
detects overlay candidate changes and announces the selected
|
||||||
|
candidate.
|
||||||
|
|
||||||
|
Detection:
|
||||||
|
ns_ax_face_is_selected(face) checks whether a face name contains
|
||||||
|
"current", "selected", or "selection" (matching vertico-current,
|
||||||
|
icomplete-selected-match, ivy-current-match, etc.). Supports
|
||||||
|
both single face symbols and face lists.
|
||||||
|
|
||||||
|
ns_ax_selected_overlay_text(b, beg, end, out_line) scans the
|
||||||
|
buffer region line by line using Fget_char_property to check
|
||||||
|
both text properties and overlay face properties.
|
||||||
|
|
||||||
|
Overlay changes are tracked independently of text changes:
|
||||||
|
BUF_OVERLAY_MODIFF is checked in an independent if-branch (not
|
||||||
|
else-if) because Vertico bumps both BUF_MODIFF (text properties)
|
||||||
|
and BUF_OVERLAY_MODIFF (overlays) in the same command cycle.
|
||||||
|
|
||||||
|
textDidChange flag:
|
||||||
|
hl-line-mode and similar packages update face properties (text
|
||||||
|
properties, not characters) on every cursor movement, bumping
|
||||||
|
BUF_MODIFF without changing BUF_CHARS_MODIFF. The original
|
||||||
|
else-if structure caused the modiff branch to fire (correctly
|
||||||
|
skipping ValueChanged) but also blocked the cursor-move branch
|
||||||
|
(SelectedTextChanged). A BOOL textDidChange flag decouples the
|
||||||
|
two branches: ValueChanged and SelectedTextChanged remain
|
||||||
|
mutually exclusive for real edits, but SelectedTextChanged fires
|
||||||
|
correctly when only text properties changed.
|
||||||
|
|
||||||
|
Zoom:
|
||||||
|
The selected candidate position is stored in overlayZoomRect /
|
||||||
|
overlayZoomActive on the parent EmacsView. draw_window_cursor
|
||||||
|
uses this rect instead of the text cursor when a candidate is
|
||||||
|
active. Cleared when BUF_CHARS_MODIFF changes (user types)
|
||||||
|
or when no candidate is found.
|
||||||
|
|
||||||
|
|
||||||
|
CHILD FRAME COMPLETION ANNOUNCEMENTS (Patch 0008)
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Completion frameworks such as Corfu, Company-box, and similar render
|
||||||
|
candidates in a child frame rather than as overlay strings. This
|
||||||
|
patch detects child frames via FRAME_PARENT_FRAME and announces
|
||||||
|
the selected candidate.
|
||||||
|
|
||||||
|
Detection:
|
||||||
|
Child frames are dispatched in postAccessibilityUpdates before
|
||||||
|
the main tree rebuild logic. FRAME_PARENT_FRAME(emacsframe)
|
||||||
|
returns non-NULL for child frames.
|
||||||
|
|
||||||
|
ns_ax_selected_child_frame_text(b, buf_obj, out_line) scans the
|
||||||
|
child frame buffer line by line, reusing ns_ax_face_is_selected
|
||||||
|
from patch 0007.
|
||||||
|
|
||||||
|
Buffer switch safety:
|
||||||
|
Fbuffer_substring_no_properties operates on current_buffer, which
|
||||||
|
may differ from the child frame buffer during ns_update_end.
|
||||||
|
The function uses record_unwind_current_buffer /
|
||||||
|
set_buffer_internal_1 to temporarily switch, with unbind_to on
|
||||||
|
all three return paths after the switch. Uses specpdl_ref (not
|
||||||
|
ptrdiff_t) for the SPECPDL_INDEX return value.
|
||||||
|
|
||||||
|
Re-entrance protection:
|
||||||
|
The accessibilityUpdating guard MUST precede the child frame
|
||||||
|
dispatch because Lisp calls in the scan function (Fget_char_property,
|
||||||
|
Fbuffer_substring_no_properties) can trigger redisplay.
|
||||||
|
BUF_MODIFF gating provides a secondary guard and prevents
|
||||||
|
redundant scans.
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- WINDOWP / BUFFERP checks for partially initialized child frames.
|
||||||
|
- Buffer size limit (10000 chars) skips non-completion child frames
|
||||||
|
(eldoc, which-key, etc.).
|
||||||
|
|
||||||
|
Focus restoration:
|
||||||
|
childFrameCompletionActive (BOOL on EmacsView) is set by the child
|
||||||
|
frame handler on the parent view. On the parent's next accessibility
|
||||||
|
cycle, FOR_EACH_FRAME checks whether any child frame is still
|
||||||
|
visible. If not, FocusedUIElementChangedNotification is posted on
|
||||||
|
the focused buffer element to restore VoiceOver character echo and
|
||||||
|
cursor tracking.
|
||||||
|
|
||||||
|
Zoom:
|
||||||
|
Direct UAZoomChangeFocus (not overlayZoomRect) because the child
|
||||||
|
frame's ns_update_end runs after the parent's draw_window_cursor,
|
||||||
|
so the last Zoom call wins.
|
||||||
|
|
||||||
|
Deduplication:
|
||||||
|
Static C string cache (lastCandidate via xstrdup/xfree) avoids
|
||||||
|
re-announcing the same candidate.
|
||||||
|
|
||||||
|
|
||||||
KNOWN LIMITATIONS
|
KNOWN LIMITATIONS
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@@ -545,6 +655,19 @@ KNOWN LIMITATIONS
|
|||||||
- No multi-frame coordination. EmacsView.accessibilityElements is
|
- No multi-frame coordination. EmacsView.accessibilityElements is
|
||||||
per-view; there is no cross-frame notification ordering.
|
per-view; there is no cross-frame notification ordering.
|
||||||
|
|
||||||
|
- Overlay completion (0007) face matching uses string containment
|
||||||
|
("current", "selected", "selection"). Custom completion frameworks
|
||||||
|
with face names not containing these substrings will not be detected.
|
||||||
|
|
||||||
|
- Child frame completion (0008) static lastBuffer pointer may become
|
||||||
|
stale if the buffer is freed and a new one allocated at the same
|
||||||
|
address. This is harmless (worst case: one missed announcement).
|
||||||
|
|
||||||
|
- Child frame window-appeared announcement: macOS automatically
|
||||||
|
announces the window title when a child frame NSWindow appears.
|
||||||
|
This cannot be suppressed without breaking VoiceOver focus tracking
|
||||||
|
or Zoom integration.
|
||||||
|
|
||||||
- GNUstep is explicitly excluded (#ifdef NS_IMPL_COCOA). GNUstep
|
- GNUstep is explicitly excluded (#ifdef NS_IMPL_COCOA). GNUstep
|
||||||
has a different accessibility model and requires separate work.
|
has a different accessibility model and requires separate work.
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,15 @@ Base: emacs master (upstream HEAD at time of test)
|
|||||||
|
|
||||||
1. Patch Application
|
1. Patch Application
|
||||||
--------------------
|
--------------------
|
||||||
PASS — All 6 patches applied cleanly via git-am:
|
PASS — All 8 patches applied cleanly via git-am:
|
||||||
0001 ns: add accessibility base classes and text extraction
|
0001 ns: add accessibility base classes and text extraction
|
||||||
0002 ns: implement buffer accessibility element (core protocol)
|
0002 ns: implement buffer accessibility element (core protocol)
|
||||||
0003 ns: add buffer notification dispatch and mode-line element
|
0003 ns: add buffer notification dispatch and mode-line element
|
||||||
0004 ns: add interactive span elements for Tab navigation
|
0004 ns: add interactive span elements for Tab navigation
|
||||||
0005 ns: integrate accessibility with EmacsView and redisplay
|
0005 ns: integrate accessibility with EmacsView and redisplay
|
||||||
0006 doc: add VoiceOver accessibility section to macOS appendix
|
0006 doc: add VoiceOver accessibility section to macOS appendix
|
||||||
|
0007 ns: announce overlay completion candidates for VoiceOver
|
||||||
|
0008 ns: announce child frame completion candidates for VoiceOver
|
||||||
|
|
||||||
No conflicts, no warnings.
|
No conflicts, no warnings.
|
||||||
|
|
||||||
@@ -111,3 +113,32 @@ PASS — Ran 1 test, 1 result as expected:
|
|||||||
- ns-accessibility-enabled is bound OK
|
- ns-accessibility-enabled is bound OK
|
||||||
- ns-accessibility-enabled defaults to t OK
|
- ns-accessibility-enabled defaults to t OK
|
||||||
(ERT 1/1 passed, 2026-02-28 11:45:55 CET)
|
(ERT 1/1 passed, 2026-02-28 11:45:55 CET)
|
||||||
|
|
||||||
|
14. VoiceOver — Overlay Completion (Patch 0007)
|
||||||
|
------------------------------------------------
|
||||||
|
PASS — Vertico minibuffer overlay completion:
|
||||||
|
- Vertico candidates announced on C-n / C-p navigation OK
|
||||||
|
- Selected candidate face detected (vertico-current) OK
|
||||||
|
- Deduplication: same candidate not re-announced OK
|
||||||
|
- Zoom tracks selected candidate in minibuffer
|
||||||
|
(overlayZoomRect / overlayZoomActive lifecycle) OK
|
||||||
|
- overlayZoomActive cleared on text input OK
|
||||||
|
- hl-line-mode compatibility: cursor movement in dired
|
||||||
|
and read-only buffers correctly announces lines
|
||||||
|
(textDidChange flag decouples modiff branch from
|
||||||
|
cursor-move branch) OK
|
||||||
|
|
||||||
|
15. VoiceOver — Child Frame Completion (Patch 0008)
|
||||||
|
----------------------------------------------------
|
||||||
|
PASS — Corfu child frame completion:
|
||||||
|
- Corfu popup candidates announced via VoiceOver OK
|
||||||
|
- Selected candidate face detected (corfu-current) OK
|
||||||
|
- Zoom tracks selected candidate in child frame
|
||||||
|
(direct UAZoomChangeFocus) OK
|
||||||
|
- No Emacs freeze (re-entrance guard before child frame
|
||||||
|
dispatch, buffer switch with unbind_to on all paths) OK
|
||||||
|
- Focus restored to parent buffer after corfu closes
|
||||||
|
(childFrameCompletionActive flag + FOR_EACH_FRAME
|
||||||
|
visibility check + FocusedUIElementChanged) OK
|
||||||
|
- Non-completion child frames skipped (10KB buffer limit) OK
|
||||||
|
- specpdl_ref type used correctly (not ptrdiff_t) OK
|
||||||
|
|||||||
Reference in New Issue
Block a user