當一個專案同時包含「系統級底層攔截」與「GUI 視覺畫面設計」時,你不能再用口語聊天的方式對 AI 許願。你必須使用 CO-STAR 框架,將需求結構化地封裝起來:
請將以下這張黃金派工單,整段複製並貼給你的 AI:
「[Context 背景脈絡] 你現在是一位頂尖且極度嚴謹的 NVDA 視障輔助軟體外掛工程師。我們正在為最新的 NVDA 2026.1 進行開發。
[Objective 任務目標] 請幫我編寫一個名為
passwordMute.py的全域外掛(GlobalPlugin),放在globalPlugins下。 功能 1:請使用底層語音過濾技術,只要焦點是密碼框,就封殺語音朗讀,保護隱私。 功能 2:請提供一個原生 GUI 設定面板,讓使用者可以打勾開啟或關閉防窺功能。[Style & Tone 開發規範與態度(請嚴格遵守 NVDA 官方指南)] 1. 【語音過濾】:請在
__init__中使用speech.filter_speechSequence.moveToEnd(self.filter_password, last=False)註冊過濾器,確保排序在最優先。 2. 【焦點判斷】:在過濾函數filter_password中,使用api.getFocusObject()判斷,若obj.role == controlTypes.Role.PASSWORD且設定為開啟,則直接return []清空語音,否則正常放行。 3. 【GUI 面板】:請繼承gui.settingsDialogs.SettingsPanel建立設定視窗,使用gui.guiHelper.BoxSizerHelper來生成wx.CheckBox打勾框。 4. 【設定儲存】:請將打勾狀態保存到 NVDA 原生的config.conf["passwordMute"]["enabled"]中。 5. 【註釋要求】:代碼中必須包含清晰的中文註釋,解釋每一行程式碼的運作原理,讓不懂寫程式代碼的一般人也能了解。[Audience 目標受眾] 你的程式碼將被視障者與 Vibe Coding 導演直接使用,請確保介面與代碼邏輯簡單清晰、完全支援螢幕閱讀器朗讀。
[Response 輸出格式] 請直接給我這支
passwordMute.py的完整 Python 原始碼,不需多餘的解釋,只要可以直接執行的程式碼。」
這份大師級外掛代碼非常精美。我們跟著 Ray,一行行看懂它是如何掌控語音與介面的:
# 引入全域外掛基礎模組
import globalPluginHandler
# 引入核心 API
import api
# 引入控制項角色定義
import controlTypes
# 引入語音模組
import speech
# 引入設定管理模組,用來讀寫 config.conf
import config
# 引入 wxPython 視窗控制庫
import wx
# 引入 NVDA 原生設定面板與版面配置輔助工具
import gui
from gui.settingsDialogs import SettingsPanel
# 1. 向 NVDA 的設定系統註冊我們外掛的專屬欄位與預設值
# 預設為啟用防窺 (enabled=True)
config.conf.spec["passwordMute"] = {
"enabled": "boolean(default=True)"
}
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self):
super().__init__()
# 2. 註冊我們的語音過濾器函數
speech.filter_speechSequence.register(self.filter_password)
# 3. 將我們的過濾器移到整個過濾鏈的最前面,保證第一個攔截
speech.filter_speechSequence.moveToEnd(self.filter_password, last=False)
# 這是語音過濾器的核心。每次 NVDA 要說話前,都會把要說的文字(speechSequence)丟進來
def filter_password(self, speechSequence):
# 取得目前使用者的焦點物件
obj = api.getFocusObject()
# 檢查設定檔中防窺功能是否為啟用狀態
isEnabled = config.conf["passwordMute"]["enabled"]
# 4. 如果焦點物件的角色是「密碼框」,且防窺功能是有開啟的
if obj and obj.role == controlTypes.Role.PASSWORD and isEnabled:
# 直接回傳一個空的列表!這會把所有原本要唸出來的字母直接消音!
return []
# 如果不是密碼框,或者防窺功能關閉了,就原封不動放行,正常朗讀
return speechSequence
# 5. 建立我們的設定面板類別,繼承自官方的原生面板
class PasswordMuteSettingsPanel(SettingsPanel):
# 設定面板的標題
title = "密碼防窺外掛設定"
# 用來繪製畫面的函數
def makeSettings(self, settingsSizer):
# 建立一個自動對齊與排版的助手
helper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer)
# 建立一個打勾框,文字為「啟用密碼框自動靜音功能」
self.chkEnabled = helper.addItem(wx.CheckBox(self, label="啟用密碼框自動靜音功能"))
# 將目前設定檔裡的數值,自動填入這個打勾框中(如果是 True 就打勾,False 就不打勾)
self.chkEnabled.SetValue(config.conf["passwordMute"]["enabled"])
# 當使用者在設定面板按下「確定」或「套用」時執行
def onSave(self):
# 將打勾框目前的狀態,儲存回 NVDA 原生的設定檔中,完成永久保存!
config.conf["passwordMute"]["enabled"] = self.chkEnabled.GetValue()
config.conf.spec:這告訴 NVDA 在 config.conf 設定檔裡開闢一小塊專屬空間。這樣一來,外掛重啟或電腦關機後,使用者的打勾設定依然會被永久記住!return []:這是過濾器的絕招。speechSequence 是一個要被送去語音引擎的「火車清單」,回傳 [] 就等於把整台火車的貨物丟掉,語音引擎收不到貨,自然保持絕對安靜!passwordMute.py 放進 globalPlugins。NVDA+N 開啟選單 -> 偏好設定 -> 設定。👉 下一堂課:Lecture 19 【實戰演練六】Browse Mode 網頁快鍵導航 (clickable_nav)
👉 回課程大綱:學習地圖
以下題目專為尋求真正硬核觀念與專家級實戰能力的學員設計。題目無法從講義表面抄寫解答,請嘗試獨立思考後再點擊展開解析。
【實戰情境問題】:在外掛中彈出一個設定對話框(`wx.Dialog`)時,如果使用 `dialog.Show()` 而非 `dialog.ShowModal()`,會引發什麼無障礙焦點逃逸 (Focus Escape) 問題?
【鑑別點說明】:考驗學員對 GUI 模態視窗與螢幕報讀器焦點捕獲的無障礙實踐。
【專家級解答與深度剖析】: `Show()` 彈出的是非模態視窗,主視窗依然可以接收鍵盤事件。當視障使用者按 Tab 鍵切換焦點時,焦點可能會跳出對話框外,進入背後不可見的主視窗或桌面上(焦點逃逸)。這會讓視障使用者徹底迷失方向,不知道自己身在何處。而 `ShowModal()` 會開啟事件卡位,強制將鍵盤焦點與事件循環鎖定在對話框內部,直到使用者按下「確定」或「取消」關閉視窗為止。
【實戰情境問題】:當外掛需要從包含 10,000 個節點的複雜 UI 樹中,過濾出所有帶有 `aria-invalid="true"` 的不合格表單元件時,如果採用遞迴深度優先搜尋 (DFS),會面臨什麼性能瓶頸?如何優化?
【鑑別點說明】:測試學員在無障礙 DOM 樹遍歷時演算法時間複雜度 $O(N)$ 的優化意識。
【專家級解答與深度剖析】: 對 10,000 個 Win32/UIA 跨進程物件進行逐個 DFS 遞迴,每一次物件屬性存取(如 `obj.role`)都會引發一次昂貴的 IPC(進程間通訊)RPC 呼叫,總耗時可高達數秒,導致 NVDA 卡死。優化策略:1. **利用 UIA Cache Request**:在一次 RPC 呼叫中批量拉回子樹的所有屬性快照;2. **樹剪枝 (Tree Pruning)**:在遍歷時檢查子樹根節點,若該區域不包含表單(如 `