# 機能設計書 45-上にスクロール

## 概要

本ドキュメントは、Windows Terminal における「上にスクロール（ScrollUp）」機能の設計を記述する。ターミナルバッファのビューポートを指定行数分上方向にスクロールする機能である。

### 本機能の処理概要

ユーザーの操作（キーバインド）に応じて、ターミナルのビューポートを上方向に指定された行数分スクロールする。行数が指定されない場合は、システム設定のスクロール行数（マウスホイール1ノッチ分）が使用される。

**業務上の目的・背景**：ターミナルでは、コマンドの出力が画面をスクロールして過去の出力が見えなくなることが頻繁にある。過去の出力やログ情報を確認するために上方向へスクロールする操作は、ターミナル利用の基本操作である。本機能により、キーバインドを使ってマウスなしでもスクロール操作が可能になる。

**機能の利用シーン**：
- 長いコマンド出力の先頭部分を確認する場合
- 過去のコマンドとその出力を振り返る場合
- マウスを使わずにキーボードのみでスクロールしたい場合
- スクリプトの実行結果を上にスクロールして確認する場合

**主要な処理内容**：
1. ScrollUpアクションを受け付け、スクロール行数を取得する
2. スクロール行数が未指定の場合、システム設定値またはデフォルト値を使用する
3. スクロールデルタを計算する（上方向は負値）
4. アクティブなタブのTermControlのビューポートを移動する

**関連システム・外部連携**：Windowsのシステム設定（SPI_GETWHEELSCROLLLINES）からデフォルトスクロール行数を取得する。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | TerminalPage（メイン画面） | 主画面 | _HandleScrollUpにより指定行数分上にスクロール |
| 6 | TermControl（ターミナル表示） | 主画面 | マウスホイールやキー操作による上スクロール |

## 機能種別

ビューポート操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| RowsToScroll | IReference<uint32_t> | No | スクロールする行数。nullの場合はシステム設定値を使用 | 0以上の整数値 |

### 入力データソース

- アクション引数（ScrollUpArgs）: キーバインド設定からのRowsToScroll指定
- システム設定: SystemParametersInfoW(SPI_GETWHEELSCROLLLINES)から取得したスクロール行数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| スクロール位置 | int | ビューポートの新しいスクロール位置（viewTop） |

### 出力先

TermControlのスクロールバーおよびビューポート位置の更新。

## 処理フロー

### 処理シーケンス

```
1. ユーザーがScrollUpアクションを実行
   └─ _HandleScrollUp (AppActionHandlers.cpp) が呼ばれる
2. ScrollUpArgsからRowsToScrollを取得
   └─ nullの場合はシステム設定値(_systemRowsToScroll)を使用
   └─ WHEEL_PAGESCROLLの場合はViewHeight()を使用
3. スクロールデルタを計算
   └─ _ComputeScrollDelta(ScrollUp, rowsToScroll) → 負値
4. タブのScroll関数を呼び出し
   └─ Tab::Scroll(scrollDelta)
5. TermControlのスクロール位置を更新
   └─ ScrollViewport(currentOffset + delta) → ScrollBar更新
```

### フローチャート

