Skip to content

更新 InputWeave.GameInput 重發資產、修正震動保護與重啟前景授權,並重構大型 UI 程式碼 - #79

Merged
perditavojo merged 17 commits into
mainfrom
dev
Sep 27, 2026
Merged

perditavojo merged 17 commits into
mainfrom
dev

Conversation

@perditavojo

Copy link
Copy Markdown
Contributor

摘要

依賴與封裝

  • build(deps):Microsoft.GameInput 3.5.274 → 3.5.278;nuget-license 4.0.17 → 4.0.18。
  • build(gameinput):以 InputWeave.GameInput v0.0.1 重發資產(封裝來源 89b148669ffe58d9927495ed0d89f9997bf4962a)替換 eng/nuget 套件,同步 CI/release workflow 預期 commit、授權檔與 README。實際 SHA256、sidecar 與 GitHub asset digest 一致:3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7。
  • fix(release):nuget-license 加上 -t 列出遞移相依,補上 Microsoft.Extensions.DependencyInjection.Abstractions(MIT)的第三方授權聲明。

修正

  • fix(vibration):熱保護在冷啟動時就會擋掉「複製成功」等重要震動(單次熱成本超過硬上限)。權重改以雙馬達為基準正規化;Normal 優先級單次超出預算時改為降強度送出,只有已過熱才拒絕。
  • fix(vibration):按住方向鍵頂著邊界時,操作失敗回饋(Critical)約每 150ms 自動連發,熱負載累積到硬上限的 5.7 倍。相同 Critical 在 500ms 內重複時改降為 Normal 交由熱保護節流;第一次仍完整送出,不同的 Critical 序列不受影響。
  • fix(restart):程式內重啟不再以 ASFW_ANY 開放所有程序搶前景,改為自行啟動新執行個體並只授權其 PID;授權在舊視窗仍位於前景時完成,並先解除全域快速鍵。

重構(行為不變)

  • refactor(menu):InitializeContextMenu 由 1,454 行依子選單拆為 175 行。
  • refactor(dialogs):NumericInputDialog、PhraseEditDialog、PhraseManagerDialog、GamepadCalibrationDialog 依職責拆成 partial 檔(已逐行比對為純搬移)。
  • refactor(a11y):三份閃爍警示的配色與動畫集中為 FlashAlertAnimator。
  • refactor(selection):三份右搖桿延伸選取邏輯集中為 TextBox 擴充方法。
  • refactor(gamepad):XInput/GameInput 的 EMA 偏移補償係數與公式集中為 GamepadBiasSmoothing。

文件與規範

  • 「Xbox 全螢幕體驗」更名為「Xbox 模式」。
  • 移除延遲與連發註解中容易被誤解為模擬人類操作的措辭。
  • git-commit-safety 明文記載前景視窗返回與 AttachThreadInput 的允許範圍。
  • .editorconfig 依 Microsoft C# 編碼慣例調整 var 規範(型別明顯時允許)。
  • 依 Claude Code 最新官方文件更新 skill 橋接描述與 agent-support 依據。
  • gamepad-api、a11y-safety、core-engineering 補上對應規則。

驗證

  • dotnet build:0 警告、0 錯誤。
  • dotnet test:426 項,415 通過、11 略過(需互動式桌面的 UI 測試),0 失敗。
  • 以 INPUTBOX_RUN_UI_TESTS=1 於互動式桌面執行 MainFormUiSmokeTests:11 項全數通過。
  • 新增測試:RestartProcessLauncherTests、GamepadBiasSmoothingTests、TextBoxSelectionExtensionsTests、FlashAlertAnimatorTests,以及 VibrationSafetyLimiterTests 的「所有內建震動模式冷啟動不被拒絕」與「相同 Critical 連發降級、熱負載不失控」回歸保護。
  • 本機依 release.yml 重建發佈 ZIP:結構檢查通過,內含新版 InputWeave DLL 與完整第三方授權聲明。

硬體驗證

