v15.3: fix VoiceOver cursor not following during typing
Root cause (confirmed via WebKit/Chromium source): ValueChanged (edit) and SelectedTextChanged (cursor move) are MUTUALLY EXCLUSIVE — apps must never send both for the same user action. VoiceOver enters 'typing mode' on Edit notifications and suppresses/ignores concurrent SelectionMove notifications, causing the cursor to appear stuck. Fix: (1) Update cachedPoint inside the modiff branch so the selection-move check doesn't trigger for edit-caused point changes. (2) Change 'if' to 'else if' for explicit mutual exclusion. Source: WebKit AXObjectCacheMac.mm — postTextStateChangePlatformNotification vs postTextSelectionChangePlatformNotification are separate code paths that never fire for the same event.
This commit is contained in:
@@ -73,7 +73,7 @@ index 7c1ee4c..4abeafe 100644
|
||||
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 932d209..792f7c5 100644
|
||||
index 932d209..5252e6d 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -1104,6 +1104,11 @@ ns_update_end (struct frame *f)
|
||||
@@ -126,7 +126,7 @@ index 932d209..792f7c5 100644
|
||||
ns_focus (f, NULL, 0);
|
||||
|
||||
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
|
||||
@@ -6847,6 +6883,756 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
|
||||
@@ -6847,6 +6883,764 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -743,6 +743,11 @@ index 932d209..792f7c5 100644
|
||||
+ }
|
||||
+
|
||||
+ self.cachedModiff = modiff;
|
||||
+ /* Update cachedPoint here so the selection-move branch below
|
||||
+ does NOT fire for point changes caused by edits. WebKit and
|
||||
+ Chromium never send both ValueChanged and SelectedTextChanged
|
||||
+ for the same user action — they are mutually exclusive. */
|
||||
+ self.cachedPoint = point;
|
||||
+
|
||||
+ NSDictionary *change = @{
|
||||
+ @"AXTextEditType": @3,
|
||||
@@ -758,8 +763,11 @@ index 932d209..792f7c5 100644
|
||||
+ }
|
||||
+
|
||||
+ /* --- Cursor moved or selection changed → line reading ---
|
||||
+ kAXTextStateChangeTypeSelectionMove = 2. */
|
||||
+ if (point != self.cachedPoint || markActive != self.cachedMarkActive)
|
||||
+ kAXTextStateChangeTypeSelectionMove = 2.
|
||||
+ Use 'else if' — edits and selection moves are mutually exclusive
|
||||
+ per the WebKit/Chromium pattern. VoiceOver gets confused if
|
||||
+ both notifications arrive in the same runloop iteration. */
|
||||
+ else if (point != self.cachedPoint || markActive != self.cachedMarkActive)
|
||||
+ {
|
||||
+ ptrdiff_t oldPoint = self.cachedPoint;
|
||||
+ self.cachedPoint = point;
|
||||
@@ -883,7 +891,7 @@ index 932d209..792f7c5 100644
|
||||
/* ==========================================================================
|
||||
|
||||
EmacsView implementation
|
||||
@@ -6889,6 +7675,7 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
|
||||
@@ -6889,6 +7683,7 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
|
||||
[layer release];
|
||||
#endif
|
||||
|
||||
@@ -891,7 +899,7 @@ index 932d209..792f7c5 100644
|
||||
[[self menu] release];
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -8237,6 +9024,18 @@ ns_in_echo_area (void)
|
||||
@@ -8237,6 +9032,18 @@ ns_in_echo_area (void)
|
||||
XSETFRAME (event.frame_or_window, emacsframe);
|
||||
kbd_buffer_store_event (&event);
|
||||
ns_send_appdefined (-1); // Kick main loop
|
||||
@@ -910,7 +918,7 @@ index 932d209..792f7c5 100644
|
||||
}
|
||||
|
||||
|
||||
@@ -9474,6 +10273,290 @@ ns_in_echo_area (void)
|
||||
@@ -9474,6 +10281,290 @@ ns_in_echo_area (void)
|
||||
return fs_state;
|
||||
}
|
||||
|
||||
@@ -1201,7 +1209,7 @@ index 932d209..792f7c5 100644
|
||||
@end /* EmacsView */
|
||||
|
||||
|
||||
@@ -9941,6 +11024,14 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
|
||||
@@ -9941,6 +11032,14 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
|
||||
|
||||
return [super accessibilityAttributeValue:attribute];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user