From ebf611bf1928c0468500853af96cabd0e6458cf2 Mon Sep 17 00:00:00 2001 From: Daneel Date: Thu, 26 Feb 2026 09:23:39 +0100 Subject: [PATCH] v13.3: restore typing echo + add full text protocol on EmacsView MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Key changes: - Typing echo notifications back in ns_draw_window_cursor (on EmacsView, synchronous with cursor draw — this is how v9 did it and it worked) - Rich userInfo: AXTextEditType=3, AXTextChangeValues with actual char - SelectedTextChangedNotification on every cursor draw - Full text protocol on EmacsView: accessibilityNumberOfCharacters, accessibilitySelectedText, accessibilityInsertionPointLineNumber, accessibilityVisibleCharacterRange, accessibilityLineForIndex:, accessibilityRangeForLine:, accessibilityAttributedStringForRange: - accessibilityAttributedStringForRange: on EmacsAccessibilityBuffer too - Virtual tree kept for VoiceOver window/buffer detection --- ...oundsForRange-for-macOS-Zoom-cursor-.patch | 155 +++++++++++++++++- 1 file changed, 148 insertions(+), 7 deletions(-) diff --git a/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch b/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch index c2c0b1c..bbc123c 100644 --- a/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch +++ b/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch @@ -2,7 +2,7 @@ From: Martin Sukany Date: Wed, 26 Feb 2026 00:00:00 +0100 Subject: [PATCH] ns: add macOS Zoom cursor tracking and VoiceOver accessibility -Dual accessibility: UAZoomChangeFocus + virtual element tree. +Dual accessibility: UAZoomChangeFocus + virtual element tree + typing echo. MRC compatible (unsafe_unretained, proper retain/release). --- --- a/src/nsterm.h 2026-02-26 08:46:18.118172281 +0100 @@ -69,7 +69,7 @@ MRC compatible (unsafe_unretained, proper retain/release). --- a/src/nsterm.m 2026-02-26 08:46:18.124172384 +0100 -+++ b/src/nsterm.m 2026-02-26 09:02:44.734005575 +0100 ++++ b/src/nsterm.m 2026-02-26 09:23:14.570493387 +0100 @@ -1104,6 +1104,11 @@ unblock_input (); @@ -82,7 +82,7 @@ MRC compatible (unsafe_unretained, proper retain/release). } static void -@@ -3232,6 +3237,38 @@ +@@ -3232,6 +3237,75 @@ /* Prevent the cursor from being drawn outside the text area. */ r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); @@ -98,6 +98,43 @@ MRC compatible (unsafe_unretained, proper retain/release). + /* Store cursor rect for accessibilityBoundsForRange: queries. */ + view->lastAccessibilityCursorRect = r; + ++ struct buffer *curbuf ++ = XBUFFER (XWINDOW (f->selected_window)->contents); ++ ++ if (curbuf && BUF_MODIFF (curbuf) != view->lastAccessibilityModiff) ++ { ++ /* Buffer content changed — typing echo. Post ValueChanged ++ with rich userInfo on the VIEW so VoiceOver can speak. ++ kAXTextStateChangeTypeEdit = 1, kAXTextEditTypeTyping = 3. */ ++ view->lastAccessibilityModiff = BUF_MODIFF (curbuf); ++ ++ NSString *changedText = @""; ++ ptrdiff_t pt = BUF_PT (curbuf); ++ if (pt > BUF_BEGV (curbuf)) ++ { ++ NSRange charRange = NSMakeRange ( ++ (NSUInteger)(pt - BUF_BEGV (curbuf) - 1), 1); ++ changedText = [view accessibilityStringForRange:charRange]; ++ if (!changedText) ++ changedText = @""; ++ } ++ ++ NSDictionary *change = @{ ++ @"AXTextEditType": @3, ++ @"AXTextChangeValue": changedText ++ }; ++ NSDictionary *userInfo = @{ ++ @"AXTextStateChangeType": @1, ++ @"AXTextChangeValues": @[change] ++ }; ++ NSAccessibilityPostNotificationWithUserInfo ( ++ view, NSAccessibilityValueChangedNotification, userInfo); ++ } ++ ++ /* Always notify cursor movement. */ ++ NSAccessibilityPostNotification ( ++ view, NSAccessibilitySelectedTextChangedNotification); ++ + /* Tell macOS Zoom where the cursor is. UAZoomChangeFocus() + expects top-left origin (CG coordinate space). */ + if (UAZoomEnabled ()) @@ -121,7 +158,7 @@ MRC compatible (unsafe_unretained, proper retain/release). ns_focus (f, NULL, 0); NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; -@@ -6849,6 +6886,631 @@ +@@ -6849,6 +6923,637 @@ /* ========================================================================== @@ -550,6 +587,12 @@ MRC compatible (unsafe_unretained, proper retain/release). + return [text substringWithRange:range]; +} + ++- (NSAttributedString *)accessibilityAttributedStringForRange:(NSRange)range ++{ ++ NSString *str = [self accessibilityStringForRange:range]; ++ return [[[NSAttributedString alloc] initWithString:str] autorelease]; ++} ++ +- (NSInteger)accessibilityLineForIndex:(NSInteger)index +{ + struct window *w = self.emacsWindow; @@ -753,7 +796,7 @@ MRC compatible (unsafe_unretained, proper retain/release). EmacsView implementation ========================================================================== */ -@@ -6889,6 +7551,7 @@ +@@ -6889,6 +7594,7 @@ [layer release]; #endif @@ -761,7 +804,7 @@ MRC compatible (unsafe_unretained, proper retain/release). [[self menu] release]; [super dealloc]; } -@@ -9474,6 +10137,293 @@ +@@ -9474,6 +10180,391 @@ return fs_state; } @@ -1017,6 +1060,104 @@ MRC compatible (unsafe_unretained, proper retain/release). + return [NSString stringWithLispString:str]; +} + ++- (NSInteger)accessibilityNumberOfCharacters ++{ ++ if (!emacsframe) ++ return 0; ++ struct buffer *curbuf ++ = XBUFFER (XWINDOW (emacsframe->selected_window)->contents); ++ if (!curbuf) ++ return 0; ++ ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf); ++ return (NSInteger) MIN (range, 10000); ++} ++ ++- (NSString *)accessibilitySelectedText ++{ ++ if (!emacsframe) ++ return @""; ++ struct buffer *curbuf ++ = XBUFFER (XWINDOW (emacsframe->selected_window)->contents); ++ if (!curbuf || NILP (BVAR (curbuf, mark_active))) ++ return @""; ++ return @""; ++} ++ ++- (NSInteger)accessibilityInsertionPointLineNumber ++{ ++ if (!emacsframe) ++ return 0; ++ struct window *w = XWINDOW (emacsframe->selected_window); ++ if (!w) ++ return 0; ++ return (NSInteger) (w->cursor.vpos); ++} ++ ++- (NSRange)accessibilityVisibleCharacterRange ++{ ++ if (!emacsframe) ++ return NSMakeRange (0, 0); ++ struct buffer *curbuf ++ = XBUFFER (XWINDOW (emacsframe->selected_window)->contents); ++ if (!curbuf) ++ return NSMakeRange (0, 0); ++ ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf); ++ return NSMakeRange (0, (NSUInteger) MIN (range, 10000)); ++} ++ ++- (NSAttributedString *)accessibilityAttributedStringForRange:(NSRange)range ++{ ++ NSString *str = [self accessibilityStringForRange:range]; ++ return [[[NSAttributedString alloc] initWithString:str] autorelease]; ++} ++ ++- (NSInteger)accessibilityLineForIndex:(NSInteger)index ++{ ++ if (!emacsframe) ++ return 0; ++ struct window *w = XWINDOW (emacsframe->selected_window); ++ if (!w || !w->current_matrix) ++ return 0; ++ struct buffer *curbuf = XBUFFER (w->contents); ++ if (!curbuf) ++ return 0; ++ ptrdiff_t charpos = BUF_BEGV (curbuf) + (ptrdiff_t) index; ++ struct glyph_matrix *matrix = w->current_matrix; ++ for (int i = 0; i < matrix->nrows; i++) ++ { ++ struct glyph_row *row = matrix->rows + i; ++ if (!row->enabled_p) ++ continue; ++ if (MATRIX_ROW_START_CHARPOS (row) <= charpos ++ && charpos < MATRIX_ROW_END_CHARPOS (row)) ++ return (NSInteger) i; ++ } ++ return 0; ++} ++ ++- (NSRange)accessibilityRangeForLine:(NSInteger)line ++{ ++ if (!emacsframe) ++ return NSMakeRange (0, 0); ++ struct window *w = XWINDOW (emacsframe->selected_window); ++ if (!w || !w->current_matrix) ++ return NSMakeRange (0, 0); ++ struct buffer *curbuf = XBUFFER (w->contents); ++ if (!curbuf) ++ return NSMakeRange (0, 0); ++ struct glyph_matrix *matrix = w->current_matrix; ++ if (line < 0 || line >= matrix->nrows) ++ return NSMakeRange (0, 0); ++ struct glyph_row *row = matrix->rows + line; ++ if (!row->enabled_p) ++ return NSMakeRange (0, 0); ++ ptrdiff_t start = MATRIX_ROW_START_CHARPOS (row) - BUF_BEGV (curbuf); ++ ptrdiff_t end = MATRIX_ROW_END_CHARPOS (row) - BUF_BEGV (curbuf); ++ if (start < 0) start = 0; ++ if (end < start) end = start; ++ return NSMakeRange ((NSUInteger) start, (NSUInteger) (end - start)); ++} ++ +/* ---- Legacy parameterized attribute APIs (Zoom uses these) ---- */ + +- (NSArray *)accessibilityParameterizedAttributeNames @@ -1055,7 +1196,7 @@ MRC compatible (unsafe_unretained, proper retain/release). @end /* EmacsView */ -@@ -9941,6 +10891,14 @@ +@@ -9941,6 +11032,14 @@ return [super accessibilityAttributeValue:attribute]; }