[閒聊] ScreenReader DIY 實錄(一) - 討論區

[閒聊] ScreenReader DIY 實錄(一)

文章瀏覽次數 1424 文章回覆數 9

coscell

coscell圖像(預設)

2020-04-16 21:12:06

From:180.176.111.5

說實話我已經開始對NVDA不滿了,效能差就不說了,還會經常無故變啞巴,動不動就要重起。
於是我開始興起自己寫一個的念頭。
當然這是癡人說夢,別說想要趕上NVDA,能做出作品就是天大奇蹟了!
不過既然住定要失敗,從中學習到經驗和知識一定有的,就幹吧!

接下來教該選擇語言。
要效能當然要用C,可是我已經非常生疏了,過程還會吃盡苦頭實在不划算。
再來應該輪到 python.
可是NVDA就是 python 開發,過程一定會偷用他的程式碼,這樣有什麼意思?
最後剩下 AutoIt3 了。

不論用什麼語言,螢幕報讀軟體一定要會說話。
很幸運我找到了神人製作的 AutoIt3 的 SAPI5 語音模組。
初步實驗:

#include <TTS.au3>
$talk = _StartTTS()
_Speak($talk, "大家好")

就叫 Coscell's ScreenReader Demo 好了,存成 SCRD.au3.
測試結果真的會說話耶!
真是好的開始,可以準備下一部了。

留言

#1

特種兵

特種兵圖像(預設)

2020-04-17 17:35:01

From:211.23.21.202

不知道什麼時候放棄
不知道三分鐘熱度的毛病還在不在?

#2

coscell

coscell圖像(預設)

2020-04-17 21:39:46

From:180.176.111.5

我高點寫了八年,你說呢

#3

Maxe

Maxe圖像(預設)

2020-04-20 15:43:31

From:211.23.21.202

那試試這個如何?

若電腦上已安裝 Autoit 可直接複製以下代碼,存成 .au3 之後便可立即執行體驗。
建議選擇可閱讀中文的 Sapi5 語音,從控制台找到文字轉語音,並進行設定。
我在幾年前完成它時,只有在 Win7 測試過,至少已經可以很穩定的在記事本閱讀長篇小說了。

代碼開始:

; 定義初始化函數
func init()
; 建立 Sapi 語音物件
global $sapi = ObjCreate("Sapi.SpVoice")
; 為了避免與其他正在使用 Sapi 的程式搶主要輸出管道,所以我們另外跟系統要一個新的輸出管道。
$sapi_audio = objCreate("sapi.spMMAudioOut")
; 然後將輸出管道設定成我們新建的管道
$sapi.audioOutputStream = $sapi_audio
; 然後這個新建的管道實力就可以不要了
$sapi_audio = null

; 設定尋找視窗標題的模式,目的等我們用到的時候再講

opt("WinTitleMatchMode", 4)
; 註冊 shift+esc 這個快速鍵來執行 onExit 這個函數,已關閉導讀軟體。 + 是 shift 的意思
hotKeySet("+{ESC}", "onExit")
; 讓語音說出軟體已啟動的提示
output("實驗型螢幕導讀軟體已啟動!若要關閉導讀軟體,請按 Shift+ESC 鍵。", 0)
endFunc

; 執行初始化動作
init()

; 主程式無窮迴圈開始
while 1
; 回圈內不斷執行 eventProcess 這個函數
eventProcess()
; 讓每一次都稍微休息一下,不要轉太快
sleep(20)
wEnd

; 定義 eventProcess 這個函數,函數內將檢查焦點的改變與控件資訊,最後通知對應事件的函數
func eventProcess()
; 定義 4 個靜態變數,以記錄當前視窗標題、焦點指向的控件,以及如果控件是編輯區,則記錄游標所在的行列。
static $window, $focus, $line, $col

; 收集要讓語音朗讀的文字
$output = ""
; 抓取當前視窗的視窗標題,那個 "active" 是目前顯示在畫面上視窗的意思,是設定視窗標題搜尋第 4 模式的功能
$gWindow = WinGetTitle("active", "")
; 檢查抓取的視窗標題與上一圈抓到的是否相同,若不同就表示視窗改變了,需通知對應函數
if $gWindow <> $window then
$window = $gWindow
$output &= onActiveWindowChange($window)
endIf

