「すべて読み上げ」で改行をまたぐ単語を適切に読み上げない
ひさしぶりにこの件を確認していますが、 この現象はスペースで単語を区切らない日本語のような言語に固有の問題で、 少なくとも英語については下記で対応済みと思われます。
Say all without unnatural pauses
http://community.nvda-project.org/ticket/149
http://community.nvda-project.org/changeset/e13e64af10d6708413d3b4c87365bb382502c8a5
speech.py の re_last_pause の動作を調べる実験:
--- a/source/speech.py +++ b/source/speech.py @@ -1555,9 +1555,11 @@ def speakWithoutPauses(speechSequence,detectBreaks=True): for index in xrange(len(speechSequence)-1,-1,-1): item=speechSequence[index] if isinstance(item,basestring): + log.info("re_last_pause matching(%s)" % item) m=re_last_pause.match(item) if m: before,after=m.groups() + log.info("re_last_pause(%s)(%s)" % (before, after)) if after: pendingSpeechSequence.append(after) if before:
読み上げるテキスト
NVDAは、コミュニティーの援 助によりNV Accessが開発しました。 It is a fine day. It is? a fine day. It is another fine day. Is it really fine day?
ログ
INFO - speech.speakWithoutPauses (23:47:02): re_last_pause matching(NVDAは、コミュニティーの援 ) INFO - speech.speakWithoutPauses (23:47:02): re_last_pause matching(助によりNV Accessが開発しました。 ) INFO - speech.speakWithoutPauses (23:47:02): re_last_pause matching(It is ) INFO - speech.speakWithoutPauses (23:47:02): re_last_pause matching(a fine day. ) INFO - speech.speakWithoutPauses (23:47:02): re_last_pause(a fine day. )() INFO - speech.speakWithoutPauses (23:47:02): re_last_pause matching(It is? ) INFO - speech.speakWithoutPauses (23:47:02): re_last_pause(It is? )() INFO - speech.speakWithoutPauses (23:47:02): re_last_pause matching(a fine day. ) INFO - speech.speakWithoutPauses (23:47:02): re_last_pause(a fine day. )() INFO - speech.speakWithoutPauses (23:48:47): re_last_pause matching(It is ) INFO - speech.speakWithoutPauses (23:48:47): re_last_pause matching(another fine day. Is it ) INFO - speech.speakWithoutPauses (23:48:47): re_last_pause(another fine day. )(Is it ) INFO - speech.speakWithoutPauses (23:48:47): re_last_pause matching(really fine day? ) INFO - speech.speakWithoutPauses (23:48:47): re_last_pause(really fine day? )()
仮に全角マルを re_last_pause に追加しても、音声エンジンには下記のようにコマンドが送られており、 IndexCommand で分割されるために、うまく単語がつながらない。
実は英語に関してもコマンドを実行するタイミングをまとめているだけで、文字列はちゃんとセンテンスごとに結合されていない。
IO - speech.speak (00:04:57): Speaking [IndexCommand(1), IndexCommand(2), LangChangeCommand ('ja'), u'NVDAは、コミュニティーの援', IndexCommand(3), u'助によりNV Accessが開発しました。'] INFO - speech.speakWithoutPauses (00:04:57): re_last_pause matching(It is) INFO - speech.speakWithoutPauses (00:04:57): re_last_pause matching(a fine day.) INFO - speech.speakWithoutPauses (00:04:57): re_last_pause(a fine day.)() IO - speech.speak (00:04:57): Speaking [IndexCommand(4), IndexCommand(5), LangChangeCommand ('ja'), u'It is', IndexCommand(6), u'a fine day.'] INFO - speech.speakWithoutPauses (00:04:57): re_last_pause matching(It is?) INFO - speech.speakWithoutPauses (00:04:57): re_last_pause(It is?)() IO - speech.speak (00:04:57): Speaking [IndexCommand(7), IndexCommand(8), LangChangeCommand ('ja'), u'It is?'] INFO - speech.speakWithoutPauses (00:04:57): re_last_pause matching(a fine day.) INFO - speech.speakWithoutPauses (00:04:57): re_last_pause(a fine day.)() IO - speech.speak (00:04:57): Speaking [IndexCommand(9), LangChangeCommand ('ja'), u'a fine day.'] INFO - speech.speakWithoutPauses (00:04:57): re_last_pause matching(It is) INFO - speech.speakWithoutPauses (00:04:59): re_last_pause matching(another fine day. Is it) INFO - speech.speakWithoutPauses (00:04:59): re_last_pause(another fine day. )(Is it) IO - speech.speak (00:04:59): Speaking [IndexCommand(10), IndexCommand(11), LangChangeCommand ('ja'), u'It is', IndexCommand(12), u'another fine day. '] INFO - speech.speakWithoutPauses (00:04:59): re_last_pause matching(really find day?) INFO - speech.speakWithoutPauses (00:04:59): re_last_pause(really find day?)() IO - speech.speak (00:04:59): Speaking [LangChangeCommand ('ja'), u'Is it', IndexCommand(13), u'really find day?']
finalSpeechSequence を後処理で加工する方法を思いついたので実装してみた:
To git@github.com:nvdajp/nvdajp.git * [new branch] ti33823 -> ti33823
書式設定で「行番号」を読み上げる場合はどうしても単語が繋がらないので、 現状ではサポート対象外とします。
アドオンマネージャーから「アドオンを入手」で Firefox が開いてコミュニティアドオンの ページが読み上げられるときに下記のエラーが出ている:
ERROR - queueHandler.pumpAll (21:20:38): error in generator 4 Traceback (most recent call last): File "queueHandler.pyo", line 72, in pumpAll File "sayAllHandler.pyo", line 128, in readTextHelper_generator File "speech.pyo", line 1016, in speakTextInfo File "speech.pyo", line 1538, in speakWithoutPauses File "speech.pyo", line 1596, in speakWithoutPauses IndexError: string index out of range
正式な nvda_2015.3jp-beta-150731.exe で修正される予定です。
NVDA 2015.3jp-beta-150731
メイン ランドマーク見出し レベル2 リスト 5項目リンク活動報告書
should be separated such as:
メイン ランドマーク 見出し レベル2 リスト 5項目 リンク 活動報告書
Firefox や IE で「リンク」「リストの外」などが直後のコンテンツとつながって読み上げられてしまう問題への暫定的な対策:
To git@github.com:nvdajp/nvdajp.git 8586017..5909fea ti33823 -> ti33823
以下のサイトを読ませたときに、本文の途中にあるリンクが不適切な順番で 読み上げられるという報告がありました。
http://www.mitsue.co.jp/knowledge/blog/a11y/201510/26_2100.html
確認したところ、本件の実装の不備であると分かったので、 いったんこの処理を無効化したいと思います。
2016.3jp に向けてもういちど実装してみる:
jpbeta160624 で本件の新しい実装をマージしました。
Firefox で Web ページを読み上げるときに不具合がないこと、 「リンク」などロールの名前とコンテンツが不適切に繋がらないこと、 書式情報で「行番号の報告」をチェックにした場合も行番号とコンテンツが不適切に繋がらないこと、 メモ帳とワードパッドでだいたい期待通りに改行をはさんだ文字列をつないで読み上げること、 などの確認をしていますが、あまり綺麗な実装ではありません。
特定の状況(例えば全角カタカナの単語の途中で改行された場合など)の接続ができない、 という制約も残っています。
どうしても解決できない不具合がでてきたら、 オプションで今回の処理を無効化できるようにしたいと思います。
以下のような状況で 「スク」「リーンリーダー」 「コンピュ」「ーター」 をつないで読むことができていない。
オペレーティングシステム用の無料でオープンソースのスク リーンリーダーです。 NVDAによって視覚障害者は、合成音 声や点字によるフィードバックを通して、Windowsコンピュ ーターを晴眼者と同じコストで使えるようになります。
後者はルール(ひらがなまたはカタカナと、改行直後の長音記号)を 追加して次のベータ版で改善予定。 前者は(別の状況で副作用があるので)このままとする。
Windows 10 x64 + Internet Explorer 11 で下記のエラーが出る場合がある:
INFO - __main__ (16:53:05): Starting NVDA INFO - core.main (16:53:09): Config dir: C:\Users\nishimotz\AppData\Roaming\nvda INFO - core.main (16:53:11): NVDA version 2016.3jp-beta-160810 INFO - core.main (16:53:11): Using Windows version 10.0.14393 workstation INFO - core.main (16:53:11): Using Python version 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (Intel)] INFO - core.main (16:53:11): Using comtypes version 0.6.2 INFO - synthDrivers.jtalk.mecab.Mecab_initialize (16:53:16): dic: C:\Program Files (x86)\NVDA\synthDrivers\jtalk\dic INFO - synthDrivers.jtalk.mecab.Mecab_initialize (16:53:16): mecab:0.996 nvdajp-jtalk-dic (utf-8) 20160810-071901 INFO - synthDrivers.jtalk.jtalkDriver.initialize (16:53:17): loaded C:\Program Files (x86)\NVDA\synthDrivers\jtalk\mei\mei_happy.htsvoice INFO - synthDriverHandler.setSynth (16:53:17): Loaded synthDriver nvdajp_jtalk INFO - core.main (16:53:17): Using wx version 3.0.2.0 msw (classic) INFO - braille.initialize (16:53:17): Using liblouis version 2.6.5 INFO - braille.BrailleHandler.setDisplayByName (16:53:17): Loaded braille display driver noBraille, current display has 0 cells. INFO - brailleInput.initialize (16:53:17): Braille input initialized WARNING - core.main (16:53:18): Java Access Bridge not available INFO - _UIAHandler.UIAHandler.MTAThreadFunc (16:53:18): UIAutomation: IUIAutomation3 INFO - core.main (16:53:18): NVDA initialized INFO - config.ConfigManager.save (16:54:39): Base configuration saved INFO - synthDrivers.jtalk.jtalkDriver.initialize (16:57:16): loaded C:\Program Files (x86)\NVDA\synthDrivers\jtalk\mei\mei_happy.htsvoice INFO - synthDriverHandler.setSynth (16:57:16): Loaded synthDriver nvdajp_jtalk INFO - synthDrivers.jtalk.jtalkDriver.initialize (16:57:28): loaded C:\Program Files (x86)\NVDA\synthDrivers\jtalk\lite\voice.htsvoice INFO - config.ConfigManager.save (16:57:48): Base configuration saved ERROR - queueHandler.pumpAll (17:04:10): error in generator 23 Traceback (most recent call last): File "queueHandler.pyo", line 72, in pumpAll File "sayAllHandler.pyo", line 123, in readTextHelper_generator File "textInfos\offsets.pyo", line 446, in move File "virtualBuffers\__init__.pyo", line 214, in _getStoryLength WindowsError: [Error 1775] リモート プロシージャ コール中にクライアントからホストに NULL コンテキスト ハンドルが渡されました。 INFO - config.ConfigManager.save (17:15:30): Base configuration saved ERROR - queueHandler.pumpAll (17:17:58): error in generator 57 Traceback (most recent call last): File "queueHandler.pyo", line 72, in pumpAll File "sayAllHandler.pyo", line 149, in readTextHelper_generator File "treeInterceptorHandler.pyo", line 143, in makeTextInfo File "virtualBuffers\__init__.pyo", line 196, in __init__ File "textInfos\offsets.pyo", line 311, in __init__ File "virtualBuffers\__init__.pyo", line 214, in _getStoryLength WindowsError: [Error 1775] リモート プロシージャ コール中にクライアントからホストに NULL コンテキスト ハンドルが渡されました。
「すべて読み上げ」で改行をまたぐ単語を適切に読み上げない問題について、 過去に話し合った記憶はありますがチケットがないようなので、作っておきます。
状況としては以下のように改行がはいった場合の読み上げです:
「こみゅにてぃーのえん」「すけにより」 のように1行目の行末と2行目の行頭の単語がつながりません。
ただし、書式設定で「行番号」を通知するようにしてメモ帳で読み上げると、
のような読み上げになります。
この場合、行1の最後と行2の最初のどちらかで「えんじょ」と読ませてしまってよいのか?
あらゆる条件で破綻がないように実装をするには工夫が必要と思います。