I want to exactly recreate macOS's built-in Text To Speech keyboard shortcut feature with AppleScript. When I say "exactly," I mean "exactly."
The built-in option can be found in System Preferences → Dictation & Speech → Text to Speech:
Here is the description of this feature:
Set a key combination to speak selected text.
Use this key combination to hear your computer speak selected text. If the computer is speaking, press the keys to stop.
The reason that I want to recreate this feature (instead of simply using it) is because it is buggy; sometimes it works, but, other times, I press the keyboard shortcut and nothing happens. If I code it manually in AppleScript, I hope that the process will be more reliable.
I understand how to start and stop Speech in AppleScript, as explained here.
But I would like to use the same keyboard shortcut, and thus the same .scpt file, to both start and stop the Speech, mirroring the functionality of the built-in Speech keyboard shortcut.
I am using FastScripts to run the .scpt file by a keyboard shortcut.
If the same .scpt file is in charge of both starting and stopping the Speech, the script requires an if statement at the top of the AppleScript, or something similar, to immediately check if Speech is currently being spoken or not, before the script can proceed. I do not know how to implement this check, or if it is even possible.
But, here's what I have:
if <This is where I need your help, Ask Different> then
say "" with stopping current speech
error number -128 -- quits the AppleScript
end if
-- Back up original clipboard contents:
set savedClipboard to my fetchStorableClipboard()
-- Copy selected text to clipboard:
tell application "System Events" to keystroke "c" using {command down}
delay 1 -- Without this, the clipboard may have stale data.
set theSelectedText to the clipboard
-- Restore original clipboard:
my putOnClipboard:savedClipboard
-- Speak the selected text:
say theSelectedText waiting until completion no
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
on fetchStorableClipboard()
set aMutableArray to current application's NSMutableArray's array() -- used to store contents
-- get the pasteboard and then its pasteboard items
set thePasteboard to current application's NSPasteboard's generalPasteboard()
-- loop through pasteboard items
repeat with anItem in thePasteboard's pasteboardItems()
-- make a new pasteboard item to store existing item's stuff
set newPBItem to current application's NSPasteboardItem's alloc()'s init()
-- get the types of data stored on the pasteboard item
set theTypes to anItem's types()
-- for each type, get the corresponding data and store it all in the new pasteboard item
repeat with aType in theTypes
set theData to (anItem's dataForType:aType)'s mutableCopy()
if theData is not missing value then
(newPBItem's setData:theData forType:aType)
end if
end repeat
-- add new pasteboard item to array
(aMutableArray's addObject:newPBItem)
end repeat
return aMutableArray
end fetchStorableClipboard
on putOnClipboard:theArray
-- get pasteboard
set thePasteboard to current application's NSPasteboard's generalPasteboard()
-- clear it, then write new contents
thePasteboard's clearContents()
thePasteboard's writeObjects:theArray
end putOnClipboard:
(Originally, I had wanted the AppleScript to speak the clipboard
, but then I realized that this was overwriting the original clipboard contents. So, I actually want the AppleScript to speak the contents of the theSelectedText
variable, as demonstrated in the above code.)