當使用者按下快捷鍵 NVDA+Shift+I 時,外掛會自動朗讀出「目前的 NVDA 版本」以及「現在的時間」。
當你有一個點子時,絕對不要直接對 AI 說:「幫我寫一個報時的外掛」。這樣含糊的指令會讓 AI 自由發揮,進而寫出充滿 Bug 的程式碼。你必須依照以下三步驟進行拆解:
你要把點子切成三個黃金問題:
1. 觸發時機(什麼時候發動?):我是要按快捷鍵?還是在開啟某個軟體時自動發動?
* 本專案答案:按快捷鍵 NVDA+Shift+I。
2. 資訊來源(我要去哪裡抓資料?):我是要抓時間?抓剪貼簿?還是抓網頁上的按鈕?
* 本專案答案:抓系統時間、抓 NVDA 版本。
3. 動作與回饋(AI 要做什麼?):我是要讓它發出聲音?還是點字顯示?
* 本專案答案:用語音和點字同步讀出來。
這一步是 Vibe Coding 的精髓!我們要用我們前面學到的專有名詞,來限定 AI 的程式碼框架:
* 「按快捷鍵」 ➔ 翻譯成 globalPlugins(全域外掛),並指定使用最新的 @scriptHandler.script 裝飾器來綁定。
* 「抓 NVDA 版本」 ➔ 翻譯成 呼叫 NVDA 的 core.version。
* 「用語音和點字同步讀出來」 ➔ 翻譯成 嚴格使用 ui.message()。
將步驟一與步驟二的結果,組裝成一份結構化的 Prompt 丟給 AI。
請直接複製以下 Prompt 貼給你的 AI 工程師(Antigravity、Claude 或 ChatGPT):
「你現在是一位頂尖的 NVDA 視障輔助軟體外掛工程師。我需要你幫我開發一個名為『系統情報員』的全域外掛。請給我以下兩個檔案的內容:
- 開發需求描述:
- 類型:全域外掛(GlobalPlugin),請在
globalPlugins目錄下建立systemInfo.py。- 觸發方式:使用最新的
@scriptHandler.script裝飾器,將快捷鍵綁定為kb:NVDA+shift+i。- 功能邏輯:當按下快捷鍵時,先獲取 Python 的
datetime.now()取得時間,再獲取 NVDA 核心的core.version取得版本。使用者回饋:請使用
ui.message()進行播報,確保語音與點字同步。嚴格規範限制:
- 請提供
manifest.ini宣告檔內容,name 設定為 systemInfo,最低支援版本 (minimumNVDAVersion) 必須設定為 2026.1。- 程式碼中必須包含清晰的中文註解,解釋每一行程式碼的運作原理,讓不懂寫程式代碼的一般人也能了解。
請直接輸出這兩個檔案的完整程式碼,不需要額外解釋。」
當 AI 產生代碼後,我們該怎麼看懂它呢?這就是第四步!
AI 給你的 systemInfo.py 代碼大致如下(我們來白話看懂它):
# 引入 NVDA 官方提供的全域外掛基礎模組
import globalPluginHandler
# 引入處理快捷鍵綁定的模組
import scriptHandler
# 引入語音與點字輸出的模組
import ui
# 引入 NVDA 核心資訊模組,用來抓版本
import core
# 引入 Python 內建的時間模組
from datetime import datetime
# 建立我們的外掛類別,繼承自官方的全域外掛範本
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
# 使用裝飾器,告訴 NVDA 當使用者按下 NVDA+Shift+I 時,執行底下的函數
@scriptHandler.script(
description="Announces current time and NVDA version", # 快捷鍵的無障礙說明
gestures=["kb:NVDA+shift+i"] # 綁定的實體按鍵
)
def script_announceInfo(self, gesture):
# 1. 抓取現在的時間,並格式化為時與分
currentTime = datetime.now().strftime("%H:%M")
# 2. 抓取當前的 NVDA 版本號
nvdaVersion = core.version
# 3. 組合我們要讀給使用者聽的中文句子
message = f"現在時間是 {currentTime},當前 NVDA 版本為 {nvdaVersion}"
# 4. 呼叫官方 API,讓語音與點字同步報讀
ui.message(message)
class GlobalPlugin(...):這是外掛的「大門」。NVDA 啟動時會來這裡找這個類別。@scriptHandler.script(...):這就是告訴電腦「聽好了!只要使用者按下 NVDA+Shift+I,就立刻執行底下的 def script_announceInfo!」ui.message(message):這是最安全的發聲 API。systemInfoAddon 資料夾。manifest.ini 存檔放入。globalPlugins 資料夾,並將上述 systemInfo.py 放入。scratchpad 中。NVDA+Ctrl+F3 重新啟動 NVDA,然後按下 NVDA+Shift+I 測試!👉 下一堂課:Lecture 15 【基礎專案】剪貼簿淨化大師:結合 NVDA API 與模擬鍵盤
👉 回課程大綱:學習地圖
以下題目專為尋求真正硬核觀念與專家級實戰能力的學員設計。題目無法從講義表面抄寫解答,請嘗試獨立思考後再點擊展開解析。
【實戰情境問題】:當 NVDA 啟動時,它是如何掃描並載入 `globalPlugins` 目錄下的 Python 模組的?為什麼外掛中的 Python 檔案命名為 `__init__.py` 或 `myPlugin.py` 會產生不同的模組導出行為?
【鑑別點說明】:測試學員對 NVDA 外掛架構、Python import 機制與外掛生命週期 (Life Cycle) 的理解。
【專家級解答與深度剖析】: NVDA 在啟動時會讀取所有已安裝外掛的 `manifest.ini` 驗證相容版本,隨後遍歷 `globalPlugins` 目錄。若 `globalPlugins/myAddon/` 下存在 `__init__.py`,Python 會將該目錄視為一個完整的模組包 (Package),並自動實例化其中的 `GlobalPlugin` 類別;若只是單個 `myPlugin.py` 檔案,NVDA 則會直接載入該單一模組。外掛類別必須繼承 `globalPluginHandler.GlobalPlugin`,NVDA 才會在全域環境中監聽其快速鍵與事件。
【實戰情境問題】:在 NVDA 外掛中,如何使用 `@script` 裝飾器將鍵盤組合鍵(如 `NVDA + Shift + Z`)綁定到特定函數?當外掛被停用或 NVDA 關閉時,為什麼必須在 `terminate()` 方法中清理資源?
【鑑別點說明】:考驗學員對 NVDA 快速鍵手勢 (Gestures) 映射與記憶體/執行緒清理的實戰經驗。
【專家級解答與深度剖析】: NVDA 透過 `scriptHandler.script` 裝飾器與 `script_` 前綴函數來識別快速鍵腳本,並在類別內部定義 `__gestures__ = {"kb:nvda+shift+z": "myScript"}` 建立手勢映射。當使用者卸載、停用外掛或重啟 NVDA 時,NVDA 會調用外掛的 `terminate()` 析構方法。若外掛在背景開闢了未關閉的子執行緒、全域 Win32 鉤子 (Hook) 或定時器,而沒有在 `terminate()` 中顯式停止,會導致 NVDA 進程無法正常退出,鎖死 Python DLL 記憶體。