# 機能設計書 55-Gestures

## 概要

本ドキュメントは、Avaloniaフレームワークにおけるジェスチャー認識（Gestures）機能の設計仕様を定義する。Gesturesは、タップ、ダブルタップ、右タップ、長押し、ピンチ、スクロールなどの高レベルなジェスチャーイベントを提供する静的クラスである。

### 本機能の処理概要

Gesturesは、低レベルなポインターイベント（PointerPressed/Released/Moved）を監視し、これらを高レベルなジェスチャーイベントに変換する静的クラスである。タッチ、マウス、ペンなど複数の入力デバイスに対して一貫したジェスチャー認識を提供する。

**業務上の目的・背景**：ユーザーは直感的なジェスチャー操作でアプリケーションを操作することを期待している。Gesturesは、クロスプラットフォームで一貫したジェスチャー認識を提供し、開発者がデバイスごとのジェスチャー実装を意識することなく、タップ、ダブルタップ、長押しなどの標準的なジェスチャーをサポートできるようにする。

**機能の利用シーン**：
- ボタンやリスト項目のタップ選択
- ダブルタップによる編集モード切り替え
- 右タップによるコンテキストメニュー表示
- 長押しによるドラッグ開始や追加アクション表示
- ピンチズームによる拡大縮小
- スワイプによるスクロール

**主要な処理内容**：
1. Tapped/DoubleTapped/RightTappedイベントの生成
2. HoldingEvent（長押し）の検出と状態管理
3. ScrollGesture/PinchGestureの処理
4. タッチパッドジェスチャー（Magnify/Rotate/Swipe）のルーティング
5. IsHoldingEnabled/IsHoldWithMouseEnabled添付プロパティによる制御

**関連システム・外部連携**：InputElement、PointerEventArgs、PlatformSettings、DispatcherTimerと連携してジェスチャーを検出する。

**権限による制御**：IsHoldingEnabled/IsHoldWithMouseEnabledで長押しジェスチャーの有効/無効を制御可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 34 | Gestures | 主機能 | ジェスチャー認識のデモ。タップ・ダブルタップ・長押し等 |
| 103 | Gestures | 主機能 | ジェスチャーのテスト |

## 機能種別

ジェスチャー認識 / イベント処理 / ユーザーインタラクション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| PointerPressedEventArgs | PointerPressedEventArgs | Yes | ポインター押下イベント | イベントハンドラー経由 |
| PointerReleasedEventArgs | PointerReleasedEventArgs | Yes | ポインター解放イベント | イベントハンドラー経由 |
| PointerEventArgs | PointerEventArgs | Yes | ポインター移動イベント | イベントハンドラー経由 |

### 入力データソース

- PointerPressed/Released/Movedイベント（RouteFinishedサブスクリプション経由）
- PlatformSettings（タップサイズ、長押し時間などの設定）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| TappedEventArgs | TappedEventArgs | タップイベント引数 |
| HoldingRoutedEventArgs | HoldingRoutedEventArgs | 長押しイベント引数 |
| PinchEventArgs | PinchEventArgs | ピンチイベント引数 |
| ScrollGestureEventArgs | ScrollGestureEventArgs | スクロールジェスチャーイベント |
| PointerDeltaEventArgs | PointerDeltaEventArgs | タッチパッドジェスチャー |

### 出力先

- ジェスチャーを検出したInputElement（イベント配信先）

## 処理フロー

### 処理シーケンス

```
1. PointerPressed受信
   └─ RouteFinishedサブスクリプションで検出
2. ジェスチャー状態初期化
   └─ GestureState作成、タイマー開始
3. 長押し判定
   └─ HoldWaitDuration経過後にHoldingイベント発火
4. PointerMoved受信
   └─ タップ領域外移動でジェスチャーキャンセル
5. PointerReleased受信
   └─ タップ/ダブルタップ/右タップ判定
6. ジェスチャーイベント発火
   └─ 該当するジェスチャーイベントをRaiseEvent
```

### フローチャート