GameInput hardware verification(InputWeave.GameInput 0.0.1 @ 89b1486、Microsoft.GameInput 3.5.278):
- Xbox USB: 通過 (Xbox One 控制器 VID_045E&PID_02EA, USB;拔插 3 次,斷線 0.4–1.1 秒、重連 1.5–2.5 秒內反映,資源無洩漏)
- Xbox Bluetooth: 略過 (測試時僅有 USB 連線)
- Sony / DualSense: 略過 (無可用硬體)
- Nintendo / Switch Pro: 略過 (無可用硬體)
- Elite / Paddle: 略過 (無可用硬體)
- 執行階段缺失 / runtime 載入失敗: 略過 (系統內建 GameInput.dll,無法安全遮蔽)
- Release ZIP: 通過 (本機依 release.yml 重建並驗證結構)

震動實測(同一支控制器,GameInput 回報 4 顆馬達、強度 70%):「複製成功」在修正後正常送出(修正前此組合會被整個擋掉)。Critical 連發節流的修正尚未在實體控制器上確認。

合規

重啟前景授權與前景返回相關變更前,已以瀏覽器即時讀取 FFXIV 繁中版使用者合約、第三方授權聲明,以及宇峻奧汀使用條款、隱私權政策與免責聲明全文。變更僅限本程式自身的重啟、選取計算、震動與視覺回饋,不接觸遊戲程序、不模擬輸入,輸出邊界仍為剪貼簿。

相關

gh-pages 的 footer 第三方授權同步與 Claude 規範更新共 2 個提交,將於本 PR 合併後推送,以維持與 main README 同步。

perditavojo and others added 16 commits September 27, 2026 06:01
- Microsoft.GameInput 由 3.5.274 升級至 3.5.278,與 InputWeave.GameInput 重發資產建置時使用的版本一致。
- 本機工具 nuget-license 由 4.0.17 升級至 4.0.18。
- README 第三方授權段落的 Microsoft.GameInput 線上授權連結同步更新為 3.5.278。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 以 GitHub release v0.0.1(2026-09-26 重發)資產替換 eng/nuget/InputWeave.GameInput.0.0.1.nupkg;實際 SHA256、sidecar 與 GitHub asset digest 皆為 3342051977f6f1b91f2a18acfc224456320264dd67633ed4bc41c8188c9fcdb7。
- nuspec repository commit 為 89b148669ffe58d9927495ed0d89f9997bf4962a,套件內容僅含 net48、net8.0、net10.0 受控組件與 XML 文件,未納入 GameInput redist 或 native shim。
- 同步 CI 與 release workflow 的預期封裝來源 commit、第三方授權聲明、授權附檔、README 與測試 README 的來源與雜湊。
- Upstream 變更涵蓋 callback 與原生資源生命週期修正、SafeHandle 終結器、裝置事件佇列上限、TryGetCurrent 系列與多目標框架;InputBox 無需修改程式碼即可建置並通過既有測試,實機硬體矩陣尚待人工驗證。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Microsoft 已將「Xbox 全螢幕體驗」正式更名為「Xbox 模式」,同步修正相關文字:

- README 常見問題標題改為「從 Xbox 模式切換回 Windows 桌面後,應用程式視窗過大」。
- MainForm 視窗還原與 WindowFocusService 前景切換的程式註解改用「Xbox 模式」,並修正原註解中的錯字;僅調整註解,未變更任何執行行為。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
InputWeave.GameInput 89b1486 重發資產新增相依 Microsoft.Extensions.DependencyInjection.Abstractions 10.0.12(MIT),
該組件會隨發佈檔一併散布,但 release workflow 的 nuget-license 未列出遞移相依,導致 ThirdPartyNotices.txt 缺少其聲明。

- release.yml 的 nuget-license 加上 -t(--include-transitive),完整列出遞移相依套件。
- README 第三方函式庫授權聲明新增 Microsoft.Extensions.DependencyInjection.Abstractions(dotnet/runtime,MIT)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- GaussianDelayHelper 改以「排程抖動」描述,並註明僅用於本程式內部 A11y 廣播避讓時序,不參與任何對其他視窗的輸入或輸出。
- XInput/GameInput 控制器的連發間隔欄位註解原寫「加入生理抖動」,但 GamepadRepeatStateMachine 實際為固定的初始延遲與重複間隔,改為符合實作的描述。

僅調整註解,未變更任何執行行為。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
原本重啟前以 AllowSetForegroundWindow(ASFW_ANY) 讓任何程序都能搶前景,授權範圍大於需要。

