修正被 VS Code 蓋住:定期重新宣告置頂
摘要: 每 2 秒重新宣告一次置頂,並在螢幕配置變動與啟動後各補一次。 根本原因: Windows 會把視窗踢出 topmost band,卻留著 WS_EX_TOPMOST 樣式位元。 以 Win32 檢查實際情況:寵物視窗的 exStyle 是 0x08280028(含 WS_EX_TOPMOST), 但 z-order 排在 Z=4,而兩個 TOPMOST=false 的 VS Code 視窗排在 Z=1 與 Z=2, 也就是它們蓋在寵物上面。Electron 這邊仍以為自己是置頂的, setAlwaysOnTop 已經在建立視窗時與勾選選單時都設過,所以不會自己修好。 影響: 寵物被 VS Code 之類的一般視窗蓋住,只能重啟或重新勾一次選單的「永遠置頂」。 修法: - 新增 reassertTopmost():setAlwaysOnTop(true, "screen-saver") 之後再呼叫 moveTop()。 單靠 setAlwaysOnTop 不夠——狀態沒變時它可能不會真的呼叫 SetWindowPos; moveTop() 會強制 SetWindowPos,對 WS_EX_TOPMOST 的視窗即為插回 topmost band 最上面。 視窗是 WS_EX_NOACTIVATE + focusable:false(已用 Win32 確認),不會搶焦點。 - 每 TOPMOST_REASSERT_MS(2000)呼叫一次;display-metrics-changed / added / removed 也各接一次,因為螢幕配置變動最容易觸發降級。 - ready-to-show 的 showInactive 後補一次;選單勾選置頂時也補一次。 - 拖曳中(dragTimer 存在)跳過,避免和每 16 ms 的位置更新打架。 - 結束時清掉 timer。 驗證: - 先從外部對執行中的視窗呼叫 SetWindowPos(HWND_TOPMOST) 確認這正是有效解: 寵物由 Z=4 移到 Z=0,兩個 VS Code 視窗退到 Z=5、Z=6。 - 再以改好的版本實測守護行為,用 SetWindowPos(HWND_BOTTOM) 模擬 Windows 的降級: 基準 petZ=0 TOPMOST=true 上方 0 個;強制降級後 petZ=17 TOPMOST=false 上方 4 個 (VS Code 兩個、CM 等);1 秒後回到 petZ=0 TOPMOST=true 上方 0 個;3 秒後維持。 - 以 ELECTRON_RUN_AS_NODE 讀打包後 app.asar,確認版本 2.0.8 與八項改動都在出貨檔案裡。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -243,6 +243,7 @@ Claude Code ──hook(stdin JSON)──▶ hook/claude-pet-hook.js ──PO
|
||||
|
||||
- **點穿**:視窗預設 `setIgnoreMouseEvents(true, { forward: true })`,renderer 讀 canvas 該點的 alpha(或是否壓在氣泡上)來即時切換,所以透明處永遠點得到底下的視窗。判定的座標有兩個來源:renderer 自己的 mousemove,以及**主程序每 50 ms 的游標輪詢**。後者是必要的——視窗處於點穿狀態時 Electron 的 `forward` 不保證會把 mousemove 轉發進來(游標直接跳到寵物上常常收不到),只靠 mousemove 會在「游標還停在寵物身上時進入點穿」之後再也收不到事件,變成永遠卡在點穿、按不下去也拖不動。另外每一格畫完也會用最後已知座標重驗一次,因為換格會改變游標底下的像素。
|
||||
- **拖曳**:由主程序用 `screen.getCursorScreenPoint()` 每 16 ms 更新視窗位置,游標離開視窗也不會掉;方向由水平位移決定。
|
||||
- **置頂要定期重新宣告**:Windows 有時候會把視窗踢出 topmost band,卻留著 `WS_EX_TOPMOST` 樣式位元——從外部檢查看到 `TOPMOST=true`,但 z-order 排在一般視窗(例如 VS Code)之下,寵物就被蓋住,而 Electron 這邊仍以為自己是置頂的,不會自己修好。所以每 2 秒重新宣告一次,並在螢幕配置變動時立刻補一次。`setAlwaysOnTop` 在狀態沒變時可能不會真的呼叫 `SetWindowPos`,因此再補一個 `moveTop()` 強制插回 topmost band 最上面;視窗是 `WS_EX_NOACTIVATE` + `focusable: false`,不會搶焦點。
|
||||
- **行為邏輯以 Codex 為準**,細節見[與 Codex 的對照](#與-codex-的對照)。
|
||||
- **顯示尺寸與 sprite 來源尺寸分開**:`CELL_W/CELL_H`(192 × 208)只用來從 spritesheet 取格子,畫到畫面上的是 `PET_W/PET_H`(126 × 137,Codex 的 mascot 尺寸)。視窗寬度另有 `MIN_WIN_W = 240` 的下限,免得寵物變小後氣泡被截掉。
|
||||
- **Spritesheet 以 data URL 傳給 renderer**,避免 `file://` 跨來源污染 canvas 導致 `getImageData` 失敗。
|
||||
|
||||
Reference in New Issue
Block a user