```mermaid
flowchart TD
    A[PointerPressed受信] --> B{既存ジェスチャー中?}
    B -->|Yes| C[Holding中ならキャンセル]
    C --> D[ジェスチャー状態リセット]
    B -->|No| D
    D --> E{ClickCount % 2 == 1?}
    E -->|Yes| F[GestureState = Pending]
    F --> G[長押しタイマー開始]
    E -->|No| H{ClickCount % 2 == 0?}
    H -->|Yes| I[DoubleTappedEvent発火]
    H -->|No| J[待機]

    G --> K[PointerMoved受信]
    K --> L{タップ領域内?}
    L -->|No| M[Holding中ならキャンセル]
    M --> N[ジェスチャー状態リセット]
    L -->|Yes| O[継続]

    G --> P[タイマー満了]
    P --> Q[HoldingEvent Started発火]
    Q --> R[GestureState = Holding]

    R --> S[PointerReleased受信]
    S --> T{Holding中?}
    T -->|Yes| U[HoldingEvent Completed発火]
    T -->|No| V{RightButton?}
    V -->|Yes| W[RightTappedEvent発火]
    V -->|No| X{DoubleTapped?}
    X -->|No| Y[TappedEvent発火]
    X -->|Yes| Z[スキップ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-55-01 | タップ判定 | PointerRelease時にタップ領域内なら成立 | LeftButton解放時 |
| BR-55-02 | ダブルタップ優先 | ダブルタップ判定時はTappedをスキップ | ClickCount偶数時 |
| BR-55-03 | 長押し条件 | IsHoldingEnabled=true かつ タイマー満了 | HoldWaitDuration経過 |
| BR-55-04 | マウス長押し | IsHoldWithMouseEnabled=trueでマウスも長押し対象 | マウスデバイス時 |
| BR-55-05 | 移動キャンセル | タップ領域外への移動でジェスチャーキャンセル | PointerMoved時 |

### 計算ロジック

**タップ領域判定**：
- PlatformSettings.GetTapSize(PointerType)で取得
- s_lastPressPointを中心にtapSizeの矩形を作成
- ContainsExclusiveで包含判定

## データベース操作仕様

### 操作別データベース影響一覧

該当なし（UIフレームワークのためデータベース操作は行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | なし | - | - |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- ジェスチャー判定は即座に行われる必要がある
- 長押しタイマーはDispatcherTimer.RunOnceを使用

## セキュリティ考慮事項

特になし

## 備考

- Gesturesは静的コンストラクタでPointerイベントをサブスクライブ
- WeakReferenceで前回押下要素を保持しメモリリークを防止

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

ジェスチャーイベントで使用される型定義を先に把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | TappedEventArgs.cs | `src/Avalonia.Base/Input/TappedEventArgs.cs` | タップイベント引数 |
| 1-2 | HoldingRoutedEventArgs.cs | `src/Avalonia.Base/Input/HoldingRoutedEventArgs.cs` | 長押しイベント引数、HoldingState列挙型 |
| 1-3 | PinchEventArgs.cs | `src/Avalonia.Base/Input/PinchEventArgs.cs` | ピンチイベント引数 |

**読解のコツ**: HoldingStateはStarted/Completed/Cancelledの3状態。長押しの開始、完了（指を離した）、キャンセル（移動した）を表す。

#### Step 2: 静的クラス初期化を理解する

Gesturesクラスの初期化とイベントサブスクリプションを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Gestures.cs | `src/Avalonia.Base/Input/Gestures.cs` | 静的コンストラクタ、イベントサブスクリプション |

**主要処理フロー**:
1. **13-19行目**: GestureState record struct定義
2. **21-24行目**: 静的フィールド（s_gestureState、s_lastPress等）
3. **118-123行目**: 静的コンストラクタ、RouteFinishedサブスクリプション

#### Step 3: ジェスチャー検出ロジックを理解する

各ジェスチャーの検出アルゴリズムを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Gestures.cs | `src/Avalonia.Base/Input/Gestures.cs` | PointerPressed/Released/Movedハンドラー |

**主要処理フロー**:
- **228-285行目**: PointerPressed処理
  - **240-250行目**: 既存Holding状態のキャンセル
  - **253-273行目**: 新規ジェスチャー開始、長押しタイマー
  - **274-283行目**: ダブルタップ判定
- **287-329行目**: PointerReleased処理
  - **295-306行目**: タップ領域判定
  - **308-321行目**: Holding完了/RightTapped/Tapped発火
- **332-364行目**: PointerMoved処理
  - **340-355行目**: 領域外移動でHoldingキャンセル

### プログラム呼び出し階層図

```
InputElement.PointerPressedEvent.RouteFinished
    │
    └─ Gestures.PointerPressed
           │
           ├─ 既存Holding状態チェック・キャンセル
           ├─ GestureState設定
           ├─ 長押しタイマー開始
           │      └─ DispatcherTimer.RunOnce
           │             └─ HoldingEvent Started発火
           └─ ダブルタップ判定
                  └─ DoubleTappedEvent発火

InputElement.PointerReleasedEvent.RouteFinished
    │
    └─ Gestures.PointerReleased
           │
           ├─ タップ領域判定
           └─ イベント発火
                  ├─ HoldingEvent Completed
                  ├─ RightTappedEvent
                  └─ TappedEvent

InputElement.PointerMovedEvent.RouteFinished
    │
    └─ Gestures.PointerMoved
           │
           └─ 領域外移動でキャンセル
                  └─ HoldingEvent Cancelled発火
```

### データフロー図

```
[入力]                     [処理]                        [出力]

PointerPressedEvent ───▶ Gestures.PointerPressed ───▶ DoubleTappedEvent
                              │                          (ClickCount偶数時)
                              └─ DispatcherTimer ───▶ HoldingEvent Started
                                   (HoldWaitDuration後)

PointerReleasedEvent ───▶ Gestures.PointerReleased ───▶ TappedEvent
                              │                         RightTappedEvent
                              └─ タップ領域判定          HoldingEvent Completed

PointerMovedEvent ───▶ Gestures.PointerMoved ───▶ HoldingEvent Cancelled
                              └─ 領域外判定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Gestures.cs | `src/Avalonia.Base/Input/Gestures.cs` | ソース | 静的クラス、ジェスチャー検出 |
| TappedEventArgs.cs | `src/Avalonia.Base/Input/TappedEventArgs.cs` | ソース | タップイベント引数 |
| HoldingRoutedEventArgs.cs | `src/Avalonia.Base/Input/HoldingRoutedEventArgs.cs` | ソース | 長押しイベント引数 |
| PinchEventArgs.cs | `src/Avalonia.Base/Input/PinchEventArgs.cs` | ソース | ピンチイベント引数 |
| ScrollGestureEventArgs.cs | `src/Avalonia.Base/Input/ScrollGestureEventArgs.cs` | ソース | スクロールジェスチャー引数 |
| PointerDeltaEventArgs.cs | `src/Avalonia.Base/Input/PointerDeltaEventArgs.cs` | ソース | デルタイベント引数 |
| PullGestureEventArgs.cs | `src/Avalonia.Base/Input/PullGestureEventArgs.cs` | ソース | プルジェスチャー引数 |
| InputElement.cs | `src/Avalonia.Base/Input/InputElement.cs` | ソース | ポインターイベント定義 |