- 新增 RestartProcessLauncher,行為對齊 WinForms Application.Restart()(同一執行檔、只轉送第一個之後的引數),改用 ArgumentList 避免引號拼接錯誤,並回傳新程序識別碼。
- RestartApplication 先解除全域快速鍵並釋放 Mutex,趁舊視窗仍在前景時啟動新執行個體,再以其 PID 授權前景;控制器觸發重啟不會產生 Windows 輸入事件,授權必須在關閉視窗前完成。
- 無法啟動新程序時退回原本的 ASFW_ANY 與 Application.Restart() 流程。
- 新增 RestartProcessLauncherTests(4 項),同步更新測試 README 與 core-engineering 規範。

合規:已即時查核 FFXIV 繁中版使用者合約、第三方授權聲明與宇峻奧汀使用條款、隱私權政策、免責聲明;變更僅限本程式重啟自身的前景授權,不接觸遊戲程序、不模擬輸入,輸出邊界仍為剪貼簿。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
原設定全面禁止 var,但與 Microsoft C# 編碼慣例(2026-03 更新)及 .NET Runtime 程式碼風格不一致,測試專案實際也已使用 var 186 處。

- csharp_style_var_when_type_is_apparent 改為 true:型別可由右側直接看出(new、明確轉型)時可使用 var,亦可沿用 target-typed new()。
- 內建型別與其他情況維持明確型別;IDE0008 設為 suggestion,提示型別無法直接看出卻使用 var 的情況,IDE0007 維持 silent,不催促改寫既有明確型別寫法。
- core-engineering 新增 var 使用原則與官方來源連結。

建置維持 0 警告。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
依 2026-09-27 查核的 Claude Code 記憶與 Skills 官方文件:

- 保留 CLAUDE.md 的 @AGENTS.md 匯入:Claude Code 雖可直接讀取 AGENTS.md,但只在沒有 CLAUDE.md 時生效,且部分工作階段無法直接讀取;官方確認此匯入不會重複載入。
- Claude Code 只從 .claude/skills/ 探索 skill,橋接仍屬必要。
- 兩個橋接 skill 的 description 改為先寫主要使用情境,符合官方撰寫建議,提升自動載入判斷。
- agent-support 記錄 Anthropic 查核日期、上述結論與 Agent Skills 標準欄位的可攜性限制。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
熱成本為「振幅² × 持續時間 × 權重」,XInput 權重固定為 2、GameInput 為回報的馬達數量,
單次提示的成本就可能超過硬上限 × 1.05(約 189),Normal 優先級會被直接拒絕。
例如「複製成功」在 XInput 強度 100%,或 GameInput 4 馬達預設強度 70% 時完全不震動。

- 新增 VibrationSafetyLimiter.GetMotorThermalCostMultiplier,以雙主馬達為 1.0 正規化權重,XInput 與 GameInput 共用同一基準。
- Normal 優先級單次請求超出剩餘熱預算時,依剩餘預算降低振幅後送出並標記 ScaledByThermalOverflow;只有降到保底比例以下(已接近過熱)才拒絕。
- 新增測試:倍率正規化、所有內建震動模式在冷啟動下於各強度與馬達數都不被拒絕、單次超預算改為降強度、已過熱時仍會拒絕。
- gamepad-api 規範新增熱成本正規化與回饋不得冷啟動遺失的規則。

震動僅作用於本程式連接的控制器,不涉及遊戲輸入、輸出或按鍵映射。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WindowFocusService 在返回前一個視窗時會暫時以 AttachThreadInput 連結執行緒輸入佇列。
它不送出任何輸入,未違反既有紅線,但未寫明理由容易在日後審查時被誤判。

- 說明返回目標只來自使用者先前的前景視窗,唯一的程序判斷是排除 InputBox 自己,不辨識特定應用程式。
- 列出允許的 Win32 呼叫,並要求 AttachThreadInput 必須在 finally 中解除。
- 明訂此路徑不得加入模擬輸入、輸入訊息、自動貼上或依應用程式身分分流的邏輯。
- 補上程式內重啟只可授權新 InputBox 程序前景的限制。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gamepad-api 要求 XInput 與 GameInput 的 EMA 平滑係數完全相同,但原本兩個後端各自宣告 8 個常數與相同的學習率公式,
一致性只靠文件規則維持,日後改一邊忘了另一邊就會造成行為分歧。

