Add LINE version detection and ChatWindow mode support#52
Conversation
Read LINE version and language from local INI files at startup for debugging. Classify the active window as AllInOneWindow (with sidebar) or standalone ChatWindow (no sidebar) so sidebar heuristics are skipped in ChatWindow mode, fixing misidentification of message list items. Add NVDA+Shift+V shortcut to report LINE version and window type. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| parser = configparser.ConfigParser() | ||
| parser.read(iniPath, encoding="utf-8") | ||
| return parser.get("global", "last_updated_version", fallback=None) |
There was a problem hiding this comment.
configparser.ConfigParser 預設對區段名稱(section)不做大小寫折疊(只對選項名稱做 str.lower)。如果 LINE.ini 實際上使用 [Global](首字大寫,Windows INI 慣例),parser.get("global", ...) 將找不到該區段並靜默回傳 None,導致版本號永遠顯示為「未知」。
建議在解析前統一降低區段名稱的大小寫,或遍歷所有區段找到正確的名稱:
| parser = configparser.ConfigParser() | |
| parser.read(iniPath, encoding="utf-8") | |
| return parser.get("global", "last_updated_version", fallback=None) | |
| parser = configparser.ConfigParser() | |
| parser.read(iniPath, encoding="utf-8") | |
| # Try both common casings for the section name | |
| for section in ("global", "Global", "GLOBAL"): | |
| if parser.has_section(section): | |
| return parser.get(section, "last_updated_version", fallback=None) | |
| return None |
Prompt To Fix With AI
This is a comment left during a code review.
Path: addon/appModules/line.py
Line: 60-62
Comment:
**INI 區段名稱大小寫可能不符**
`configparser.ConfigParser` 預設對**區段名稱(section)不做大小寫折疊**(只對選項名稱做 `str.lower`)。如果 LINE.ini 實際上使用 `[Global]`(首字大寫,Windows INI 慣例),`parser.get("global", ...)` 將找不到該區段並靜默回傳 `None`,導致版本號永遠顯示為「未知」。
建議在解析前統一降低區段名稱的大小寫,或遍歷所有區段找到正確的名稱:
```suggestion
parser = configparser.ConfigParser()
parser.read(iniPath, encoding="utf-8")
# Try both common casings for the section name
for section in ("global", "Global", "GLOBAL"):
if parser.has_section(section):
return parser.get(section, "last_updated_version", fallback=None)
return None
```
How can I resolve this? If you propose a fix, please make it concise.|
@greptileai global是小寫 |
|
了解, 不過這與我標記的主要問題無關——第 137–138 行的重複 # 目前(有 bug):
rootCond = handler.clientObject.CreatePropertyCondition(
rootCond = handler.clientObject.CreatePropertyCondition( # ← 這行是多餘的
30003, 50033
)移除重複行後應為: rootCond = handler.clientObject.CreatePropertyCondition(
30003, 50033 # ControlType == Pane
)這個重複行導致 UIA 窗格偵測永遠丟出例外,ChatWindow 的核心判斷邏輯因此完全失效。 |
8d4f5b4 to
e0c0774
Compare
|
@greptileai 要怎麼修正 |
|
在 修正方式是在 這樣一來, |
bef3360 to
e0c0774
Compare
| handler = UIAHandler.handler | ||
| if handler: | ||
| walker = handler.clientObject.RawViewWalker | ||
| rootCond = handler.clientObject.CreatePropertyCondition( | ||
| 30003, 50033 # ControlType == Pane | ||
| ) | ||
| rootEl = handler.clientObject.ElementFromHandle(hwnd) | ||
| if rootEl: | ||
| panes = rootEl.FindAll(2, rootCond) # TreeScope.Children=2 | ||
| paneCount = panes.Length if panes else 0 | ||
| if paneCount >= 2: | ||
| windowType = "allinone" | ||
| else: | ||
| # Single pane or no panes — could be ChatWindow | ||
| # at larger size | ||
| windowType = "allinone" if winWidth >= 700 else "chat" | ||
| except Exception: | ||
| # Fallback: wide window is likely AllInOneWindow | ||
| windowType = "allinone" |
There was a problem hiding this comment.
handler 或 rootEl 為 None 時寬視窗被誤分類為 "unknown"
當 UIAHandler.handler 為 None(UIA 尚未就緒)或 ElementFromHandle 返回 None 時,對應的 if 分支直接被跳過,不會觸發 except Exception,因此 windowType 維持初始值 "unknown"。
對於寬度 ≥ 600px 的視窗,開發者的意圖是回退到 "allinone"(如 except 分支的注釋所示)。但 handler is None 或 rootEl is None 這兩個路徑繞過了 except,直接讓 windowType = "unknown" 被快取。後續 _isChatWindowMode() 回傳 False,導致 _queryAndSpeakUIAFocus 中 ChatWindow 的訊息項目回退到位置像素判斷,isMessageItem 永遠為 False,copy-first 讀取功能失效。
建議明確處理 None 路徑:
handler = UIAHandler.handler
if handler:
rootCond = handler.clientObject.CreatePropertyCondition(
30003, 50033 # ControlType == Pane
)
rootEl = handler.clientObject.ElementFromHandle(hwnd)
if rootEl:
panes = rootEl.FindAll(2, rootCond)
paneCount = panes.Length if panes else 0
if paneCount >= 2:
windowType = "allinone"
else:
windowType = "allinone" if winWidth >= 700 else "chat"
else:
windowType = "allinone" if winWidth >= 700 else "chat"
else:
windowType = "allinone"Prompt To Fix With AI
This is a comment left during a code review.
Path: addon/appModules/line.py
Line: 135-153
Comment:
**`handler` 或 `rootEl` 為 `None` 時寬視窗被誤分類為 `"unknown"`**
當 `UIAHandler.handler` 為 `None`(UIA 尚未就緒)或 `ElementFromHandle` 返回 `None` 時,對應的 `if` 分支直接被跳過,不會觸發 `except Exception`,因此 `windowType` 維持初始值 `"unknown"`。
對於寬度 ≥ 600px 的視窗,開發者的意圖是回退到 `"allinone"`(如 `except` 分支的注釋所示)。但 `handler is None` 或 `rootEl is None` 這兩個路徑繞過了 `except`,直接讓 `windowType = "unknown"` 被快取。後續 `_isChatWindowMode()` 回傳 `False`,導致 `_queryAndSpeakUIAFocus` 中 ChatWindow 的訊息項目回退到位置像素判斷,`isMessageItem` 永遠為 `False`,copy-first 讀取功能失效。
建議明確處理 `None` 路徑:
```python
handler = UIAHandler.handler
if handler:
rootCond = handler.clientObject.CreatePropertyCondition(
30003, 50033 # ControlType == Pane
)
rootEl = handler.clientObject.ElementFromHandle(hwnd)
if rootEl:
panes = rootEl.FindAll(2, rootCond)
paneCount = panes.Length if panes else 0
if paneCount >= 2:
windowType = "allinone"
else:
windowType = "allinone" if winWidth >= 700 else "chat"
else:
windowType = "allinone" if winWidth >= 700 else "chat"
else:
windowType = "allinone"
```
How can I resolve this? If you propose a fix, please make it concise.|
繼續修正有bug,暫時先這樣 |
Summary
LINE.ini,installLang.ini) at addon startup for debugging and diagnostic loggingChanges
New Functions
_getLineDataDir()— Locate LINE data directory_readLineVersion()— Extract version from LINE.ini_readLineLanguage()— Extract language from installLang.ini_classifyLineWindow()— Detect AllInOneWindow vs ChatWindow mode with caching_isChatWindowMode()— Helper to check if current window is ChatWindowImproved Logic
_isInChatListContext()— Skip sidebar checks in ChatWindow mode_findChatListFromWindow()— Return early if in ChatWindow (no sidebar to search)_queryAndSpeakUIAFocus()— Treat all ListItems as message items in ChatWindow modeAppModule Updates
script_reportLineInfo()(NVDA+Shift+V) to announce version, language, and window typeTest Plan
🤖 Generated with Claude Code
Greptile Summary
此 PR 為 LINE Desktop NVDA 附加元件新增 LINE 版本與語言的診斷性讀取(從本地 INI 檔案)、視窗類型分類(AllInOneWindow 與 ChatWindow),以及 NVDA+Shift+V 診斷快捷鍵。ChatWindow 模式下側邊欄相關啟發式判斷也會提前返回或改用更合適的邏輯。
主要變更摘要:
_getLineDataDir()、_readLineVersion()、_readLineLanguage()以讀取 LINE 安裝資訊作為診斷用途_classifyLineWindow()以寬度啟發式 + UIA 窗格計數判斷視窗類型,並快取 2 秒_isInChatListContext、_findChatListFromWindow、_queryAndSpeakUIAFocus中加入 ChatWindow 模式早期返回路徑AppModule.__init__快取版本與語言,並新增script_reportLineInfo(NVDA+Shift+V)尚待處理的問題: 多個前次審查所提問題目前仍存在於程式碼中(
walker未使用、TreeScope.Children深度不足、寬 ChatWindow 回退誤判、INI 區段名稱大小寫)。此外本次審查發現:當UIAHandler.handler為None或ElementFromHandle回傳None時,寬視窗的windowType會維持"unknown"而非回退到"allinone",導致 copy-first 讀取功能在邊緣情況下失效。Confidence Score: 2/5
PR 的核心 ChatWindow 分類邏輯存在已知與新發現的準確性問題,視窗分類在特定情況下會退化,主要功能尚未穩定。
多個來自前次審查的 P1 問題(INI 區段大小寫、UIA 搜尋深度不足、寬 ChatWindow 回退誤判)仍存在於程式碼中未獲解決,加上本次新發現的 handler/rootEl 為 None 時 windowType 維持 unknown 的邏輯缺口,使視窗分類在邊緣情況下無法正確觸發 ChatWindow 路徑。
addon/appModules/line.py:特別關注 _classifyLineWindow() 中的 handler/rootEl None 路徑處理(第 135–153 行)
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[_classifyLineWindow 被呼叫] --> B{快取命中?} B -- 是 --> C[返回快取結果] B -- 否 --> D[GetWindowRect 取得 winWidth] D --> E{winWidth >= 600?} E -- 否 --> F[windowType = chat] E -- 是 --> G{UIAHandler.handler 非 None?} G -- 否 --> H[windowType 維持 unknown] G -- 是 --> I[ElementFromHandle 取得 rootEl] I --> J{rootEl 非 None?} J -- 否 --> K[windowType 維持 unknown] J -- 是 --> L[FindAll Pane 取得 paneCount] L --> M{paneCount >= 2?} M -- 是 --> N[windowType = allinone] M -- 否 --> O{winWidth >= 700?} O -- 是 --> P[windowType = allinone] O -- 否 --> Q[windowType = chat] H --> R[快取結果] K --> R F --> R N --> R P --> R Q --> RPrompt To Fix All With AI
Reviews (7): Last reviewed commit: "Add LINE version detection and ChatWindo..." | Re-trigger Greptile