當使用者開啟暫時性螢幕簾幕後,如果重開 NVDA(或系統錯誤重啟),外掛會自動在重啟前記錄狀態;並在 NVDA 啟動時自動恢復簾幕,且在恢復後自動清理標記。
當我們重啟 NVDA 時,Python 的整個虛擬機進程會被銷毀並重新建立。這意味著,所有的記憶體變數都會歸零!我們不能用簡單的 self.curtainEnabled = True 來記錄。
我們必須設計一個「跨進程持久化(存入硬碟)」的提示詞架構:
core.triggerNVDAExit 與崩潰重啟的 core.restartUnsafely 函數。由於這是核心系統,我們不能直接改程式,必須指示 AI 採用 Monkeypatching(動態修改/猴子補丁) 技術!NVDAState.ReadPaths.configDir(使用者設定路徑)下,寫入一個名為 screen_curtain_restart_active 的空檔案作為標記。__init__ 中,檢查該檔案是否存在。若存在,立刻刪除該檔案以確保安全,並呼叫 screenCurtain.screenCurtain.enable(persist=False) 自動重新開啟簾幕。請將以下 Prompt 貼給你的 AI:
「你現在是精通 NVDA 核心生命週期與跨進程狀態設計的頂級工程師。請幫我開發一個全域外掛(GlobalPlugin),檔案名為
screen_curtain_restore.py。1. 開發需求描述: - 重啟前攔截 (Monkeypatching):請動態替換(接管)
core.triggerNVDAExit與core.restartUnsafely。在這兩個函數執行前,檢查screenCurtain.screenCurtain.enabled是否為 True。若是,請在globalvars.appArgs.configDir(設定目錄)下建立一個名為screen_curtain_restart_active的暫存標記檔案。 - 重啟後恢復與清理:在GlobalPlugin.__init__中,檢查該標記檔案是否存在。如果存在: - 請立刻刪除該檔案,以防異常殘留。 - 呼叫screenCurtain.screenCurtain.enable(persist=False)開啟簾幕。 - 開發者 Scratchpad 相容性防護(重要):為防止在 Scratchpad 模式下測試拋出找不到附加元件元數據的錯誤,請對addonHandler.initTranslation()加上 try-except 保護,防止 AddonError 導致外掛無法載入。2. 規範限制: - 程式碼必須有非常詳細且給一般人看得懂的中文註釋,逐行解釋猴子補丁與標記檔讀寫的邏輯,讓不懂程式碼的人也能了解。
請直接輸出完整程式碼。」
AI 產出的 screen_curtain_restore.py 結構如下,我們來讀懂這段高級魔法:
import globalPluginHandler
import addonHandler
import core
import screenCurtain
import os
import globalvars
# 1. 開發者 Scratchpad 相容性防禦
# 如果在未打包的暫存區測試,這行會拋錯,所以必須用 try-except 包裹起來保護
try:
addonHandler.initTranslation()
except Exception:
pass
# 定義我們在硬碟中存放「隱私便條紙」的實體路徑
RESTART_MARKER_FILE = os.path.join(globalvars.appArgs.configDir, "screen_curtain_restart_active")
# 2. 備份 NVDA 核心原本的重啟函數
original_triggerNVDAExit = core.triggerNVDAExit
original_restartUnsafely = core.restartUnsafely
# 3. 寫一個我們自己的「攔截版」重啟函數
def patched_triggerNVDAExit(newNVDA=None):
# 如果偵測到使用者是要「重新啟動」而非關機 (newNVDA 不為 None)
# 且當前螢幕簾幕是「開啟的」
if newNVDA and screenCurtain.screenCurtain.enabled:
# 在硬碟中寫下一張「隱私便條紙」(建立暫存標記檔)
try:
with open(RESTART_MARKER_FILE, "w") as f:
f.write("active")
except Exception:
pass
# 最後,把控制權交還給原本的重啟函數,讓 NVDA 正常重啟
original_triggerNVDAExit(newNVDA)
# 4. 猴子補丁:用我們寫的攔截版,替換掉官方原本的函數
core.triggerNVDAExit = patched_triggerNVDAExit
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def __init__(self):
super().__init__()
# 5. 重啟完成!外掛被載入,立刻去硬碟檢查有沒有「隱私便條紙」
if os.path.exists(RESTART_MARKER_FILE):
# 發現便條紙!為維護安全,立刻刪除檔案(撕毀便條紙),避免下次開機誤判
try:
os.remove(RESTART_MARKER_FILE)
except Exception:
pass
# 6. 安全插隊:啟用螢幕簾幕(暫時性模式)
screenCurtain.screenCurtain.enable(persist=False)
core.triggerNVDAExit = new_triggerNVDAExit:這就是 Monkeypatching(猴子補丁)。我們在程式執行時,偷偷把 NVDA 原裝的重啟按鈕換成我們自己改裝的按鈕。當使用者按下重啟,會先執行我們的標記檔寫入,隨後再執行原裝的重啟。os.remove(MARKER_PATH):這叫 「檢索即刪除」。如果重啟後不立刻刪除檔案,萬一未來哪天電腦意外斷電,下次開機時 NVDA 就會誤以為是重啟而強行把螢幕關掉,造成困擾。所以必須用完就撕毀!screen_curtain_restore.py 原始碼如果你是完全沒有寫過程式的新手,這段代碼展示了如何優雅地使用「保險箱標記」與「動態改裝(猴子補丁)」來解決跨重啟的記憶問題。
import 與 try-except)import core:引進 NVDA 的核心控制台。import screenCurtain:引進負責螢幕簾幕(把螢幕變黑)的控制官。try:
addonHandler.initTranslation()
except Exception:
pass
這段程式碼的意思是:「嘗試啟動外掛的語言翻譯機制,但如果因為我們在開發測試區(Scratchpad)執行而失敗了,請**假裝沒事並直接跳過**(pass),不要讓整個程式當掉。」這是極為實用的代碼安全氣囊。MARKER_PATH)MARKER_PATH 定義了硬碟中一個名為 screen_curtain_restart_active 檔案的存放路徑(放在 NVDA 的使用者設定目錄中)。這是著名的 猴子補丁 (Monkeypatching) 技術,像是給原廠車改裝零件:
core.triggerNVDAExit 先存到 original_triggerNVDAExit" 變數裡。new_triggerNVDAExit):
screenCurtain.screenCurtain.enabled)。"1")。original_triggerNVDAExit(newNVDA),完成正常的重啟流程。new_restartUnsafely):應對 NVDA 崩潰重啟的情況,同樣在崩潰前寫入便條紙。core.triggerNVDAExit = new_triggerNVDAExit。用我們改裝好的新按鈕,覆蓋掉 NVDA 內建的按鈕。GlobalPlugin)當 NVDA 重新啟動,會初始化我們的外掛類別 GlobalPlugin:
MARKER_PATH 看看那張秘密便條紙在不在 (os.path.exists)。os.remove)!這是為了防止下一次正常關機後,重新開機時被誤判開啟。screenCurtain.screenCurtain.enable(persist=False) 把螢幕變黑。設定 persist=False 表示這只是「暫時性的遮蔽」,不會把這個狀態寫入使用者的永久設定中。screen_curtain_restore.py 放入 globalPlugins。NVDA+Q 開啟重啟對話框,選擇「重新啟動」。以下題目專為尋求真正硬核觀念與專家級實戰能力的學員設計。題目無法從講義表面抄寫解答,請嘗試獨立思考後再點擊展開解析。
【實戰情境問題】:NVDA 的「螢幕幕簾」功能開啟後,螢幕會變得一片漆黑,但視障使用者仍然能正常操作電腦。這在作業系統圖形渲染層(GDI / Desktop Window Manager, DWM)是如何透過覆蓋黑色全螢幕視窗實施物理防窺的?
【鑑別點說明】:深剖 Windows GDI/DWM 繪圖層、全螢幕 Topmost 視窗與螢幕幕簾安全防護。
【專家級解答與深度剖析】: NVDA 螢幕幕簾透過 Win32 API 建立一個位於最高層級(`WS_EX_TOPMOST`)的黑色的全螢幕無邊框視窗,覆蓋所有顯示器。此外,為了防止黑客透過截圖軟體或外接顯示器竊視,先進的幕簾機制會調用 Win32 `SetWindowDisplayAffinity(WDA_EXCLUDEFROMCAPTURE)`,直接在 Windows 組合管理員 (DWM) 層面將桌面繪圖輸出抹黑。這確保了身旁旁觀者完全看不到螢幕上的敏感個人資料與密碼。
【實戰情境問題】:如果 NVDA 在螢幕幕簾開啟狀態下突然發生 Python 崩潰(Crash),導致螢幕一片漆黑且語音報讀中斷(使用者陷入雙重黑暗與無聲困境),請設計一套外掛層級的「緊急解鎖護城河 (Emergency Uncurtain Guard)」。
【鑑別點說明】:考驗學員對極限故障安全(Fail-Safe Design)與無障礙安全防線的設計能力。
【專家級解答與深度剖析】: 這是無障礙軟體最嚴重的災難情境。防禦護城河設計:1. **Watchdog 獨立狗守護進程**:啟動一個極輕量的 C++/Python 看門狗進程,定期接收 NVDA 的心跳訊號 (Heartbeat);2. **心跳中斷自動銷毀**:若看門狗連續 3 秒未收到心跳(代表 NVDA 崩潰),看門狗立刻強行銷毀幕簾黑幕視窗;3. **緊急硬體熱鍵**:監聽全域硬體按鍵組合(如 `Ctrl + Alt + Shift + Esc`),直接由作業系統層面物理性解除幕簾,保障使用者絕不被困在黑屏中。