# 通知設計書 46-ScrollPositionChanged

## 概要

本ドキュメントは、Windows Terminal における ScrollPositionChanged イベントの設計仕様を記述する。このイベントは、ターミナルのスクロール位置が変更された際に発火し、スクロールバーの更新と選択マーカーの位置調整を行う。

### 本通知の処理概要

ScrollPositionChangedイベントは、ターミナルバッファのスクロール位置変更をUI層に伝えるためのイベントである。TerminalCoreがSetScrollPositionChangedCallbackで設定されたコールバックを呼び出し、ControlCoreの_terminalScrollPositionChangedメソッドが発火する。このイベントはスロットリング（8msの遅延）が適用され、XAMLスクロールバーの更新コストを抑制する。TermControlは受信後、スクロールバーの値・範囲を更新し、表示中の選択マーカーの位置を再計算する。

**業務上の目的・背景**：ターミナルはテキスト出力やユーザーのスクロール操作により頻繁にスクロール位置が変化する。スクロールバーの表示をリアルタイムに更新する必要があるが、高頻度の更新はXAMLのパフォーマンスに悪影響を与えるため、スロットリングが適用される。

**通知の送信タイミング**：ターミナル内部のスクロール位置が変更された時に発火する。ユニットテスト中は即座に発火し、通常時はThrottledFuncにより8ms間隔でスロットリングされる。また、テキスト選択操作（SelectCommand/SelectOutput）によるスクロール時も明示的に発火される。

**通知の受信者**：TermControlの`_ScrollPositionChanged`ハンドラがControlCoreおよびControlInteractivityからのイベントを受信する。

**通知内容の概要**：ScrollPositionChangedArgsオブジェクトにViewTop（int32_t、ビューポート先頭行）、ViewHeight（int32_t、ビューポート高さ）、BufferSize（int32_t、バッファ全体の行数）が格納される。

**期待されるアクション**：TermControlはスクロールバーのMaximum/Minimum/Value/ViewportSizeを更新し、選択マーカーが表示中の場合は位置を再計算する。また、QuickFixメニューの位置を更新する。

## 通知種別

アプリ内通知（WinRT イベント / TerminalCoreコールバック）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（スロットリングあり、8ms間隔） |
| 優先度 | 中 |
| リトライ | 無し |

### 送信先決定ロジック

TerminalCoreがコールバック経由でControlCoreの_terminalScrollPositionChangedを呼び出す。ControlCoreはThrottledFuncを使用してUIスレッドでScrollPositionChanged.raiseを実行する。TermControlはControlCoreとControlInteractivityの両方からイベントを購読する。

## 通知テンプレート

### メール通知の場合

該当なし（アプリ内イベント通知のため）

### 本文テンプレート

