Ich möchte die in macOS integrierte Text-to-Speech-Tastaturkürzelfunktion mit AppleScript genau nachbilden. Wenn ich „genau“ sage, meine ich „genau“.
Die integrierte Option finden Sie in den Systemeinstellungen → Diktat & Sprache → Text zu Sprache:
Hier ist die Beschreibung dieser Funktion:
Stellen Sie eine Tastenkombination ein, um ausgewählten Text zu sprechen.
Verwenden Sie diese Tastenkombination, um Ihren Computer ausgewählten Text sprechen zu hören. Wenn der Computer spricht, drücken Sie die Tasten zum Stoppen.
Der Grund, warum ich diese Funktion neu erstellen möchte (anstatt sie einfach zu verwenden), ist, dass sie fehlerhaft ist; Manchmal funktioniert es, aber manchmal drücke ich die Tastenkombination und es passiert nichts. Wenn ich es manuell in AppleScript codiere, hoffe ich, dass der Prozess zuverlässiger ist.
Ich verstehe, wie man Speech in AppleScript startet und stoppt, wie hier erklärt .
Ich möchte jedoch dieselbe Tastenkombination und damit dieselbe .scpt-Datei verwenden, um die Sprachausgabe sowohl zu starten als auch zu stoppen, wodurch die Funktionalität der integrierten Sprachtastenkombination widergespiegelt wird.
Ich verwende FastScripts, um die .scpt-Datei über eine Tastenkombination auszuführen.
Wenn die gleiche .scpt-Datei sowohl für das Starten als auch für das Stoppen der Sprache zuständig ist, benötigt das Skript eine if-Anweisung am Anfang des AppleScripts oder etwas Ähnliches, um sofort zu prüfen, ob die Sprache gerade gesprochen wird oder nicht, bevor das Skript dies kann fortfahren. Ich weiß nicht, wie ich diese Überprüfung implementieren soll, oder ob es überhaupt möglich ist.
Aber hier ist, was ich habe:
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:
(Ursprünglich wollte ich, dass das AppleScript spricht the clipboard
, aber dann wurde mir klar, dass dies den ursprünglichen Inhalt der Zwischenablage überschrieb. Also möchte ich eigentlich, dass das AppleScript den Inhalt der theSelectedText
Variablen spricht, wie im obigen Code gezeigt.)
Es ist mit dem say
Befehl in einer Shell möglich, nicht mit dem AppleScript- say
Befehl.
Info zum AppleScript say Befehl:
say "I want to recreate macOS's built-in Text To Speech" waiting until completion no
delay 0.5
say "" with stopping current speech -- this stop the first say command of this script
delay 1
say "Hello"
Dieses Skript verwendet den say
Befehl in einer Shell, um den Inhalt des pbpaste
Befehls (die Zwischenablage) zu sprechen, und fügt die PID des say
Befehls in eine dauerhafte Eigenschaft ein:
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
property this_say_Pid : missing value -- the persistent property
if this_say_Pid is not missing value then -- check the pid of all 'say' commands, if exists then quit the unix process
set allSayPid to {}
try
set allSayPid to words of (do shell script "pgrep -x 'say'")
end try
if this_say_Pid is in allSayPid then -- the PID = an item in the list
do shell script "/bin/kill " & this_say_Pid -- quit this process to stop the speech
error number -128 -- quits the AppleScript
end if
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.
-- Speak the clipboard:
-- pbpaste = the contents of the clipboard , this run the commands without waiting, and get the PID of the 'say' command
set this_say_Pid to do shell script "LANG=en_US.UTF-8 pbpaste -Prefer txt | say > /dev/null 2>&1 & echo $!"
-- Restore original clipboard:
my putOnClipboard:savedClipboard
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:
Es ist möglich, dass das erste Skript nicht funktioniert, wenn der Wert der Variable this_say_Pid nicht über Läufe hinweg bestehen bleibt, hängt davon ab, wie das Skript gestartet wird. In diesem Fall müssen Sie die PID in eine Datei schreiben, verwenden Sie also dieses Skript:
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
set tFile to POSIX path of (path to temporary items as text) & "_the_Pid_of_say_command_of_this_script.txt" -- the temp file
set this_say_Pid to missing value
try
set this_say_Pid to paragraph 1 of (read tFile) -- get the pid of the last speech
end try
if this_say_Pid is not in {"", missing value} then -- check the pid of all 'say' commands, if exists then quit the unix process
set allSayPid to {}
try
set allSayPid to words of (do shell script "pgrep -x 'say'")
end try
if this_say_Pid is in allSayPid then -- the PID = an item in the list
do shell script "/bin/kill " & this_say_Pid -- quit this process to stop the speech
error number -128 -- quits the AppleScript
end if
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.
-- Speak the clipboard:
-- pbpaste = the contents of the clipboard , this run the commands without waiting, and it write the PID of the 'say' command to the temp file
do shell script "LANG=en_US.UTF-8 pbpaste -Prefer txt | say > /dev/null 2>&1 & echo $! > " & quoted form of tFile
-- Restore original clipboard:
my putOnClipboard:savedClipboard
-- *** Important *** : This script is not complete, you must add the 'putOnClipboard:' handler and the 'fetchStorableClipboard()' handler to this script.
Benutzer3439894
say
Befehl ausführt . Beim Lesen von mitps
undlsof
davor, während und danach konnte ich mithilfe von ein Musterdiff
von Dateien isolieren, die ins Spiel kommen, die mit dem Aufrufprozess verknüpft sind und zum Testen codiert werden könnten. Ich würde mich jedoch wahrscheinlich für Ihre Methode entscheiden, da es einfach ist, die von Ihnen vorgeschlagene Methode zu verwenden oder zu verwenden,pgrep say
um ihrePID
.Rubiks Sphäre
jackjr300
do shell script "/bin/ps ....
ein Leerzeichen vor der PID enthält, während das Ergebnis meines gespeicherten Skripts nur die PID ist. Auf jeden Fall wird das Skript nach Ihren Bedürfnissen geändert.jackjr300
pgrep
Befehl jetzt verwenden, danke.Rubiks Sphäre
Rubiks Sphäre
jackjr300
keystroke "c" using {command down}
von der vordersten Anwendung aus funktioniert, wenn Sie einen Piepton hören (der Tastendruck hat nicht funktioniert). Versuchen Sie, die Zeit in Sekunden desdelay
Befehls zu erhöhen.delay
Versuchen Sie , vor dieser Zeile einen Befehl einzufügenmy putOnClipboard:savedClipboard
.delay
Versuchen Sie , vor dieser Zeile einen Befehl einzufügentell application "System Events" to keystroke "c" using {command down}
.Rubiks Sphäre
jackjr300
Rubiks Sphäre
Rubiks Sphäre
delay 1
Zeile in geändertdelay 0.1
, und es funktioniert immer noch perfekt. Ich habe dann die Reaktionszeit Ihres Skripts mit der Reaktionszeit der integrierten Text-zu-Sprache-Tastenkombination verglichen, und Ihr Skript ist tatsächlich etwas schneller, sowohl was das Starten als auch das Stoppen der Sprache betrifft. Vielen Dank für Ihre Hilfe! Ich werde Ihrem Code nur eine Überprüfung hinzufügen, damit der Code den Text aus der Zwischenablage nicht spricht, sondern das Skript beendet, wenn der ausgewählte Text leer ist, wenn das Skript ausgeführt wird.