Fix VO cursor sync, word double-read, and VO->Emacs positioning
patch 0002: Do not activate mark in setAccessibilitySelectedTextRange. VoiceOver range.length is an internal word-boundary hint, not a text selection. Activating the mark made accessibilitySelectedTextRange return a non-zero length, causing VoiceOver to position its browse cursor at the END of the selection instead of the START. patch 0003: Fix word announcement double-read and punctuation. - Explicit word announcement only for Emacs-initiated (discontiguous) moves; VO-initiated (sequential) word navigation relies on VO auto-speech from the granularity=word notification, preventing double-read. - Strip trailing/leading punctuation from word announcements using punctuationCharacterSet so 'Ahoj,' is announced as 'Ahoj'. patch 0008: Post FocusedUIElementChangedNotification on the EmacsView (not just on line-granularity moves) for all Emacs-initiated cursor movements. Posting on the view causes VoiceOver to re-query accessibilityFocusedUIElement and re-anchor its browse cursor at the current accessibilitySelectedTextRange. Also fixes a pre-existing off-by-one in the macos.texi hunk header.
This commit is contained in:
@@ -30,7 +30,7 @@ diff --git a/src/nsterm.m b/src/nsterm.m
|
|||||||
index 852e7f9..3e1ac74 100644
|
index 852e7f9..3e1ac74 100644
|
||||||
--- a/src/nsterm.m
|
--- a/src/nsterm.m
|
||||||
+++ b/src/nsterm.m
|
+++ b/src/nsterm.m
|
||||||
@@ -7631,6 +7631,1129 @@ - (id)accessibilityTopLevelUIElement
|
@@ -7631,6 +7631,1121 @@ - (id)accessibilityTopLevelUIElement
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -833,20 +833,12 @@ index 852e7f9..3e1ac74 100644
|
|||||||
+
|
+
|
||||||
+ SET_PT_BOTH (charpos, CHAR_TO_BYTE (charpos));
|
+ SET_PT_BOTH (charpos, CHAR_TO_BYTE (charpos));
|
||||||
+
|
+
|
||||||
+ /* Keep mark state aligned with requested selection range. */
|
+ /* Always deactivate mark: VoiceOver range.length is an internal
|
||||||
+ if (range.length > 0)
|
+ word boundary hint, not a text selection. Activating the mark
|
||||||
+ {
|
+ makes accessibilitySelectedTextRange return a non-zero length,
|
||||||
+ ptrdiff_t mark_charpos = [self charposForAccessibilityIndex:
|
+ which confuses VoiceOver into positioning its browse cursor at
|
||||||
+ range.location + range.length];
|
+ the END of the selection instead of the start. */
|
||||||
+ if (mark_charpos > BUF_ZV (b))
|
+ bset_mark_active (b, Qnil);
|
||||||
+ mark_charpos = BUF_ZV (b);
|
|
||||||
+ Fset_marker (BVAR (b, mark), make_fixnum (mark_charpos),
|
|
||||||
+ Fcurrent_buffer ());
|
|
||||||
+ bset_mark_active (b, Qt);
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
+ bset_mark_active (b, Qnil);
|
|
||||||
+
|
|
||||||
+ unbind_to (count, Qnil);
|
+ unbind_to (count, Qnil);
|
||||||
+
|
+
|
||||||
+ /* Update cached state so the next notification cycle doesn't
|
+ /* Update cached state so the next notification cycle doesn't
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ diff --git a/src/nsterm.m b/src/nsterm.m
|
|||||||
index 3e1ac74..d3015e2 100644
|
index 3e1ac74..d3015e2 100644
|
||||||
--- a/src/nsterm.m
|
--- a/src/nsterm.m
|
||||||
+++ b/src/nsterm.m
|
+++ b/src/nsterm.m
|
||||||
@@ -8758,6 +8758,605 @@ - (NSRect)accessibilityFrame
|
@@ -8758,6 +8758,609 @@ - (NSRect)accessibilityFrame
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -162,8 +162,8 @@ index 3e1ac74..d3015e2 100644
|
|||||||
+ user expectation ("w" jumps to next word and reads it). */
|
+ user expectation ("w" jumps to next word and reads it). */
|
||||||
+ BOOL isWordMove
|
+ BOOL isWordMove
|
||||||
+ = (!markActive && !oldMarkActive
|
+ = (!markActive && !oldMarkActive
|
||||||
+ && granularity
|
+ && granularity == ns_ax_text_selection_granularity_word
|
||||||
+ == ns_ax_text_selection_granularity_word);
|
+ && direction == ns_ax_text_selection_direction_discontiguous);
|
||||||
+ if (isWordMove && cachedText)
|
+ if (isWordMove && cachedText)
|
||||||
+ {
|
+ {
|
||||||
+ NSCharacterSet *ws
|
+ NSCharacterSet *ws
|
||||||
@@ -191,7 +191,11 @@ index 3e1ac74..d3015e2 100644
|
|||||||
+ NSString *word
|
+ NSString *word
|
||||||
+ = [cachedText substringWithRange:
|
+ = [cachedText substringWithRange:
|
||||||
+ NSMakeRange (wstart, wend - wstart)];
|
+ NSMakeRange (wstart, wend - wstart)];
|
||||||
+ word = [word stringByTrimmingCharactersInSet: ws];
|
+ NSMutableCharacterSet *trims
|
||||||
|
+ = [ws mutableCopy];
|
||||||
|
+ [trims formUnionWithCharacterSet:
|
||||||
|
+ [NSCharacterSet punctuationCharacterSet]];
|
||||||
|
+ word = [word stringByTrimmingCharactersInSet:trims];
|
||||||
+ if ([word length] > 0)
|
+ if ([word length] > 0)
|
||||||
+ {
|
+ {
|
||||||
+ NSDictionary *annInfo = @{
|
+ NSDictionary *annInfo = @{
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ diff --git a/etc/NEWS b/etc/NEWS
|
|||||||
index 2b1f9e6..5766428 100644
|
index 2b1f9e6..5766428 100644
|
||||||
--- a/etc/NEWS
|
--- a/etc/NEWS
|
||||||
+++ b/etc/NEWS
|
+++ b/etc/NEWS
|
||||||
@@ -4400,16 +4400,20 @@ allowing Emacs users access to speech recognition utilities.
|
@@ -4400,16 +4400,19 @@ allowing Emacs users access to speech recognition utilities.
|
||||||
Note: Accepting this permission allows the use of system APIs, which may
|
Note: Accepting this permission allows the use of system APIs, which may
|
||||||
send user data to Apple's speech recognition servers.
|
send user data to Apple's speech recognition servers.
|
||||||
|
|
||||||
@@ -518,7 +518,7 @@ index 8d44b5f..29b646d 100644
|
|||||||
NSInteger direction = ns_ax_text_selection_direction_discontiguous;
|
NSInteger direction = ns_ax_text_selection_direction_discontiguous;
|
||||||
if (point > oldPoint)
|
if (point > oldPoint)
|
||||||
direction = ns_ax_text_selection_direction_next;
|
direction = ns_ax_text_selection_direction_next;
|
||||||
@@ -9488,6 +9670,41 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property
|
@@ -9488,6 +9670,36 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property
|
||||||
granularity = ns_ax_text_selection_granularity_line;
|
granularity = ns_ax_text_selection_granularity_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,19 +542,14 @@ index 8d44b5f..29b646d 100644
|
|||||||
+ if (emacsMovedCursor && !isCtrlNP)
|
+ if (emacsMovedCursor && !isCtrlNP)
|
||||||
+ direction = ns_ax_text_selection_direction_discontiguous;
|
+ direction = ns_ax_text_selection_direction_discontiguous;
|
||||||
+
|
+
|
||||||
+ /* Post FocusedUIElementChanged when Emacs moved the cursor
|
+ /* Post FocusedUIElementChanged on the containing NSView whenever
|
||||||
+ across a line boundary so VoiceOver re-anchors its browse
|
+ Emacs moves the cursor independently of VoiceOver. Posting on
|
||||||
+ cursor at the new accessibilitySelectedTextRange.
|
+ the view causes VoiceOver to re-query accessibilityFocusedUIElement
|
||||||
+ SelectedTextChanged with discontiguous direction alone is
|
+ and re-anchor its browse cursor at the new selection range, without
|
||||||
+ not sufficient; VoiceOver requires this notification to
|
+ re-announcing the element name. Required for all granularities. */
|
||||||
+ re-query the focused element and update its internal
|
+ if (emacsMovedCursor && [self isAccessibilityFocused])
|
||||||
+ browse position. */
|
|
||||||
+ if (emacsMovedCursor
|
|
||||||
+ && granularity
|
|
||||||
+ == ns_ax_text_selection_granularity_line
|
|
||||||
+ && [self isAccessibilityFocused])
|
|
||||||
+ ns_ax_post_notification (
|
+ ns_ax_post_notification (
|
||||||
+ self,
|
+ self.emacsView,
|
||||||
+ NSAccessibilityFocusedUIElementChangedNotification);
|
+ NSAccessibilityFocusedUIElementChangedNotification);
|
||||||
+
|
+
|
||||||
/* Post notifications for focused and non-focused elements. */
|
/* Post notifications for focused and non-focused elements. */
|
||||||
|
|||||||
Reference in New Issue
Block a user