```
該当なし（ScrollPositionChangedArgsとしてViewTop/ViewHeight/BufferSizeが伝達される）
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| ViewTop | ビューポート先頭行（0始まり） | Terminal内部 | Yes |
| ViewHeight | ビューポートの高さ（行数） | Terminal内部 | Yes |
| BufferSize | バッファ全体の行数 | Terminal内部 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部処理 | ターミナル出力によるスクロール | スクロール位置変更時 | 新しいテキスト出力による自動スクロール |
| ユーザー操作 | マウスホイール/スクロールバー操作 | スクロール位置変更時 | ユーザーによるスクロール操作 |
| ユーザー操作 | SelectCommand/SelectOutput | スクロール位置変更時 | コマンド/出力選択によるスクロール |
| 内部処理 | UserScrollViewport | スクロール位置変更時 | プログラム的なスクロール位置設定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 初期化未完了 | `_initializedTerminal.load()` がfalseの場合はearly returnする |
| スロットリング | 8ms以内の連続呼び出しはThrottledFuncによりマージされる |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[トリガー: スクロール位置変更] --> B[Terminal: ScrollPositionChangedCallback]
    B --> C[ControlCore::_terminalScrollPositionChanged]
    C --> D{ユニットテスト中?}
    D -->|Yes| E[即座にScrollPositionChanged.raise]
    D -->|No| F[ThrottledFunc経由 - 8ms間隔]
    F --> G[UIスレッドで ScrollPositionChanged.raise]
    E --> H[TermControl::_ScrollPositionChanged]
    G --> H
    H --> I[スクロールバー値更新]
    H --> J[選択マーカー位置更新]
    H --> K[QuickFixMenu位置更新]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（データベースは使用しない）

### 更新テーブル一覧

該当なし（データベースは使用しない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| weak_ptr失効 | ControlCoreがすでに破棄されている場合 | weakThis.get()のnullチェックでスキップ |
| _IsClosing | ControlCoreがクロージング中の場合 | _IsClosing()チェックでスキップ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| スロットリング間隔 | 8ms（ThrottledFunc、trailing mode） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

スクロール位置情報は純粋なUI状態であり、個人情報や機密情報を含まない。

## 備考

- ControlCore.idlではScrollPositionChangedは「UIスレッドから常に呼び出される」カテゴリに分類されている
- ThrottledFuncはControlCoreの_setupDispatcherAndCallbacks内（232-243行目）でセットアップされる
- TermControlは_ScrollPositionChangedハンドラ内で_updateScrollBar->Run(update)を呼び出し、さらにスクロールバー側のスロットリングも行う
- SelectCommand/SelectOutput操作時は_terminalScrollPositionChangedが明示的に呼ばれる（2663-2679行目）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | 91-96行目: ScrollPositionChangedArgs定義（ViewTop, ViewHeight, BufferSize） |
| 1-2 | EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | 131-146行目: ScrollPositionChangedArgs実装 |

**読解のコツ**: WINRT_PROPERTYマクロはget/setアクセサとプライベートフィールド `_Xxx` を生成する。

#### Step 2: コールバック登録とスロットリング設定

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 118-119行目: SetScrollPositionChangedCallback登録 |
| 2-2 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 232-243行目: ThrottledFunc<ScrollPositionChangedArgs>のセットアップ。8msの遅延、trailing mode |

**主要処理フロー**:
1. **118-119行目**: Terminalにスクロールコールバックを登録
2. **232行目**: `shared->updateScrollBar = std::make_shared<ThrottledFunc<...>>` でスロットリングを構築
3. **234行目**: `delay = std::chrono::milliseconds{ 8 }` で8ms間隔に設定

#### Step 3: イベント発火処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | 1617-1643行目: _terminalScrollPositionChanged - 初期化チェック、ユニットテスト分岐、ThrottledFunc経由の発火 |

**主要処理フロー**:
- **1621-1624行目**: `_initializedTerminal.load()` がfalseならearly return
- **1627-1629行目**: ScrollPositionChangedArgs生成
- **1631-1633行目**: ユニットテスト時は直接raise
- **1637-1641行目**: 通常時はThrottledFunc経由でUIスレッドからraise

#### Step 4: TermControl側ハンドラ

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | 318行目: interactivityのScrollPositionChanged購読 |
| 4-2 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | 394行目: coreのScrollPositionChanged購読 |
| 4-3 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | 2492-2512行目: _ScrollPositionChanged - スクロールバー更新、選択マーカー更新、QuickFix更新 |

**主要処理フロー**:
- **2496-2501行目**: ScrollBarUpdateを構築（Maximum, Minimum, ViewportSize, Value）
- **2502行目**: `_updateScrollBar->Run(update)` でスクロールバーを更新
- **2506-2508行目**: 選択マーカーが表示中の場合は位置を再計算
- **2511行目**: `RefreshQuickFixMenu()` でQuickFixメニュー位置を更新

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

```
Terminal (TerminalCore層)
    |
    +-- ScrollPositionChangedCallback(viewTop, viewHeight, bufferSize)
            |
            +-- ControlCore::_terminalScrollPositionChanged()
                    |
                    +-- ScrollPositionChangedArgs生成
                    +-- [ユニットテスト] ScrollPositionChanged.raise() 直接
                    +-- [通常時] ThrottledFunc::Run() (8ms遅延)
                            |
                            +-- UIスレッドで ScrollPositionChanged.raise()
                                    |
                                    +-- TermControl::_ScrollPositionChanged()
                                            |
                                            +-- _updateScrollBar->Run() [スクロールバー更新]
                                            +-- _updateSelectionMarkers() [選択マーカー更新]
                                            +-- RefreshQuickFixMenu()
```

### データフロー図

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

スクロール操作          Terminal                       TermControl
テキスト出力       -->  ScrollPositionChangedCallback   -->  スクロールバー更新
                       ControlCore::ThrottledFunc          (Maximum/Value/ViewportSize)
                       (8ms間隔)                       -->  選択マーカー位置更新
                       ScrollPositionChanged.raise()   -->  QuickFixMenu位置更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | IDL | ScrollPositionChangedArgs定義 |
| EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | ソース | ScrollPositionChangedArgs実装 |
| ControlCore.idl | `src/cascadia/TerminalControl/ControlCore.idl` | IDL | ScrollPositionChangedイベント宣言 |
| ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | ソース | ScrollPositionChangedイベント定義、ThrottledFunc |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | コールバック登録、スロットリング設定、_terminalScrollPositionChanged |
| ControlInteractivity.cpp | `src/cascadia/TerminalControl/ControlInteractivity.cpp` | ソース | ScrollPositionChangedイベント定義 |
| ControlInteractivity.h | `src/cascadia/TerminalControl/ControlInteractivity.h` | ソース | ScrollPositionChangedイベント宣言 |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | _ScrollPositionChangedハンドラ |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ソース | ハンドラ宣言 |
| Terminal.cpp | `src/cascadia/TerminalCore/Terminal.cpp` | ソース | SetScrollPositionChangedCallback |
| Terminal.hpp | `src/cascadia/TerminalCore/Terminal.hpp` | ソース | コールバック宣言 |
