Subject: Re: bug#79070: [PATCH] Fix macOS dictation post NSTextInputClient migration in v30

From: Alvaro Ramirez <[email-masked]>
Date: Wed, 23 Jul 2025 14:02:28 +0100

Eli Zaretskii <[email-masked]> writes:

> Thanks, but one of my previous comments, viz.:
>
>   This should explain better what are the indications of the 
>   problem.
>
> is still not addressed.

Updated PROBLEMS in 
0006-Enabled-macOS-dictation-post-NSTextInputClient-migration.patch.
Hope that's better now.

>> A tiny bit of additional info with respect to roll back (yields
>> deprecation warning) vs roll forward fix... macOS seems to use 
>> a
>> different dictation mechanism after NSTextInputClient was
>> introduced (Emacs v30). Attaching screenshots showing different 
>> UI
>> dictation triggered by either patch.
>
> Could you please spell out what that means for Emacs users?

Not much really. This is more of a macOS implementation 
detail. Emacs users will get their dictation feature back, 
regressed in Emacs 30. Fixing the regression leads to using a 
newer API, which triggers a slightly different-looking UI. The way 
the feature is triggered (global keyboard shortcut) and 
transcription behaviour remain the same, so no significant change 
in expectation as to how the feature works.

In a little more detail...

Introducing NSTextInputClient in Emacs v30 broke/removed dictation 
as a side effect. This introduction seems to signal to macOS to 
rely more on NSTextInputClient (new class) and less on NSTextInput 
(deprecated class) to power separate internal dictation 
subsystems. The screenshots I shared show the slightly 
different-looking UI for each internal subsystem. One uses a large 
microphone icon vs the tiny blue microphone icon (newer). Enabling 
dictation (global keyboard shortcut) and transcription behaviour 
remain the same.

>From 689a18cf6dfa3ee12acb0e6a0a2dc5c03d1488bf Mon Sep 17 00:00:00 2001
From: Alvaro Ramirez <[email-masked]>
Date: Mon, 21 Jul 2025 12:53:50 +0100
Subject: [PATCH] Enabled macOS dictation post NSTextInputClient migration in v30

* src/nsterm.m (selectedRange): Implement to fix dictation.
* etc/NEWS: Announce regression fix.
* etc/PROBLEMS: Help users recover from rejected permission.
---
 etc/NEWS     |  5 +++++
 etc/PROBLEMS | 13 +++++++++++++
 src/nsterm.m | 19 ++++++++++++++++++-
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/etc/NEWS b/etc/NEWS
index b469b22aacf..4e6bfc45f1e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2786,6 +2786,11 @@ allowing Emacs users access to speech recognition utilities.
 Note: Accepting this permission allows the use of system APIs, which may
 send user data to Apple's speech recognition servers.
 
+---
+** Re-introduced dictation, lost in Emacs v30 (macOS).
+We lost macOS dictation in v30 when migrating to NSTextInputClient.
+Implemented 'selectedRange' in 'nsterm.m' to enable in new subsystem.
+
 +++
 ** On Mac OS X, stipples now render with color.
 
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 20fe9134da5..ccc9e48f530 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -3566,6 +3566,19 @@ file; for example:
       "/usr/local/opt/libgccjit/lib/gcc/11"
       "/usr/local/opt/gcc/lib/gcc/11/gcc/x86_64-apple-darwin20/11.2.0") ":"))
 
+** macOS text dictation isn't recognising keyboard shortcut
+
+There's a chance that microphone permission may have been rejected in the past.
+
+Try clearing this permission with:
+
+  tccutil reset Microphone org.gnu.Emacs
+
+** macOS text dictation not reachable from Emacs on macOS 12
+
+The keyboard shortcut that normally enables dictation for all macOS apps may be
+ignored on Emacs for users running macOS 12.
+
 * Runtime problems specific to PGTK build
 
 ** Whether a display server is available cannot be automatically detected.
diff --git a/src/nsterm.m b/src/nsterm.m
index 003aadb9782..2b34894f36e 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -7413,7 +7413,24 @@ - (NSRange)selectedRange
 {
   if (NS_KEYLOG)
     NSLog (@"selectedRange request");
-  return NSMakeRange (NSNotFound, 0);
+
+  struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
+  struct buffer *buf = XBUFFER (w->contents);
+  ptrdiff_t point = BUF_PT (buf);
+
+  if (NILP (BVAR (buf, mark_active)))
+    {
+      NSUInteger selection_location = point - BUF_BEGV (buf);
+      return NSMakeRange (selection_location, 0);
+    }
+
+  ptrdiff_t mark = marker_position (BVAR (buf, mark));
+  ptrdiff_t region_start = min (point, mark);
+  ptrdiff_t region_end = max (point, mark);
+  NSUInteger selection_location = region_start - BUF_BEGV (buf);
+  NSUInteger selection_length = region_end - region_start;
+
+  return NSMakeRange (selection_location, selection_length);
 }
 
 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
-- 
2.50.0