- 新增 GamepadBiasSmoothing,集中 8 個平滑係數與 ComputeAdaptiveSmoothing 公式;已確認兩邊原本數值完全相同,行為不變。
- 兩個後端移除重複常數,只保留與自身數值尺度相關的 BiasAdaptiveErrorRange 與學習閾值。
- 新增 GamepadBiasSmoothingTests(5 項),並更新 gamepad-api 規範與測試 README。

HandleRepeat 的差異僅在按鈕列舉型別與日誌來源,計時已共用 GamepadRepeatStateMachine;
合併剩餘派送程式碼需統一兩個後端的方向型別與基底類別,風險高於收益,本次不處理。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
主視窗、數值輸入對話框與片語編輯對話框各有一份相同的右搖桿延伸選取程式碼:
單字跳轉目標計算(GetWordSelectionCaretTarget)、選取錨點與活動邊緣推算,以及 EM_SETSEL 反向選取後捲動。

- ControlExtensions 新增 GetWordJumpTarget、ResolveSelectionAnchor、SetSelectionWithActiveEdge。
- 三處呼叫端改用擴充方法並移除重複實作;各自的震動、報讀與選取回饋維持不變。
- 移除 MainForm.Gamepad 不再使用的 Interop using。
- 新增 TextBoxSelectionExtensionsTests(6 項),更新測試 README。

僅調整本程式自身文字方塊的選取計算,不涉及對其他視窗的輸入或輸出。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
主視窗、數值輸入對話框與片語編輯對話框各有一份約 150 行的閃爍警示,
其中警示色、純淨底色插值、WCAG 相對亮度前景切換(L≈0.1791)與 1Hz 正弦脈衝/靜態長脈衝退回完全相同。

- 新增 FlashAlertAnimator:GetAlertColor、ComputeFrameColors(純函式)與 RunAsync(光敏安全動畫節奏)。
- 三處呼叫端改用共用實作,只保留各自的套用目標、狀態旗標與結束後還原;深色判斷讀取應用程式層級狀態,改為動畫開始時計算一次與原行為等價。
- 新增 FlashAlertAnimatorTests(7 項),其中驗證整個脈衝過程文字對比皆 ≥4.5:1。
- a11y-safety 規範註明閃爍警示的唯一實作位置,更新測試 README。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
InitializeContextMenu 是整個專案最難維護的單一方法。依選單結構拆成以下私有方法,只搬移程式碼、呼叫順序與原本相同:

- InitializeToggleMenuItems:隱私模式、允許中斷廣播、動畫式視覺警示、返回時最小化。
- CreateHotkeySettingsMenu、CreateSettingsMenu(組裝進階設定)、CreateWindowOperationsMenu、CreateFeedbackMenu、CreateGamepadSettingsMenu。
- InitializePhrasesMenu:片語子選單。
- 跨子選單共用的 AddNumericItem 由區域函式提升為私有方法(只使用參數與實例成員)。
- 以 MemberNotNull 標註初始化方法,讓可空性分析得知欄位已初始化。

InitializeContextMenu 由 1,454 行縮減為 175 行。建置 0 警告;全部測試通過,
另以 INPUTBOX_RUN_UI_TESTS=1 在互動式桌面執行 MainFormUiSmokeTests 11 項全數通過。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NumericInputDialog(2,422 行)、PhraseEditDialog(2,201 行)、PhraseManagerDialog(2,012 行)
與 GamepadCalibrationDialog(1,217 行)比照 MainForm 的分部檔做法拆分,只搬移成員、不改任何邏輯:

- .Layout.cs:DPI 與系統偏好變更、最小尺寸、智慧定位與焦點視覺。
- .Gamepad.cs:控制器事件訂閱、方向與按鍵處理、選取延伸。
- .A11y.cs:報讀、閃爍與驗證回饋。
- 各自特有的分部:NumericInputDialog.AccessibleNumericUpDown、PhraseManagerDialog.Phrases(清單操作)、GamepadCalibrationDialog.Visualizer(校正繪製)。
- 欄位、建構函式與對話框生命週期保留在主檔;PhraseManagerDialog 的 #region 由分部檔取代。
- 各檔只保留實際使用的 using(以 IDE0005 分析移除)。