```mermaid
flowchart TD
    A[ScrollUpアクション発火] --> B[ScrollUpArgsから行数取得]
    B --> C{RowsToScroll指定あり?}
    C -->|Yes| D[指定値を使用]
    C -->|No| E{systemRowsToScroll == WHEEL_PAGESCROLL?}
    E -->|Yes| F[ViewHeight()を使用]
    E -->|No| G[systemRowsToScrollを使用]
    D --> H[_ComputeScrollDelta]
    F --> H
    G --> H
    H --> I[Tab::Scroll実行]
    I --> J[ScrollViewport更新]
    J --> K[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | デフォルト行数 | RowsToScroll未指定時はシステムのスクロール行数設定を使用 | RowsToScroll == null |
| BR-45-02 | ページスクロール | WHEEL_PAGESCROLLの場合はビューの高さ（ViewHeight）分スクロール | systemRowsToScroll == WHEEL_PAGESCROLL |
| BR-45-03 | 方向 | ScrollUp方向のデルタは負値として計算される | 常時 |
| BR-45-04 | 境界制御 | スクロール位置はbase::ClampAddにより安全に加算され、バッファ範囲外にはならない | 常時 |
| BR-45-05 | フォールバック | SystemParametersInfoW失敗時はDefaultRowsToScroll（3行）にフォールバック | API呼び出し失敗時 |

### 計算ロジック

- デルタ計算: `scrollDelta = -1 * rowsToScroll`（上方向は負値）
- 新スクロール位置: `base::ClampAdd(currentOffset, scrollDelta)`

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

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

本機能ではデータベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 無操作 | フォーカスされたタブが存在しない | 何も起こらずに終了 |
| - | フォールバック | SystemParametersInfoW失敗 | DefaultRowsToScroll（3行）を使用 |

### リトライ仕様

リトライは不要。

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

なし。UIスレッド上でのビューポート操作のみ（ASSERT_UI_THREAD）。

## パフォーマンス要件

即時応答。スクロールバーの値更新のみ。

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

特になし。

## 備考

- _systemRowsToScrollは設定の再読み込み時に更新される。
- Tab::ScrollではASSERT_UI_THREADマクロでUIスレッド上の実行が保証される。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | ScrollUpArgsの定義。RowsToScrollプロパティ（IReference<UInt32>、null可能） |
| 1-2 | ActionArgs.h | `src/cascadia/TerminalSettingsModel/ActionArgs.h` | SCROLL_UP_ARGSマクロ（203-204行目）。デフォルト値はnullptr |

**読解のコツ**: RowsToScrollがIReference<uint32_t>（null許容の値型）であるため、null判定でデフォルト動作と明示的指定を切り分ける設計になっている。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | _HandleScrollUp関数（133-142行目）- ScrollUpArgsからRowsToScrollを取得、_Scrollを呼び出す |

**主要処理フロー**:
1. **136行目**: ScrollUpArgsにキャスト
2. **139行目**: _Scroll(ScrollUp, realArgs.RowsToScroll()) を呼び出し

#### Step 3: _Scroll関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | _Scroll関数（2360-2380行目）- 行数決定ロジックとTab::Scrollの呼び出し |
| 3-2 | TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | _ComputeScrollDelta関数（4397-4400行目）- 方向に応じた符号付きデルタの算出 |
| 3-3 | TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | _ReadSystemRowsToScroll関数（4408-4418行目）- システム設定からのスクロール行数取得 |

**主要処理フロー**:
- **2362-2370行目**: RowsToScroll nullの場合、_systemRowsToScrollまたはViewHeight()を使用
- **2374-2375行目**: RowsToScroll指定ありの場合、その値を使用
- **2377-2378行目**: _ComputeScrollDeltaでデルタ算出、Tab::Scrollで実行

#### Step 4: Tab/TermControl層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | Tab::Scroll関数（513-520行目）- currentOffset + deltaを計算してScrollViewportを呼び出す |
| 4-2 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ScrollViewport関数（2669-2672行目）- スクロールバーの値を更新 |

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

```
TerminalPage::_HandleScrollUp (AppActionHandlers.cpp:133)
    ├─ ScrollUpArgs::RowsToScroll() → 行数取得
    └─ TerminalPage::_Scroll (TerminalPage.cpp:2360)
           ├─ 行数決定（引数 or _systemRowsToScroll or ViewHeight）
           ├─ _ComputeScrollDelta(ScrollUp, rows) → 負値デルタ
           └─ Tab::Scroll (Tab.cpp:513)
                  ├─ GetActiveTerminalControl()
                  ├─ ScrollOffset() → 現在位置取得
                  ├─ base::ClampAdd(currentOffset, delta)
                  └─ TermControl::ScrollViewport (TermControl.cpp:2669)
                         └─ ScrollBar().Value(viewTop)
```

### データフロー図

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

ScrollUpArgs          →  _HandleScrollUp               →  スクロール位置更新
  (RowsToScroll)          └─ _Scroll
                               ├─ 行数決定
                               │   (null → システム設定)
システム設定           →       ├─ _ComputeScrollDelta      → デルタ（負値）
  (_systemRowsToScroll)       │   (ScrollUp → -rows)
                               └─ Tab::Scroll
                                    └─ ScrollViewport      →  スクロールバー
                                         (currentOffset       値更新
                                          + delta)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | _HandleScrollUpアクションハンドラー |
| TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | ソース | _Scroll/_ComputeScrollDelta/_ReadSystemRowsToScroll |
| TerminalPage.h | `src/cascadia/TerminalApp/TerminalPage.h` | ヘッダー | _Scroll関数等の宣言 |
| Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | ソース | Tab::Scroll関数 |
| Tab.h | `src/cascadia/TerminalApp/Tab.h` | ヘッダー | Tab::Scroll関数の宣言 |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | ScrollViewport/ScrollOffset |
| ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | IDL | ScrollUpArgs定義 |
| ActionArgs.h | `src/cascadia/TerminalSettingsModel/ActionArgs.h` | ヘッダー | SCROLL_UP_ARGSマクロ |
| AllShortcutActions.h | `src/cascadia/TerminalSettingsModel/AllShortcutActions.h` | ヘッダー | ScrollUpアクションの登録 |
