解决 NVDA 浏览模式先读角色/状态的插件(内容优先朗读)

大家好,我是沈广荣,今天给大家分享一个我做的小插件,专门解决 NVDA 浏览模式里“先读角色/状态、后读内容”的问题。对中文用户来说,这个顺序会明显拖慢浏览效率,所以我去翻了 NVDA 源码,把顺序做了最小化调整。顺便也把整个过程写下来,分享给大家,下面是分析过程和实现细节。


问题现象

浏览模式移动光标时,NVDA 默认会先报“按钮/链接/可点击”等角色和状态,然后才读正文。中文语序下,这会让信息密度变低,浏览时节奏被打断。


源码分析路径(我怎么定位到问题)

  1. 朗读入口
  • 目录(需先克隆nvda源代码):nvda源代码/source/speech/
  • 核心函数:speech.py 里的 getTextInfoSpeech
  1. 浏览模式的 TextInfo
  • 目录:nvda源代码/source/browseMode.py
  • 浏览模式的文本对象是 BrowseModeDocumentTextInfo
  1. 关键序列来源
  • getTextInfoSpeech 会调用 info.getTextWithFields(formatConfig)
  • 返回值是“文本 + 字段命令”的混合序列(controlStart / controlEnd / formatChange 等)
  1. 顺序产生的原因
  • NVDA 在“进入字段”时就把角色/状态加入 speechSequence
  • 文本被收集到 relativeSpeechSequence,最后拼在后面
  • 所以顺序天然是:角色/状态 → 内容

NVDA 原始逻辑(简要)

  • 构建 controlFieldStack 并与缓存对比,计算公共字段数量
  • 对公共字段 + 新字段调用 getControlFieldSpeech,立即追加到 speechSequence
  • 遍历文本与字段命令,文本追加到 relativeSpeechSequence
  • 最后把文本追加到主序列

结论:角色/状态先读,是它的默认设计


我们的插件怎么做(保持行为一致,只改顺序)

插件文件(插件目录):globalPlugins/contentFirstBrowse.py

核心策略:

  • 几乎完整复制 NVDA 的 getTextInfoSpeech
  • 只改一个点:控制字段的“开始朗读”延迟到正文出现之后
  • 只在“浏览模式 + 光标移动”生效,不影响其他场景

关键代码结构与原因(我尽量会按块说明)

1) 精准生效条件

  • 只对 OutputReason.CARET 生效
  • 只对 BrowseModeDocumentTextInfo 生效
  • 还会检查 passThrough_lastCaretMoveWasFocus

原因:避免影响焦点变化、SayAll、快速导航等行为。


2) 保留缓存与格式配置

  • SpeakTextInfoStateformatConfig 全部沿用原逻辑

原因:这是 NVDA 性能与一致性保证,不能破坏。


3) controlFieldStack 构建保持一致

  • 解析 initialFields 建栈
  • 移除 _startOfNode/_endOfNode
  • 比较旧栈计算 commonFieldCount

原因:这是“进入/退出字段”判断的基础,不能变。


4) 核心改动:延迟字段开始朗读

做法:把“进入字段时要朗读的内容”先放进 pendingStartFields,等正文出现再统一冲刷。

原因:

  • 正文先读,角色/状态后读
  • 只改时机,不改内容
  • 数学内容、可点击状态等仍然保留

5) 文本遍历逻辑保留

  • controlStart / controlEnd / formatChange 处理方式不变
  • 语言切换、缩进、空行提示都保持原有逻辑

原因:只改“顺序”,不改“语义”。


6) 生命周期管理

  • 插件初始化时替换 speechMod.getTextInfoSpeechspeech.getTextInfoSpeech
  • 卸载时恢复原函数

原因:覆盖所有调用路径,且可安全卸载。


小结

这次改动的核心是:延迟控制字段的开始朗读,让正文先出声。其余 NVDA 行为全部保持一致,因此风险可控、兼容性好。

如果你想自己验证源码,可以直接看 nvda源代码/source/speech/speech.pygetTextInfoSpeech,对照插件文件就能看出变化点了。


插件源代码与下载

GitHub 仓库:https://github.com/shenguangrong/contentFirstBrowse

发布包下载:点此下载contentFirstBrowse插件包

标签: 网页浏览, 浏览器, 浏览模式, 文档浏览模式

添加新评论