NVDAと格闘する
appModulesの中には、それぞれのアプリケーションごとの処理が入ってそう
explorer.pyのevent_UIA_elementSelectedだったら、エクスプローラーでタブが切り替わったときに読み上げる処理とか
braille.なんとかで点字用の処理も行っていそう
なんかaria-errormessageがChromeとFirefoxでサポートされてるっぽいので、読んでみる
a11ysupportにはまだ反映されていなさそう
_get_errorMessage
IAccessibleHandler.RelationType.ERRORがaria-errormessageに対応する
ref: https://www.w3.org/TR/core-aam-1.2/#ariaErrorMessage
Relation: IA2_RELATION_ERROR points to accessible nodes matching IDREFs, if the referenced objects are in the accessibility tree
_getIA2RelationFirstTargetで、最初に見つかったそれを取ってきてる。どこからかは知らない
NVDAHelper.localLib.nvdaInProcUtils_getTextFromIAccessibleでcppのコードを呼び出し、getRelationElementsOfTypeで取り出したerrorTargetからgetTextFromIAccessibleでIAから情報をもらっていそう
source/speech/speech.pyの方を見てみる
一番上の変更差分であるgetObjectPropertiesSpeechから
Objectはおそらく、引数にもらってるobjであるNVDAObjectを示している。こいつが持ってるプロパティを一通りスピーチする関数なのだろう
NVDAObjectはここらへんで定義されてるやつ。PRの説明文にもあるように、今回これにerrorMessageというプロパティが新しく追加されたので、これにさっきの_get_errorMessageしたやつを入れて、読み上げさせる的な感じなのだと考えた
が、_get_errorMessageが他のところで出てこないので、謎
getObjectPropertiesSpeechはすぐ上のspeakObjectPropertiesで使われて返り値がspeechSequenceに入り、speak(speakObjectPropertiesされる
speak関数を追っていくと、SpeechManagerのgetSynth().speak(seq)という箇所にたどり着く。SynthDriverというものを使って音を流しているらしい
もう少しgetObjectPropertiesSpeechを見ていく
name == "errorMessage" and value and State.INVALID_ENTRY not in obj.states
で、後半はまあコメントに書いてあるように、NVDAObjectがaria-validというstateを持っていないときみたいな感じで、nameがなんなのかを見る。
nameはallowedProperties.items()がforで回されていて、allowedPropetiesは引数で渡されている
あとで出てくるので一応書いておくと、ここでnewPropertyValues["errorMessage"] = Noneを設定している
**allowedPropertiesの**ってなんだっけ?ダブルポインタ?と思いつつ、そういえばPythonのspread構文みたいな感じのやつだったことを思い出す
speakObjectPropertiesの引数がそのまま渡されてるっぽいので、speakObjectPropertiesで検索をかけると、例えばsource/browseMode.pyだと以下のような使われ方
speech.speakObjectProperties(
self.rootNVDAObject,
name=True,
states=True,
reason=OutputReason.FOCUS,
)
name=True?nameってstringじゃないの?と思いながらちょっと考えてみた結果、「objで渡されたものの中からkey=Trueであるkeyのみ取得する」という理解になったけど、理屈はよく分からなかった
name=True, states=Trueで渡したらallowedPropertiesは{name: True, states: True}になっちゃうのでは
次にgetPropertiesSpeechの↓を見ていく
errorMessage: str | None = propertyValues.get("errorMessage", None)
getObjectPropertiesSpeechでさっき作ったnewPropertyValuesをgetPropertiesSpeechに渡して、speechSequenceを作っている
さっきNoneを渡してたんだからNoneのような気もするが、getPropertiesSpeechは色んなところで使われているので、今回関係あるところだとここ↓でも使われている
ちょっと上でattrsからerrorMessageを取っているので、ここではちゃんとエラーメッセージが入る可能性がある
attrsはgetControlFieldSpeechが複数使われているgetTextInfoSpeechで定義されていそう
info.getTextWithFieldsから取ったtextWithFieldsの中身であるfieldのfield.fieldをinitialFieldsに入れ、その中身のfieldをnewControlFieldStackに入れ、その中身のfieldをattrsとして使っていそう
そういえば、ファイル検索するときはincludeディレクトリとuser_docsディレクトリをexcludeするといい感じになった
_get_errorMessageがどこで実行されてどのタイミングでerrorMessageプロパティに値が入るのかが分からなかった
AutoPropertyObjectというのだと、_get_から始まるやつの返り値が勝手にプロパティに代入されそう
なんか多分これ以上追ってもしょうがないけど、一応attrsについてもう少し調べたのでまとめ
attrsの型であるControlFieldは、ここ↓に書かれてる通り、table, button, formなど、テキストを包含するcontrolのaccessible nameやroleなどの情報を保有するclassらしい
Dictを継承しているので、先に出てきたようなerrorMessage = attrs.get("errorMessage", None)みたいな処理が可能になっている
newControlFieldStackはList[ControlField]型
textWithFieldsの中身であるfieldがFieldCommandで、そのfield.fieldがinitialFieldsになり、それとnewControlFieldStackの型が同じ
多分どこかでいい感じにNVDAObjectを取ってきて、attrsにしてる
L{Field}みたいな表記ってList[Field]か