From 988b041f1fe0dc730014fdac82e746412a5afc70 Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 14:41:42 +0100 Subject: [PATCH] ns: fix overlay candidate announcement for VoiceOver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix three bugs in patch 0007: 1. Post AnnouncementRequested to NSApp, not self. VoiceOver ignores announcements from non-application elements. 2. Fix face detection: compare each line's face against the first line's face using Fequal. The previous code matched ANY non-nil face, but all Vertico lines have faces — the selected candidate is the one with a DIFFERENT face (e.g. vertico-current). 3. Post SelectedTextChanged before AnnouncementRequested to interrupt VoiceOver's current speech, matching the pattern used by the existing postFocusedCursorNotification. * src/nsterm.m (ns_ax_selected_overlay_text): Collect line boundaries, compare face of each line against first line's face via Fequal, return the distinctly-faced line. (EmacsAccessibilityBuffer postAccessibilityNotificationsForFrame:): Post SelectedTextChanged then AnnouncementRequested to NSApp. --- src/nsterm.m | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/nsterm.m b/src/nsterm.m index c7bba5b..43d30f9 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -8956,19 +8956,39 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, properties. Completion frameworks highlight the current candidate with a text face (e.g. vertico-current, icomplete-selected-match). */ + NSString *candidate NSString *candidate = ns_ax_selected_overlay_text (b, BUF_BEGV (b), BUF_ZV (b)); if (candidate) { - NSDictionary *info = @{ - NSAccessibilityAnnouncementKey: candidate, - NSAccessibilityPriorityKey: - @(NSAccessibilityPriorityHigh) + /* Post SelectedTextChanged first to interrupt VoiceOver, + then AnnouncementRequested with candidate text. + Target NSApp for announcements (Apple docs require it). */ + NSDictionary *moveInfo = @{ + @"AXTextStateChangeType": + @(ns_ax_text_state_change_selection_move), + @"AXTextChangeElement": self }; ns_ax_post_notification_with_info ( self, - NSAccessibilityAnnouncementRequestedNotification, - info); + NSAccessibilitySelectedTextChangedNotification, + moveInfo); + + candidate = [candidate + stringByTrimmingCharactersInSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if ([candidate length] > 0) + { + NSDictionary *annInfo = @{ + NSAccessibilityAnnouncementKey: candidate, + NSAccessibilityPriorityKey: + @(NSAccessibilityPriorityHigh) + }; + ns_ax_post_notification_with_info ( + NSApp, + NSAccessibilityAnnouncementRequestedNotification, + annInfo); + } } } -- 2.43.0