Quiero recrear exactamente la función de método abreviado de teclado Text To Speech integrada de macOS con AppleScript. Cuando digo "exactamente", quiero decir "exactamente".
La opción integrada se puede encontrar en Preferencias del sistema → Dictado y voz → Texto a voz:
Aquí está la descripción de esta función:
Establece una combinación de teclas para pronunciar el texto seleccionado.
Use esta combinación de teclas para escuchar a su computadora pronunciar el texto seleccionado. Si la computadora está hablando, presione las teclas para detener.
La razón por la que quiero recrear esta función (en lugar de simplemente usarla) es porque tiene errores; a veces funciona, pero, otras veces, presiono el atajo de teclado y no pasa nada. Si lo codifico manualmente en AppleScript, espero que el proceso sea más confiable.
Entiendo cómo iniciar y detener Speech en AppleScript, como se explica aquí .
Pero me gustaría usar el mismo método abreviado de teclado y, por lo tanto, el mismo archivo .scpt, tanto para iniciar como para detener Speech, reflejando la funcionalidad del método abreviado de teclado de Speech integrado.
Estoy usando FastScripts para ejecutar el archivo .scpt mediante un método abreviado de teclado.
Si el mismo archivo .scpt está a cargo de iniciar y detener Speech, la secuencia de comandos requiere una declaración if en la parte superior de AppleScript, o algo similar, para verificar de inmediato si Speech se está hablando actualmente o no, antes de que la secuencia de comandos pueda. proceder. No sé cómo implementar este control, o incluso si es posible.
Pero, esto es lo que tengo:
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:
(Originalmente, quería que AppleScript hablara the clipboard
, pero luego me di cuenta de que esto estaba sobrescribiendo el contenido original del portapapeles. Entonces, en realidad quiero que AppleScript hable el contenido de la theSelectedText
variable, como se demuestra en el código anterior).
Es posible con el say
comando en un shell, no con el say
comando AppleScript.
Información para el comando say de AppleScript:
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"
Este script usa el say
comando en un shell para pronunciar el contenido del pbpaste
comando (el portapapeles) y coloca el PID del say
comando en una propiedad persistente:
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 posible que el primer script no funcione, si el valor de la variable this_say_Pid no persiste en las ejecuciones, depende de cómo se inicie el script. En ese caso, debe escribir el PID en un archivo, así que use este script:
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.
usuario3439894
say
comando AppleScript . Tomando lecturas conps
ylsof
antes, durante y después, pude aislar un patrón, usandodiff
, de archivos que entran en juego que están vinculados al proceso de llamada y podrían codificarse para probar. Sin embargo, probablemente optaría por su método, ya que es solo para usar fácilmente el método que ha propuesto o para usarpgrep say
para obtener su archivoPID
.esfera de rubik
jackjr300
do shell script "/bin/ps ....
contiene un carácter de espacio antes del pid, mientras que el resultado de mi script guardado es solo el PID. De todos modos, el guión se cambia de acuerdo a su necesidad.jackjr300
pgrep
comando ahora, gracias.esfera de rubik
esfera de rubik
jackjr300
keystroke "c" using {command down}
funcione desde la aplicación más frontal, si escucha un pitido (la pulsación de tecla no funcionó). Intenta aumentar el tiempo en segundos deldelay
comando. Intente agregar undelay
comando antes de esta líneamy putOnClipboard:savedClipboard
. Intente agregar undelay
comando antes de esta líneatell application "System Events" to keystroke "c" using {command down}
.esfera de rubik
jackjr300
esfera de rubik
esfera de rubik
delay 1
línea adelay 0.1
, y todavía funciona perfectamente. Luego comparé el tiempo de respuesta de su secuencia de comandos con el tiempo de respuesta del método abreviado de teclado de texto a voz incorporado, y su secuencia de comandos es en realidad un poco más rápida, tanto en términos de iniciar el discurso como de detenerlo. ¡Gracias por tu ayuda! Solo agregaré una verificación a su código para que, si el texto seleccionado está vacío cuando se ejecuta el script, el código no diga el texto del portapapeles, sino que cierre el script.