; 接著是視窗內焦點的位置,做法與視窗標題相同
$gFocus = ControlGetFocus("active", "")
if $gFocus <> $focus then
$focus = $gFocus
$output &= onFocusChange($focus)
endIf
; 接著檢查 $focus
select
; 如果是編輯區就抓取編輯區內的游標所在蘭列位置
case StringInStr($focus, "Edit")
$gLine = ControlCommand("active", "", $focus, "GetCurrentLine")
$gCol = ControlCommand("active", "", $focus, "GetCurrentCol")
; 接著依然跟上一圈的欄與列相比,若不同則通知對應函數
select
case $gLine <> $line
$output &= onLineChange($focus, $gLine)
case $gCol <> $col
$output &= onColChange($focus, $line, $gCol)
endSelect
$line = $gLine
$col = $gCol
endSelect
; 接著該輸出文字了,先檢查是否有累積到文字,如果沒有就不用輸出了,因為空字串是強制停止語音朗讀的意思
if $output then output($output)
endFunc

; 定義將文字傳給語音並輸出的函數,那個 $flag 不大記得具體意義了,只記得 3 是非同步輸出,也就是不等語音說完就離開這個函數,讓程式繼續執行的意思,前面有用到 0 可能是同步輸出,必須等語音閱讀完畢才會繼續程式的意思
func output($str, $flag = 3)
; 這裡用 execute 包起來,其實是因為懶得做 $sapi 萬一出意外的處理xd
execute($sapi.speak($str, $flag))
endFunc

; 當視窗改變的處理函數
func onActiveWindowChange($title)
return $title & " 視窗 "
endFunc

; 當視窗內焦點改變時的處理函數
func onFocusChange($focus)
select
; 這裡根據 $focus 的值,猜測可能的控件,並將中文名稱回傳
case StringInStr($focus, "Edit")
return " 編輯區 "
case StringInStr($focus, "List")
return " 清單 "
case StringInStr($focus, "Button")
return ControlGetText("active", "", $focus) & " 按鈕 "
case else
return "不明"
endSelect
endFunc

; 當編輯區游標所在行改變時的處理函數
func onLineChange($focus, $line)
; 抓取該編輯區內的所有文字
$text = ControlGetText("active", "", $focus)
; 抓取當前行的文字
$lineText = StringSplit($text, @crlf, 1)[$line]
if not $lineText then $lineText = "空行"
return $lineText
endFunc

; 當編輯區游標所在欄改變時的處理函數
func onColChange($focus, $line, $col)
$text = ControlGetText("active", "", $focus)
$lineText = StringSplit($text, @crlf, 1)[$line]
; 當游標到達行尾時,位置將會超過當前行的字串長度
if $col > StringLen($lineText) then return "行委"
return StringSplit($lineText, "")[$col]
endFunc

; 導讀軟體結束之前的處理函數
func onExit()
output("正在關閉實驗型螢幕導讀軟體 ...", 0)
$sapi = null
exit
endFunc

#4

特種兵

特種兵圖像(預設)

2020-04-20 19:31:35

From:211.23.21.202

上一則是本站目前最長的留言

#5

Maxe

Maxe圖像(預設)

2020-04-20 19:54:01

From:36.230.209.97

好險沒超過字數限制

#6

coscell

coscell圖像(預設)

2020-04-20 20:50:18

From:180.176.111.5

執行結果:
提示說明結束會聽到畚箕磁碟視窗不明。
隨便操作會出現 line 104 有錯,陣列索引不正確。

#7

阿慶

阿慶圖像

2020-04-26 18:38:24

From:122.116.71.150

To #3:
建議如果留言太常可以直接回應文章。

#8

星空

星空圖像(預設)

2020-04-29 18:24:37

From:117.62.104.76

可以用c#

#9

此篇留言已被刪除。