AppleScript : Speech가 현재 실행 중인지 확인할 수 있습니까?


1

AppleScript를 사용하여 macOS의 내장 텍스트 음성 변환 키보드 단축키 기능을 정확하게 재현하고 싶습니다. 내가 "정확하게"라고 말할 때, "정확하게"를 의미합니다.

내장 옵션은 시스템 환경 설정 → 받아쓰기 및 말하기 → 텍스트 음성 변환에서 찾을 수 있습니다.

스크린 샷

이 기능에 대한 설명은 다음과 같습니다.

선택한 텍스트를 말하도록 키 조합을 설정하십시오.

이 키 조합을 사용하여 컴퓨터가 선택된 텍스트를 말하는 것을들을 수 있습니다. 컴퓨터가 말하는 중이면 키를 눌러 중지합니다.

이 기능을 단순히 사용하는 대신 재생성하려는 이유는 버그가 있기 때문입니다. 때로는 작동하지만 다른 경우에는 키보드 단축키를 누르면 아무 일도 일어나지 않습니다. AppleScript에서 수동으로 코딩하면 프로세스가 더 안정적이기를 바랍니다.


여기 설명 된대로 AppleScript에서 Speech를 시작하고 중지하는 방법을 이해합니다 .

그러나 동일한 키보드 단축키와 동일한 .scpt 파일을 사용하여 내장 음성 키보드 단축키의 기능을 반영하여 음성을 시작하고 중지합니다.

키보드 단축키로 FastScripts를 사용하여 .scpt 파일을 실행하고 있습니다.

동일한 .scpt 파일이 Speech 시작과 중지를 담당하는 경우, 스크립트는 AppleScript 상단에 if 문 또는 이와 유사한 것이 필요합니다. 발하다. 이 검사를 구현하는 방법 또는 가능한지 모르겠습니다.

그러나 여기 내가 가진 것이 있습니다.

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:

(원래, AppleScript가 말하기를 원했지만 the clipboard이것이 원래 클립 보드 내용을 덮어 쓰고 있음을 깨달았습니다. 따라서 실제로 theSelectedText위 코드에서 설명한 것처럼 AppleScript가 변수 의 내용을 말하고 싶습니다 .)

답변:


3

sayAppleScript say명령이 아닌 쉘 의 명령으로 가능합니다 .

AppleScript say 명령에 대한 정보 :

  • 스크립트 종료 후가 아니라 스크립트가 실행될 때까지 동일한 스크립트에서 say 명령의 말하기를 중지 할 수 있습니다.
  • 예:
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"

이 스크립트 say는 셸 의 명령을 사용하여 명령의 내용 pbpaste(클립 보드) 을 말하고 명령의 PID를 say영구 속성에 넣습니다 .

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:

첫 번째 스크립트가 작동 하지 않을 수 있습니다. this_say_Pid 변수 의 값이 여러 실행에서 지속되지 않으면 스크립트 시작 방법에 따라 다릅니다. 이 경우 PID를 파일에 써야하므로 다음 스크립트를 사용하십시오.

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.

그냥 추가하고 싶었지만 실제로 (Apple) Script Editor 또는 AppleScript 앱 등이 AppleScript say 명령을 실행하고 있는지 알 수있는 방법이 있습니다. 와 판독 촬영 pslsof이전을, 중 및 후에, 나는 사용 패턴을 분리 할 수 있었다 diff호출 프로세스에 연결하고 테스트하기 위해 코딩 할 수있는 놀이에 와서 파일로. 그러나 제안한 방법을 쉽게 사용하거나을 pgrep say얻는 데 사용 하기 때문에 방법을 선택했을 것 PID입니다.
user3439894

@ jackjr300 질문에 중요한 세부 사항을 추가했는데 실제로 클립 보드를 음성 텍스트 소스로 직접 사용하고 싶지 않다는 사실을 깨달았습니다. 원래 클립 보드 내용이 손실 될 수 있습니다. 내 편집 내용을 참조하십시오. 그러나 어쨌든 ... 첫 번째 해결책은 현재 말하는 텍스트를 중단시키지 않고 단순히 말하기 명령을 다시 트리거하여 겹쳤습니다. 두 연설은 동시에 일어난다. 두 번째 솔루션은 같은 방식으로 작동합니다. 예를 들어, .scpt 파일을 5 번 연속으로 실행하면 5 개의 연설이 모두 동시에 작동합니다. 제대로 작동합니까?
rubik의 구체

@rubik의 구체,이 페이지에서 복사하여 붙여 넣은 스크립트는 작동하지 않습니다. 명령 결과에 do shell script "/bin/ps ....pid 앞에 공백 문자가 포함되어 있기 때문에 저장된 스크립트의 결과는 PID 전용입니다. 어쨌든 스크립트는 필요에 따라 변경됩니다.
jackjr300

@ user3439894 예, 이제이 pgrep명령 을 사용하겠습니다 . 감사합니다.
jackjr300

@ jackjr300 (1/2) 고맙습니다. 점점 가까워지고 있지만 여전히 코드에 버그가 있습니다. 이것은 첫 번째 솔루션과 두 번째 솔루션 모두에 해당됩니다. 처음 코드를 실행하면 (첫 번째 또는 두 번째 솔루션) 선택한 텍스트가 음성으로 표시됩니다. 큰. 그런 다음 즉시 코드를 두 번째로 실행하면 말하기가 중단됩니다. 큰. 그러나 선택한 텍스트를 말하는 대신 스크립트를 세 번째로 실행하면 클립 보드 텍스트가 사용됩니다 (선택한 텍스트가 클립 보드에 복사되기 전에 원본 클립 보드 내용에서와 같이). 그러나 정확히 6 분 전에 기다린다면
rubik의 영역
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.