TreeInterceptor 掃描網頁上的核取方塊。今天,我們要介紹一個真實開發出來的外掛案例:『網頁可點擊元素導航 (clickable_nav)』!」H 跳到標題,按 B 跳到按鈕。但在現代網頁裡,很多工程師不用傳統按鈕,而是把普通的文字加上 onclick 變成『可以點擊的元素』。NVDA 內建沒有快捷鍵可以跳轉到這些元素。所以,這個外掛實作了:按下 Z 或 Shift+Z,就能直接跳到網頁中下一個或上一個『可點擊 (Clickable)』的隱藏按鈕!」如果我們打開這個外掛的原始碼(clickable_nav/__init__.py),我們會看到幾個高階大師技巧。我們不改代碼,但我們要學會「看懂」它為什麼這樣寫!
網頁跳轉只有在瀏覽器中才有意義。代碼中有一段安全判斷:
vbuf = getattr(api.getFocusObject(), 'treeInterceptor', None)
if not vbuf or not vbuf.isAlive:
return gesture.send()
這段話的意思是:「如果你現在不在網頁虛擬緩衝區 (TreeInterceptor),那這個快捷鍵 Z 就不歸我管,請把按鍵 send() 還給 Windows,讓使用者可以正常打出英文字母 Z。」這就是我們說過的安全邊界!
怎麼在茫茫網頁中找到「可以點擊」的東西?
外掛寫了三個搜尋條件 (search_options):
1. states 包含 CLICKABLE:NVDA 認定的可點擊狀態。
2. clickable 屬性為 True。
3. IAccessibleAction_click:這是底層的無障礙點擊行為。
AI 透過這三個條件,呼叫 vbuf._iterNodesByAttribs,瞬間在虛擬樹中搜出下一個目標,並將游標移過去 (item.moveTo())!
如果你想要 AI 幫你重頭寫出這個外掛,你的 Prompt 該怎麼下?
「你現在是頂尖的 NVDA 外掛工程師。請幫我寫一個全域外掛,實現網頁中的『可點擊元素單鍵導航』。
開發規範: 1. 請使用
@scriptHandler.script綁定快捷鍵Z(下一個) 與Shift+Z(上一個)。 2. 【安全檢查】:執行前,先獲取api.getFocusObject().treeInterceptor。如果不在 Browse Mode,請使用gesture.send()將按鍵放行給系統。 3. 【元素搜尋】:請使用vbuf._iterNodesByAttribs向下或向上搜尋。搜尋條件必須涵蓋controlTypes.State.CLICKABLE狀態、clickable屬性,以及具備IAccessibleAction_click動作的節點。 4. 找到後,請呼叫節點的moveTo()與report()來移動焦點並朗讀。找不到則用語音提示。請給我完整的
__init__.py程式碼。」
透過閱讀 clickable_nav 的代碼,我們學到了非常實用的技巧:在寫全域外掛時,如果你的快捷鍵是普通字母(如 Z),請務必在判斷條件不符時,呼叫 gesture.send() 放行按鍵。否則你的 NVDA 會把你鍵盤上的 Z 鍵永遠吃掉,讓你再也打不出 Z!
👉 下一堂課:Lecture 20 【實戰演練七】進階語音過濾與正則運算 (brlReader)
👉 回課程大綱:學習地圖
以下題目專為尋求真正硬核觀念與專家級實戰能力的學員設計。題目無法從講義表面抄寫解答,請嘗試獨立思考後再點擊展開解析。
【實戰情境問題】:許多前端開發者喜歡用 `
【鑑別點說明】:深剖 HTML 語意化 (Semantic HTML) 與鍵盤可存取性 (Keyboard Accessibility)。
【專家級解答與深度剖析】: `
【實戰情境問題】:當 NVDA 外掛找到一個可點擊元件並嘗試對其觸發點擊時,`obj.doDefaultAction()` 與 `win32api.SetCursorPos() + mouse_event()` 有何本質差異?
【鑑別點說明】:測試學員對無障礙程式化動作 (API Action) 與物理滑鼠模擬 (Hardware Mouse Event) 的差異理解。
【專家級解答與深度剖析】: `obj.doDefaultAction()` 是呼叫無障礙 API 的程式化動作(如發送 UIA Invoke Pattern),不需要移動實體滑鼠指標,速度極快且不影響使用者螢幕游標。但如果目標網頁是用極度不規範的 JavaScript 監聽物理 `mousedown` 事件,API 動作可能會失效。此時外掛必須降級採用物理模擬:透過 `obj.location` 取得元件的螢幕幾何座標,將滑鼠游標物理移動至該座標中心並發送位元組點擊訊號。