Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
- **步驟三:在遊戲中按貼上組合鍵**
- 回到《FINAL FANTASY XIV 繁體中文版》遊戲後,在遊戲內的聊天輸入框按下遊戲中預設的貼上組合鍵(需先於遊戲設定中啟用),貼上剛才複製的文字,最後送出即可。

**補充說明**:這是一套半自動、手動觸發的聊天輔助流程,重點在於穩定輸入與快速貼上
**補充說明**:這是一套手動觸發的文字暫存與剪貼簿中轉流程,重點在於穩定輸入;實際貼上與送出仍由使用者在遊戲中自行操作

### 1. 鍵盤操作 ⌨️

Expand Down
5 changes: 3 additions & 2 deletions docs/engineering/git-commit-safety.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@
## 5. 法律合規工作流
1. 若任務涉及「按鍵處理」、「剪貼簿自動化」或「控制器映射」。
2. 使用對應代理可用的網頁抓取工具訪問上述連結(例如 Copilot:`fetch_webpage`;Gemini:`web_fetch`)。
3. 比對異動是否符合「非自動化」、「非模擬」原則。
4. 在計畫書 (/plan) 中聲明合規性分析結果。
3. 若條款頁面僅回傳 JavaScript shell 或無法直接取得條款本文,必須改用可執行 JavaScript 的瀏覽器工具、官方網站中可抓取的同等條款頁,或明確記錄「未能擷取完整本文」並停止進行高風險核心輸入/輸出異動。
4. 比對異動是否符合「非自動化」、「非模擬」原則。
5. 在計畫書 (/plan) 或交付摘要中聲明合規性分析結果。
6 changes: 3 additions & 3 deletions docs/engineering/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@