已比對原檔與拆分後所有檔案的程式碼行,除類別宣告改為 partial、新增檔頭與移除 #region 外完全一致。
建置 0 警告;全部測試通過,MainFormUiSmokeTests 11 項於互動式桌面通過。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
實測按住方向鍵頂著邊界時,操作失敗回饋(Critical,強度 53861、200ms)約每 150ms 觸發一次,
5 秒內連發 25 次;Critical 不受熱溢出拒絕,熱負載累積到硬上限的 5.7 倍,馬達被高強度連續驅動。

- VibrationSafetyLimiter 追蹤最近一次 Critical 請求;相同強度與時長在 500ms 內再次出現時視為自動連發,
  降為 Normal 並標記 DowngradedCriticalRepeat,交由熱保護與占空比節流。視窗隨每次連發延長,停手後恢復為 Critical。
- 第一次失敗回饋仍以 Critical 完整送出;強度或時長不同的 Critical 序列(例如控制器識別)不受影響。
- 新增 3 項測試(連發降級且熱負載不超過第一次脈衝、視窗過後恢復、不同序列不降級),
  並調整 2 項以相同 Critical 快速升溫的既有測試改為間隔送出,維持原測試意圖。
- gamepad-api 規範新增 Critical 連發節流規則,更新測試 README。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 27, 2026 12:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

尚有重啟 Mutex 交接競態、交錯 Critical 節流問題及關鍵啟動路徑測試缺口。

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

此 PR 更新 GameInput 依賴與重發資產,修正震動保護及重啟前景授權,並重構 WinForms/UI 程式碼與測試。

Changes:

  • 更新套件、授權資訊及 CI/release 驗證。
  • 改善震動熱保護與 Critical 連發節流。
  • 重構重啟、選取、動畫、搖桿補償及多個對話框。
  • 新增回歸測試與工程文件更新。
File Description
tests/​InputBox.Tests/​VibrationSafetyLimiterTests.cs 震動安全回歸測試
tests/​InputBox.Tests/​TextBoxSelectionExtensionsTests.cs 文字選取擴充方法測試
tests/​InputBox.Tests/​RestartProcessLauncherTests.cs 啟動資訊測試;尚缺 TryStart 成功與失敗路徑
tests/​InputBox.Tests/​README.md 同步測試清單
tests/​InputBox.Tests/​GamepadBiasSmoothingTests.cs EMA 補償測試
tests/​InputBox.Tests/​FlashAlertAnimatorTests.cs 閃爍動畫測試
src/​InputBox/​MainForm.Gamepad.cs 整合共用選取邏輯
src/​InputBox/​MainForm.Events.cs 整合共用閃爍動畫
src/​InputBox/​MainForm.cs 重啟與前景授權;存在 Mutex 交接競態
src/​InputBox/​InputBox.csproj 更新 Microsoft.GameInput
src/​InputBox/​Core/​Utilities/​GaussianDelayHelper.cs 更新延遲文件
src/​InputBox/​Core/​Services/​WindowFocusService.cs 更新模式文件註記
src/​InputBox/​Core/​Services/​RestartProcessLauncher.cs 新程序啟動與 PID 授權
src/​InputBox/​Core/​Input/​XInputGamepadController.cs XInput 補償與震動倍率
src/​InputBox/​Core/​Input/​VibrationSafetyLimiter.cs 熱保護與 Critical 節流;交錯請求追蹤仍不完整
src/​InputBox/​Core/​Input/​GamepadBiasSmoothing.cs 共用 EMA 補償公式
src/​InputBox/​Core/​Input/​GameInputGamepadController.cs GameInput 補償與震動倍率
src/​InputBox/​Core/​Feedback/​FlashAlertAnimator.cs 集中閃爍動畫
src/​InputBox/​Core/​Extensions/​ControlExtensions.cs 文字選取擴充方法
src/​InputBox/​Core/​Controls/​PhraseManagerDialog.Phrases.cs Phrase Manager phrase 職責拆分
src/​InputBox/​Core/​Controls/​PhraseManagerDialog.Layout.cs Phrase Manager 版面拆分
src/​InputBox/​Core/​Controls/​PhraseManagerDialog.Gamepad.cs Phrase Manager gamepad 邏輯拆分
src/​InputBox/​Core/​Controls/​PhraseManagerDialog.A11y.cs Phrase Manager 無障礙邏輯拆分
src/​InputBox/​Core/​Controls/​PhraseEditDialog.Layout.cs Phrase Edit 版面拆分
src/​InputBox/​Core/​Controls/​PhraseEditDialog.A11y.cs Phrase Edit 無障礙邏輯拆分
src/​InputBox/​Core/​Controls/​NumericInputDialog.Layout.cs Numeric Input 版面拆分
src/​InputBox/​Core/​Controls/​NumericInputDialog.Gamepad.cs Numeric Input gamepad 邏輯拆分
src/​InputBox/​Core/​Controls/​NumericInputDialog.AccessibleNumericUpDown.cs Numeric UpDown 無障礙控制
src/​InputBox/​Core/​Controls/​NumericInputDialog.A11y.cs Numeric Input 無障礙邏輯拆分
src/​InputBox/​Core/​Controls/​GamepadCalibrationDialog.Visualizer.cs 校準視覺化邏輯拆分
src/​InputBox/​Core/​Controls/​GamepadCalibrationDialog.Layout.cs 校準版面拆分
src/​InputBox/​Core/​Controls/​GamepadCalibrationDialog.Gamepad.cs 校準 gamepad 邏輯拆分
README.md 更新術語、依賴與授權說明
eng/​nuget/​InputWeave.GameInput.0.0.1.nupkg.sha256 更新套件雜湊
eng/​nuget/​InputWeave.GameInput_LICENSE.txt 更新來源與授權資訊
docs/​engineering/​git-commit-safety.md 更新重啟與前景視窗規範
docs/​engineering/​gamepad-api.md 更新 gamepad 規範
docs/​engineering/​core-engineering.md 更新核心工程規範
docs/​engineering/​agent-support.md 更新 agent 支援文件
docs/​engineering/​a11y-safety.md 更新無障礙安全規範
.github/​workflows/​release.yml 更新發佈驗證與授權產生
.github/​workflows/​ci.yml 更新套件來源驗證
.editorconfig 調整 C# var 規範
.config/​dotnet-tools.json 更新 nuget-license
.claude/​skills/​update-inputweave-gameinput/​SKILL.md 更新 GameInput skill 文件
.claude/​skills/​inputbox-dev/​SKILL.md 更新開發 skill 文件

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/InputBox/MainForm.cs
回應 PR #79 的 Copilot 審查意見:

