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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
- **左搖桿**:功能等同鍵盤**方向鍵**。
- 用於瀏覽輸入歷程記錄或移動游標。
- **右搖桿 ←**/**→**:**虛擬選取模式**。直接擴張或縮減文字選取範圍。
- **LT/RT**:快速將游標跳到文字開頭/結尾。
- **Start/Menu 鍵**:開啟 Windows 觸控式鍵盤(`TabTip.exe`),可在已有內容時直接叫出鍵盤進行修正。
- **Back/View 鍵**:在放開按鍵時,嘗試將焦點切換回先前的前景視窗。
- **按住 LB 與 RB 不放,再按下目前配置下的取消鍵**:功能等同於控制器 **Back/View 鍵**。
Expand All @@ -146,6 +147,7 @@
- **方向鍵 ←/→**:進入(或按目前配置下的**確認鍵**)或退出(或按目前配置下的**取消鍵**)子選單。
- **確認鍵/Start/Menu 鍵**:執行選取的項目。
- **取消鍵/Back/View 鍵**:關閉選單。
- **片語子選單開啟時**:可使用 **LB/RB** 快速切換上一頁/下一頁,並以 **LT/RT** 直接跳至首頁/末頁。
- **數值輸入對話框操作** 🔢:
- **方向鍵 ↑/↓**:增加或減少數值。
- **方向鍵 ←/→**:移動游標(或 **LB** + 方向鍵進行單字跳轉)。
Expand Down Expand Up @@ -191,7 +193,7 @@
- **片語數量提示**:片語管理對話框會顯示目前數量(例如 `12/50`);接近上限時會提供額外視覺提醒,協助避免新增失敗。
- **片語編輯對話框中的取消鍵行為**:若焦點位於名稱或內容輸入框且有文字,先清空該輸入框;若輸入框已為空或焦點不在輸入框,則執行取消關閉。
- **片語編輯對話框中的 Enter 行為**:在名稱或內容輸入框中,按下 **Enter** 時,若目前欄位為空會開啟 Windows 觸控式鍵盤;若目前欄位已有內容則執行確認驗證。於內容欄位可使用 **Shift + Enter** 換行。
- **分頁行為**:若片語項目超過單頁容量,子選單會顯示 ◀/▶ 分頁控制;每次重新開啟片語子選單時,會回到第 1 頁。
- **分頁行為**:若片語項目超過單頁容量,子選單會顯示 ◀/▶ 分頁控制;每次重新開啟片語子選單時,會回到第 1 頁。控制器可直接使用 **LB/RB** 快速切頁,並以 **LT/RT** 跳至首頁或末頁。
- **快速鍵設定** ⚙️:
- **修飾鍵組合**:可直接勾選 **Alt**、**Ctrl**、**Shift** 或 **Win** 鍵作為快速鍵的修飾部分。
- **擷取主要按鍵**:點選後,應用程式會進入擷取狀態,此時按下鍵盤上的任一按鍵即可將其設定為喚出快速鍵的主要按鍵(按下鍵盤 **ESC 鍵** 或控制器目前配置下的**取消鍵**可取消擷取)。
Expand Down
5 changes: 1 addition & 4 deletions src/InputBox/Core/Controls/GamepadMessageBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,7 @@ private void BuildButtons(
{
// 決定按鈕清單(由右至左順序,因為 FlowDirection = RightToLeft)。
List<(string label, DialogResult result, bool isPrimary, bool isCancel)> specs = GetButtonSpecs(buttons);

#pragma warning disable IDE0028 // 簡化集合初始化
List<Button> createdButtons = new(specs.Count);
#pragma warning restore IDE0028 // 簡化集合初始化
List<Button> createdButtons = [];

foreach ((string label, DialogResult result, bool isPrimary, bool isCancel) in specs)
{
Expand Down
6 changes: 6 additions & 0 deletions src/InputBox/Core/Feedback/VibrationPatterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public static float GlobalIntensityMultiplier
/// </summary>
public static readonly VibrationProfile CursorMove = new(18000, 50);

/// <summary>
/// 分頁切換(比游標移動更明確的翻頁感)
/// 說明:略強於一般游標移動,讓使用者能清楚感知已切換到另一頁,但不至於干擾連續導覽。
/// </summary>
public static readonly VibrationProfile PageSwitch = new(26000, 80);

/// <summary>
/// 複製成功(強烈且明確的確認感)
/// 說明:提供約 60% 的強度與 150ms 的持續時間,給予使用者明確「任務已完成」的安全感。
Expand Down
46 changes: 30 additions & 16 deletions src/InputBox/Core/Input/GameInputGamepadController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ public int ThumbDeadzoneExit
public event Action? BackReleased;

/// <summary>
/// 控制器 A
/// 控制器 A 鍵按下事件。
/// </summary>
public event Action? APressed;

Expand All @@ -455,77 +455,87 @@ public int ThumbDeadzoneExit
public bool IsConnected => _isConnected;

/// <summary>
/// 控制器 B
/// 控制器 B 鍵按下事件。
/// </summary>
public event Action? BPressed;

/// <summary>
/// 控制器 X
/// 控制器 X 鍵按下事件。
/// </summary>
public event Action? XPressed;

/// <summary>
/// 控制器 Y
/// 控制器 Y 鍵按下事件。
/// </summary>
public event Action? YPressed;

/// <summary>
/// 控制器上鍵重複
/// 控制器上鍵重複事件。
/// </summary>
public event Action? UpRepeat;

/// <summary>
/// 控制器下鍵重複
/// 控制器下鍵重複事件。
/// </summary>
public event Action? DownRepeat;

/// <summary>
/// 控制器左鍵重複
/// 控制器左鍵重複事件。
/// </summary>
public event Action? LeftRepeat;

/// <summary>
/// 控制器右鍵重複
/// 控制器右鍵重複事件。
/// </summary>
public event Action? RightRepeat;

/// <summary>
/// 右搖桿左推按下事件
/// 當左肩鍵(LB 鍵)被按下時觸發。
/// </summary>
public event Action? LeftShoulderPressed;

/// <summary>
/// 當右肩鍵(RB 鍵)被按下時觸發。
/// </summary>
public event Action? RightShoulderPressed;

/// <summary>
/// 右搖桿左推按下事件。
/// </summary>
public event Action? RSLeftPressed;

/// <summary>
/// 右搖桿右推按下事件
/// 右搖桿右推按下事件
/// </summary>
public event Action? RSRightPressed;

/// <summary>
/// 右搖桿左推重複事件
/// 右搖桿左推重複事件
/// </summary>
public event Action? RSLeftRepeat;

/// <summary>
/// 右搖桿右推重複事件
/// 右搖桿右推重複事件
/// </summary>
public event Action? RSRightRepeat;

/// <summary>
/// 當左觸發鍵(LT 鍵)被按下時觸發
/// 當左觸發鍵(LT 鍵)被按下時觸發
/// </summary>
public event Action? LeftTriggerPressed;

/// <summary>
/// 當右觸發鍵(RT 鍵)被按下時觸發
/// 當右觸發鍵(RT 鍵)被按下時觸發
/// </summary>
public event Action? RightTriggerPressed;

/// <summary>
/// LT 持續按住時的連發事件
/// LT 持續按住時的連發事件
/// </summary>
public event Action? LeftTriggerRepeat;

/// <summary>
/// RT 持續按住時的連發事件
/// RT 持續按住時的連發事件
/// </summary>
public event Action? RightTriggerRepeat;

Expand Down Expand Up @@ -2046,6 +2056,8 @@ static void DetectReleased(
DetectRising(currentButtons, prevButtons, GameInputGamepadButtons.DPadDown, DownPressed);
DetectRising(currentButtons, prevButtons, GameInputGamepadButtons.DPadLeft, LeftPressed);
DetectRising(currentButtons, prevButtons, GameInputGamepadButtons.DPadRight, RightPressed);
DetectRising(currentButtons, prevButtons, GameInputGamepadButtons.LeftShoulder, LeftShoulderPressed);
DetectRising(currentButtons, prevButtons, GameInputGamepadButtons.RightShoulder, RightShoulderPressed);
DetectRising(currentButtons, prevButtons, GameInputGamepadButtons.Menu, StartPressed);
DetectRising(currentButtons, prevButtons, GameInputGamepadButtons.View, BackPressed);
DetectReleased(currentButtons, prevButtons, GameInputGamepadButtons.View, BackReleased);
Expand Down Expand Up @@ -2720,6 +2732,8 @@ private void ClearAllEvents()
RSRightPressed = null;
RSLeftRepeat = null;
RSRightRepeat = null;
LeftShoulderPressed = null;
RightShoulderPressed = null;
LeftTriggerPressed = null;
RightTriggerPressed = null;
LeftTriggerRepeat = null;
Expand Down
41 changes: 40 additions & 1 deletion src/InputBox/Core/Input/GamepadEventBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,34 @@
internal sealed class GamepadEventBinder
{
/// <summary>
/// 事件對映資料
/// 事件對映資料
/// </summary>
/// <param name="OnConnectionChanged">控制器連線狀態變更時執行的處理常式。</param>
/// <param name="OnBackPressed">控制器返回鍵按下時執行的處理常式。</param>
/// <param name="OnBackReleased">控制器返回鍵放開時執行的處理常式。</param>
/// <param name="OnUpPressed">控制器上鍵按下時執行的處理常式。</param>
/// <param name="OnDownPressed">控制器下鍵按下時執行的處理常式。</param>
/// <param name="OnUpRepeat">控制器上鍵連發時執行的處理常式。</param>
/// <param name="OnDownRepeat">控制器下鍵連發時執行的處理常式。</param>
/// <param name="OnLeftPressed">控制器左鍵按下時執行的處理常式。</param>
/// <param name="OnLeftRepeat">控制器左鍵連發時執行的處理常式。</param>
/// <param name="OnRightPressed">控制器右鍵按下時執行的處理常式。</param>
/// <param name="OnRightRepeat">控制器右鍵連發時執行的處理常式。</param>
/// <param name="OnLeftShoulderPressed">左肩鍵按下時執行的處理常式。</param>
/// <param name="OnRightShoulderPressed">右肩鍵按下時執行的處理常式。</param>
/// <param name="OnLeftTriggerPressed">左觸發鍵按下時執行的處理常式。</param>
/// <param name="OnLeftTriggerRepeat">左觸發鍵連發時執行的處理常式。</param>
/// <param name="OnRightTriggerPressed">右觸發鍵按下時執行的處理常式。</param>
/// <param name="OnRightTriggerRepeat">右觸發鍵連發時執行的處理常式。</param>
/// <param name="OnStartPressed">開始鍵按下時執行的處理常式。</param>
/// <param name="OnAPressed">A 鍵按下時執行的處理常式。</param>
/// <param name="OnBPressed">B 鍵按下時執行的處理常式。</param>
/// <param name="OnYPressed">Y 鍵按下時執行的處理常式。</param>
/// <param name="OnRSLeftPressed">右搖桿左推按下時執行的處理常式。</param>
/// <param name="OnRSLeftRepeat">右搖桿左推連發時執行的處理常式。</param>
/// <param name="OnRSRightPressed">右搖桿右推按下時執行的處理常式。</param>
/// <param name="OnRSRightRepeat">右搖桿右推連發時執行的處理常式。</param>
/// <param name="OnXPressed">X 鍵按下時執行的處理常式。</param>
internal sealed record BindingMap(
Action<bool> OnConnectionChanged,
Action OnBackPressed,
Expand All @@ -20,6 +46,12 @@ internal sealed record BindingMap(
Action OnLeftRepeat,
Action OnRightPressed,
Action OnRightRepeat,
Action OnLeftShoulderPressed,
Action OnRightShoulderPressed,
Action OnLeftTriggerPressed,
Action OnLeftTriggerRepeat,
Action OnRightTriggerPressed,
Action OnRightTriggerRepeat,
Action OnStartPressed,
Action OnAPressed,
Action OnBPressed,
Expand Down Expand Up @@ -52,6 +84,13 @@ public static void Bind(IGamepadController controller, BindingMap map)
controller.RightPressed += map.OnRightPressed;
controller.RightRepeat += map.OnRightRepeat;

controller.LeftShoulderPressed += map.OnLeftShoulderPressed;
controller.RightShoulderPressed += map.OnRightShoulderPressed;
controller.LeftTriggerPressed += map.OnLeftTriggerPressed;
controller.LeftTriggerRepeat += map.OnLeftTriggerRepeat;
controller.RightTriggerPressed += map.OnRightTriggerPressed;
controller.RightTriggerRepeat += map.OnRightTriggerRepeat;

controller.StartPressed += map.OnStartPressed;
controller.APressed += map.OnAPressed;
controller.BPressed += map.OnBPressed;
Expand Down
10 changes: 10 additions & 0 deletions src/InputBox/Core/Input/IGamepadController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ internal interface IGamepadController : IDisposable, IAsyncDisposable
/// </summary>
event Action? RightPressed;

/// <summary>
/// 當左肩鍵(LB 鍵)被按下時觸發
/// </summary>
event Action? LeftShoulderPressed;

/// <summary>
/// 當右肩鍵(RB 鍵)被按下時觸發
/// </summary>
event Action? RightShoulderPressed;

/// <summary>
/// 控制器開始鍵按下事件
/// </summary>
Expand Down
84 changes: 79 additions & 5 deletions src/InputBox/Core/Input/XInputGamepadController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -395,39 +395,93 @@ private void UpdateCachedDeviceName()
public bool IsConnected => _isConnected;

/// <summary>
/// 控制器 A, B, X, Y 按鈕事件
/// 控制器 A 鍵按下事件。
/// </summary>
public event Action? APressed;

/// <summary>
/// 控制器 B 鍵按下事件。
/// </summary>
public event Action? BPressed;

/// <summary>
/// 控制器 X 鍵按下事件。
/// </summary>
public event Action? XPressed;

/// <summary>
/// 控制器 Y 鍵按下事件。
/// </summary>
public event Action? YPressed;

/// <summary>
/// 控制器鍵重複事件
/// 控制器上鍵重複事件。
/// </summary>
public event Action? UpRepeat;

/// <summary>
/// 控制器下鍵重複事件。
/// </summary>
public event Action? DownRepeat;

/// <summary>
/// 控制器左鍵重複事件。
/// </summary>
public event Action? LeftRepeat;

/// <summary>
/// 控制器右鍵重複事件。
/// </summary>
public event Action? RightRepeat;

/// <summary>
/// 右搖桿按壓事件
/// 當左肩鍵(LB 鍵)被按下時觸發。
/// </summary>
public event Action? LeftShoulderPressed;

/// <summary>
/// 當右肩鍵(RB 鍵)被按下時觸發。
/// </summary>
public event Action? RightShoulderPressed;

/// <summary>
/// 右搖桿左推按下事件。
/// </summary>
public event Action? RSLeftPressed;

/// <summary>
/// 右搖桿右推按下事件。
/// </summary>
public event Action? RSRightPressed;

/// <summary>
/// 右搖桿重複事件
/// 右搖桿左推重複事件。
/// </summary>
public event Action? RSLeftRepeat;

/// <summary>
/// 右搖桿右推重複事件。
/// </summary>
public event Action? RSRightRepeat;

/// <summary>
/// 左右觸發鍵按壓事件
/// 當左觸發鍵(LT 鍵)被按下時觸發。
/// </summary>
public event Action? LeftTriggerPressed;

/// <summary>
/// 當右觸發鍵(RT 鍵)被按下時觸發。
/// </summary>
public event Action? RightTriggerPressed;

/// <summary>
/// LT 持續按住時的連發事件。
/// </summary>
public event Action? LeftTriggerRepeat;

/// <summary>
/// RT 持續按住時的連發事件。
/// </summary>
public event Action? RightTriggerRepeat;

/// <summary>
Expand Down Expand Up @@ -884,6 +938,24 @@ private void Poll()
}

// 偵測一般按鈕事件觸發(Rising Edge:原本沒按 -> 現在按了)。
bool wasLbDownBefore = _hasPreviousState &&
_previousState.Has(XInput.GamepadButton.LeftShoulder);

if (IsLeftShoulderHeld &&
!wasLbDownBefore)
{
LeftShoulderPressed?.Invoke();
}

bool wasRbDownBefore = _hasPreviousState &&
_previousState.Has(XInput.GamepadButton.RightShoulder);

if (IsRightShoulderHeld &&
!wasRbDownBefore)
{
RightShoulderPressed?.Invoke();
}

// 處理 LT。
bool wasLtDownBefore = _hasPreviousState &&
_previousState.Gamepad.LeftTrigger > AppSettings.XInputTriggerThreshold;
Expand Down Expand Up @@ -2033,6 +2105,8 @@ private void ClearAllEvents()
RSRightPressed = null;
RSLeftRepeat = null;
RSRightRepeat = null;
LeftShoulderPressed = null;
RightShoulderPressed = null;
LeftTriggerPressed = null;
RightTriggerPressed = null;
LeftTriggerRepeat = null;
Expand Down
2 changes: 1 addition & 1 deletion src/InputBox/Core/Services/RestartMenuTextResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ private static string GetResourceOrFallback(string resourceKey, string fallback)

return string.IsNullOrWhiteSpace(value) ? fallback : value;
}
}
}
Loading
Loading