```powershell
# 從 repo 根目錄執行
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj
dotnet test --project tests/InputBox.Tests/InputBox.Tests.csproj

# 加入詳細輸出
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj --logger "console;verbosity=detailed"
dotnet test --project tests/InputBox.Tests/InputBox.Tests.csproj --logger "console;verbosity=detailed"

# 收集 Code Coverage(MTP 原生模式,同 CI)
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj -c Release --no-build `
dotnet test --project tests/InputBox.Tests/InputBox.Tests.csproj -c Release --no-build `
--coverage `
--coverage-output-format cobertura `
--coverage-output coverage.cobertura.xml
Expand Down
6 changes: 6 additions & 0 deletions tests/InputBox.Tests/DialogLabelStabilityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ namespace InputBox.Tests;
/// </summary>
public sealed class DialogLabelStabilityTests
{
/// <summary>
/// 片語編輯對話框的名稱與內容計數標籤應使用固定寬度,避免文字長度變動造成版面抖動。
/// </summary>
[Fact]
public void PhraseEditDialog_CountLabels_UseFixedWidth()
{
Expand All @@ -25,6 +28,9 @@ public void PhraseEditDialog_CountLabels_UseFixedWidth()
Assert.True(contentCount.MinimumSize.Width > 0);
}

/// <summary>
/// 片語管理對話框的片語數量標籤應使用固定寬度,避免數量變動時推擠其他控制項。
/// </summary>
[Fact]
public void PhraseManagerDialog_CountLabel_UsesFixedWidth()
{
Expand Down
27 changes: 27 additions & 0 deletions tests/InputBox.Tests/GamepadCalibrationVisualizerMapperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public void ClampNormalized_RestrictsToVisibleRange(float input, float expected)
Assert.Equal(expected, actual, 3);
}

/// <summary>
/// 死區半徑應依完整軸向範圍換算成正規化比例,避免校準圖縮放錯誤。
/// </summary>
[Fact]
public void CalculateDeadzoneRadius_UsesFullScaleRatioAndClamps()
{
Expand All @@ -31,6 +34,9 @@ public void CalculateDeadzoneRadius_UsesFullScaleRatioAndClamps()
Assert.InRange(actual, 0.07f, 0.08f);
}

/// <summary>
/// 死區值超過完整軸向範圍時應夾至最大半徑,避免繪製超出校準圖邊界。
/// </summary>
[Fact]
public void CalculateDeadzoneRadius_WhenInputExceedsFullScale_ReturnsOne()
{
Expand All @@ -39,6 +45,9 @@ public void CalculateDeadzoneRadius_WhenInputExceedsFullScale_ReturnsOne()
Assert.Equal(1.0f, actual, 3);
}

/// <summary>
/// 控制器已連線的廣播文字應包含裝置名稱,且不應殘留格式化預留位置。
/// </summary>
[Fact]
public void FormatConnectionAnnouncement_WhenConnected_IncludesDeviceName()
{
Expand All @@ -48,6 +57,9 @@ public void FormatConnectionAnnouncement_WhenConnected_IncludesDeviceName()
Assert.DoesNotContain("{0}", actual);
}

/// <summary>
/// 控制器未連線的廣播文字應使用斷線範本並帶入裝置名稱,避免播報未格式化字串。
/// </summary>
[Fact]
public void FormatConnectionAnnouncement_WhenDisconnected_UsesDisconnectedTemplate()
{
Expand All @@ -57,6 +69,9 @@ public void FormatConnectionAnnouncement_WhenDisconnected_UsesDisconnectedTempla
Assert.DoesNotContain("{0}", actual);
}

/// <summary>
/// 已連線狀態文字應包含左右搖桿座標與死區數值,讓校準診斷資訊完整可讀。
/// </summary>
[Fact]
public void FormatStatusText_WhenConnected_IncludesLeftAndRightStickValues()
{
Expand All @@ -83,6 +98,9 @@ public void FormatStatusText_WhenConnected_IncludesLeftAndRightStickValues()
Assert.Contains("2500", actual);
}

/// <summary>
/// 未連線狀態文字應回到資源檔中的斷線訊息,避免顯示空白或過期座標。
/// </summary>
[Fact]
public void FormatStatusText_WhenDisconnected_UsesDisconnectedMessage()
{
Expand All @@ -91,6 +109,9 @@ public void FormatStatusText_WhenDisconnected_UsesDisconnectedMessage()
Assert.Equal(Strings.Dialog_GamepadCalibrationVisualizer_StatusDisconnected, actual);
}

/// <summary>
/// 左搖桿位於中心區域時應允許 D-Pad 導覽焦點,避免校準對話框失去基本可操作性。
/// </summary>
[Fact]
public void ShouldHandleDirectionalFocusNavigation_WhenStickIsCentered_ReturnsTrue()
{
Expand All @@ -106,6 +127,9 @@ public void ShouldHandleDirectionalFocusNavigation_WhenStickIsCentered_ReturnsTr
Assert.True(actual);
}

/// <summary>
/// 左搖桿已明顯偏移時應阻止 D-Pad 焦點導覽,避免同一輸入同時觸發兩種移動。
/// </summary>
[Fact]
public void ShouldHandleDirectionalFocusNavigation_WhenLeftStickIsActive_ReturnsFalse()
{
Expand All @@ -121,6 +145,9 @@ public void ShouldHandleDirectionalFocusNavigation_WhenLeftStickIsActive_Returns
Assert.False(actual);
}

/// <summary>
/// 左搖桿剛跨越進入死區時應阻止焦點導覽,避免 stick-to-DPad 映射後又重複移動焦點。
/// </summary>
[Fact]
public void ShouldHandleDirectionalFocusNavigation_WhenStickJustCrossesEnterDeadzone_ReturnsFalse()
{
Expand Down
12 changes: 12 additions & 0 deletions tests/InputBox.Tests/GamepadShoulderShortcutArbiterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ namespace InputBox.Tests;
/// </summary>
public sealed class GamepadShoulderShortcutArbiterTests
{
/// <summary>
/// 已武裝的單次肩鍵點按在放開時應輸出一次翻頁動作。
/// </summary>
[Fact]
public void TryConsumeTapOnRelease_WhenSingleTapWasArmed_EmitsSinglePageAction()
{
Expand All @@ -18,6 +21,9 @@ public void TryConsumeTapOnRelease_WhenSingleTapWasArmed_EmitsSinglePageAction()
Assert.True(arbiter.TryConsumeTapOnRelease(direction: -1, isLeftStillHeld: false, isRightStillHeld: false));
}

/// <summary>
/// 肩鍵長按連發已消費動作後,放開時不應再額外輸出單次翻頁。
/// </summary>
[Fact]
public void TryConsumeTapOnRelease_WhenRepeatAlreadyConsumed_DoesNotEmitExtraTap()
{
Expand All @@ -29,6 +35,9 @@ public void TryConsumeTapOnRelease_WhenRepeatAlreadyConsumed_DoesNotEmitExtraTap
Assert.False(arbiter.TryConsumeTapOnRelease(direction: -1, isLeftStillHeld: false, isRightStillHeld: false));
}

/// <summary>
/// 肩鍵已被用作修飾鍵時,放開時不應誤觸發單次翻頁。
/// </summary>
[Fact]
public void TryConsumeTapOnRelease_WhenModifierWasUsed_DoesNotEmitTapOnRelease()
{
Expand All @@ -40,6 +49,9 @@ public void TryConsumeTapOnRelease_WhenModifierWasUsed_DoesNotEmitTapOnRelease()
Assert.False(arbiter.TryConsumeTapOnRelease(direction: +1, isLeftStillHeld: false, isRightStillHeld: false));
}

/// <summary>
/// 雙肩鍵組合保留期間應抑制翻頁,直到兩側肩鍵都放開後才解除抑制。
/// </summary>
[Fact]
public void ReserveDualShoulderCombo_SuppressesPagingUntilBothShouldersAreReleased()
{
Expand Down
6 changes: 3 additions & 3 deletions tests/InputBox.Tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,19 @@
## 二、執行方式 🚀

```powershell
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj
dotnet test --project tests/InputBox.Tests/InputBox.Tests.csproj
```

加入詳細輸出(MTP):

```powershell
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj --logger "console;verbosity=detailed"
dotnet test --project tests/InputBox.Tests/InputBox.Tests.csproj --logger "console;verbosity=detailed"
```

收集 Code Coverage(MTP 原生模式,同 CI):

```powershell
dotnet test tests/InputBox.Tests/InputBox.Tests.csproj -c Release --no-build `
dotnet test --project tests/InputBox.Tests/InputBox.Tests.csproj -c Release --no-build `
--filter-not-trait "Category=UI" `
--coverage `
--coverage-output-format cobertura `
Expand Down
2 changes: 1 addition & 1 deletion tests/InputBox.Tests/SystemHelperTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using InputBox.Core.Utilities;
using InputBox.Core.Utilities;
using Xunit;

namespace InputBox.Tests;
Expand Down
Loading