1. 重啟時的 Mutex 交接競態
   舊實例原本在啟動新執行個體前就釋放 Mutex,若恰好有另外啟動的 InputBox 在空窗期取得 Mutex,
   重啟出來的實例會喚醒它後自行退出。
   - 舊實例以 --restart-handoff=<舊 PID> 啟動新執行個體,不在啟動前釋放 Mutex,
     改於關閉所有視窗後、Environment.Exit 前於主執行緒明確釋放。
   - 新執行個體依 SingleInstanceHandoff 規則在主執行緒等待並接手 Mutex(最多 10 秒,遺棄的 Mutex 視為接手成功),
     不喚醒既有實例;逾時才退回一般流程。
   - 交接期間另外啟動的執行個體喚醒失敗時,若偵測到重啟請求進行中(RestartActivationCoordinator.HasPendingActivationRequest,不消費標記)則結束,不 fallback 多開視窗。
   - 轉送命令列時移除舊的交接參數,避免連續重啟時累積。無法啟動新程序而退回 Application.Restart 時維持先釋放 Mutex。

2. 交錯的 Critical 可規避連發偵測
   連發判定改為「前一個 Critical 之後 500ms 內的任何 Critical」,不再要求強度與時長相同。

3. 啟動路徑測試缺口
   交接參數解析、啟動動作與 fallback 判斷抽成 SingleInstanceHandoff 純函式並補齊測試。

測試:新增 SingleInstanceHandoffTests(16 項)、RestartActivationCoordinatorTests 與 RestartProcessLauncherTests 各 2 項,
VibrationSafetyLimiterTests 以交錯節流與冷啟動短序列測試取代原「不同序列不降級」測試;共 447 項,436 通過、11 略過。
實測:兩個實例模擬交接時,新實例在舊實例關閉前持續等待、關閉後立即接手(waitMs=2972),全程單一實例;
從選單連續重啟兩次成功,最終只剩一個實例且交接參數未累積。core-engineering 與 gamepad-api 規範同步更新。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@perditavojo
perditavojo merged commit 4aee215 into main Sep 27, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants