# 機能設計書 31-テキストのコピー

## 概要

本ドキュメントは、Windows Terminal における「テキストのコピー」機能（CopyText アクション）の設計を記述する。ターミナル上で選択されたテキストをクリップボードにコピーする機能であり、プレーンテキスト・HTML・RTF形式でのコピー、制御シーケンス付きコピー、単一行コピーなど複数の出力形式に対応する。

### 本機能の処理概要

**業務上の目的・背景**：ターミナルエミュレータにおいて、画面上に表示されたコマンド出力やテキストをクリップボードにコピーし、他のアプリケーションへ貼り付けることは最も基本的な操作の一つである。Windows Terminal では従来のコンソールよりも高度なコピー機能を提供し、書式付きコピー（HTML/RTF）や制御シーケンス付きコピーにも対応している。

**機能の利用シーン**：ユーザーがターミナル上のテキストを選択した状態で Ctrl+C やキーバインドを押下したとき、またはコンテキストメニューから「コピー」を選択したときに実行される。コマンド出力の共有、ログの保存、ドキュメント作成時のテキスト引用などに利用される。

**主要な処理内容**：
1. CopyTextArgs からコピーオプション（選択解除、単一行化、制御シーケンス付き、コピーフォーマット）を取得する
2. アクティブな TermControl に対してコピー処理を実行する
3. ControlInteractivity を経由して ControlCore のクリップボード書き込み処理を呼び出す
4. Terminal コアから選択テキストをプレーンテキスト・HTML・RTF形式で抽出する
5. WriteToClipboard イベントを発火し、TerminalPage 側でシステムクリップボードに書き込む
6. オプションに応じて選択状態を解除する

**関連システム・外部連携**：Windows システムクリップボード API を使用してデータを書き込む。HTML 形式と RTF 形式は、リッチテキストエディタやブラウザへの貼り付けで書式が保持される。

**権限による制御**：特になし。ただし、クリップボードアクセスにはアプリケーション権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | TermControl（ターミナル表示） | 主画面 | CopyCommandButton/SelectionContextMenuによりテキストをコピー |
| 1 | TerminalPage（メイン画面） | 主画面 | _HandleCopyText でアクションを処理 |

## 機能種別

テキスト操作 / クリップボード操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| DismissSelection | Boolean | No | コピー後に選択状態を解除するかどうか（デフォルト: true） | - |
| SingleLine | Boolean | No | 選択テキストを単一行に折り畳むかどうか（デフォルト: false） | - |
| WithControlSequences | Boolean | No | VT制御シーケンスを含めてコピーするかどうか（デフォルト: false） | - |
| CopyFormatting | IReference<CopyFormat> | No | コピー形式（HTML/RTF/両方/なし）。null の場合はグローバル設定を使用 | CopyFormat 列挙値 |

### 入力データソース

- TermControl 上で選択されているテキスト範囲
- CopyTextArgs アクション引数
- グローバル設定の CopyFormatting デフォルト値

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PlainText | hstring | 選択されたプレーンテキスト |
| Html | hstring | HTML 形式のテキスト（オプション） |
| Rtf | hstring | RTF 形式のテキスト（オプション） |

### 出力先

- Windows システムクリップボード（プレーンテキスト / HTML / RTF 形式）

## 処理フロー

### 処理シーケンス

```
1. _HandleCopyText が ActionEventArgs を受信
   └─ CopyTextArgs にキャストし、コピーオプションを取得
2. CopyFormatting の解決
   └─ realArgs.CopyFormatting() が null の場合、_settings.GlobalSettings().CopyFormatting() を使用
3. _CopyText を呼び出し
   └─ dismissSelection, singleLine, withControlSequences, format を引数に渡す
4. TermControl.CopySelectionToClipboard を呼び出し
   └─ 閉じ処理中でないことを確認後、ControlInteractivity に委譲
5. ControlInteractivity.CopySelectionToClipboard
   └─ 選択がない場合は false を返す（Ctrl+C がターミナルに ^C として送信されるようにする）
   └─ _selectionNeedsToBeCopied フラグをリセット
   └─ ControlCore.CopySelectionToClipboard を呼び出し
6. ControlCore.CopySelectionToClipboard
   └─ ターミナルロックを取得
   └─ Terminal::RetrieveSelectedTextFromBuffer でテキスト抽出
   └─ WriteToClipboard イベントを発火
7. TerminalPage._copyToClipboard
   └─ clipboard::open でクリップボードを開く
   └─ clipboard::write でプレーンテキスト、HTML、RTF を書き込む
8. 選択解除（DismissSelection が true の場合）
   └─ ControlCore.ClearSelection を呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[CopyText アクション受信] --> B{CopyTextArgs 取得成功?}
    B -->|No| Z[何もしない]
    B -->|Yes| C{CopyFormatting 指定あり?}
    C -->|Yes| D[指定値を使用]
    C -->|No| E[グローバル設定値を使用]
    D --> F[_CopyText 呼び出し]
    E --> F
    F --> G[TermControl.CopySelectionToClipboard]
    G --> H{閉じ処理中?}
    H -->|Yes| Z
    H -->|No| I[ControlInteractivity.CopySelectionToClipboard]
    I --> J{選択あり?}
    J -->|No| K[false を返す]
    J -->|Yes| L[ControlCore.CopySelectionToClipboard]
    L --> M[Terminal::RetrieveSelectedTextFromBuffer]
    M --> N[WriteToClipboard イベント発火]
    N --> O[システムクリップボードに書き込み]
    O --> P{DismissSelection?}
    P -->|Yes| Q[選択解除]
    P -->|No| R[選択を維持]
    Q --> S[完了]
    R --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | 選択なし時の動作 | 選択がない状態でコピーを実行した場合、アクションは「未処理」として返される。これにより Ctrl+C が ^C としてターミナルに送信される | 選択テキストが存在しない場合 |
| BR-31-02 | コピーフォーマットのフォールバック | CopyTextArgs で CopyFormatting が指定されていない場合、グローバル設定の CopyFormatting 値を使用する | CopyFormatting が null の場合 |
| BR-31-03 | 単一行モード | SingleLine が true の場合、選択テキスト内の改行を除去して単一行として返す | SingleLine パラメータが true |
| BR-31-04 | 制御シーケンス付きコピー | WithControlSequences が true の場合、色・スタイル情報を ANSI エスケープシーケンスとしてプレーンテキストに含める | WithControlSequences パラメータが true |

### 計算ロジック

なし

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

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 選択なし | テキストが選択されていない状態でコピーを実行 | false を返し、アクションを未処理とする |
| - | コントロール閉じ処理中 | TermControl が閉じ処理中にコピーが呼ばれた | false を返し処理を中断 |
| - | クリップボードアクセス失敗 | システムクリップボードを開けない場合 | 処理をスキップ（clipboard::open が失敗） |

### リトライ仕様

リトライは行わない。

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

ターミナルバッファの読み取り時に LockForWriting でロックを取得し、テキスト抽出と選択解除が完了するまでロックを保持する。

## パフォーマンス要件

大量のテキスト選択時でもUIスレッドをブロックしないこと。クリップボードへの書き込みは即座に完了すること。

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

- クリップボードに書き込まれるデータは、ユーザーが明示的に選択したテキストのみ
- 制御シーケンス付きコピーを有効にすると、ANSIエスケープシーケンスがプレーンテキストに含まれる

## 備考

- 選択がない場合にコピーを「未処理」として返す仕組みにより、Ctrl+C が従来の割り込みシグナル（^C）として機能する
- HTML/RTF 形式でのコピーは、エディタやメールクライアントに色付きテキストを貼り付ける際に有用
- マウスダブルクリック時のコピー（_SelectionCopyHandler）も内部的に同じ CopySelectionToClipboard メソッドを呼び出す

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | CopyTextArgs の定義。DismissSelection, SingleLine, WithControlSequences, CopyFormatting の各プロパティ |

**読解のコツ**: IDL ファイルは WinRT インターフェースの定義であり、C++ で自動生成されるプロパティやメソッドの元となる。`runtimeclass` がクラス定義に相当する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | _HandleCopyText メソッドがアクションのエントリーポイント |

**主要処理フロー**:
1. **547-557行目**: CopyTextArgs からオプションを取得し、CopyFormatting の null チェックとグローバル設定へのフォールバックを実施
2. **554行目**: _CopyText を呼び出し、結果を handled に設定

#### Step 3: TerminalPage のコピー処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | _CopyText メソッドで TermControl へ委譲 |

**主要処理フロー**:
- **3200-3207行目**: _GetActiveControl() でアクティブコントロールを取得し、CopySelectionToClipboard を呼び出す
- **3342-3355行目**: _copyToClipboard でシステムクリップボードへの書き込みを実行

#### Step 4: TermControl 層

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | CopySelectionToClipboard メソッド |

**主要処理フロー**:
- **2544-2559行目**: _IsClosing() チェック後、ControlInteractivity に委譲。DismissSelection 時に ClearSelection を呼ぶ

#### Step 5: ControlInteractivity / ControlCore 層

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ControlInteractivity.cpp | `src/cascadia/TerminalControl/ControlInteractivity.cpp` | CopySelectionToClipboard で選択有無チェック |
| 5-2 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | CopySelectionToClipboard でテキスト抽出と WriteToClipboard イベント発火 |

**主要処理フロー**:
- **199-221行目**（ControlInteractivity.cpp）: 選択がない場合は false を返す（Ctrl+C が ^C として送信される）
- **1343-1372行目**（ControlCore.cpp）: ターミナルロック取得、RetrieveSelectedTextFromBuffer 呼び出し、WriteToClipboard イベント発火

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

```
TerminalPage::_HandleCopyText (AppActionHandlers.cpp:547)
    |
    +-- TerminalPage::_CopyText (TerminalPage.cpp:3200)
           |
           +-- TermControl::CopySelectionToClipboard (TermControl.cpp:2544)
                  |
                  +-- ControlInteractivity::CopySelectionToClipboard (ControlInteractivity.cpp:199)
                  |      |
                  |      +-- ControlCore::CopySelectionToClipboard (ControlCore.cpp:1343)
                  |             |
                  |             +-- Terminal::RetrieveSelectedTextFromBuffer
                  |             +-- WriteToClipboard イベント発火
                  |                    |
                  |                    +-- TerminalPage::_copyToClipboard (TerminalPage.cpp:3342)
                  |                           |
                  |                           +-- clipboard::open / clipboard::write
                  |
                  +-- ControlCore::ClearSelection (DismissSelection 時)
```

### データフロー図

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

CopyTextArgs        --> _HandleCopyText                  --> コピーオプション解決
  (DismissSelection,    |
   SingleLine,          v
   WithControlSequences,  _CopyText
   CopyFormatting)        |
                          v
テキストバッファ    --> CopySelectionToClipboard         --> WriteToClipboardEventArgs
  (選択範囲)            |                                    (PlainText, Html, Rtf)
                        v                                    |
                    RetrieveSelectedTextFromBuffer            v
                                                        システムクリップボード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | _HandleCopyText アクションハンドラ |
| TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | ソース | _CopyText / _copyToClipboard の実装 |
| TerminalPage.h | `src/cascadia/TerminalApp/TerminalPage.h` | ヘッダ | _CopyText メソッド宣言 |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | CopySelectionToClipboard の実装 |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ヘッダ | コピー関連メソッド宣言 |
| ControlInteractivity.cpp | `src/cascadia/TerminalControl/ControlInteractivity.cpp` | ソース | CopySelectionToClipboard の選択チェック |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | テキスト抽出とクリップボードイベント発火 |
| ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | IDL | CopyTextArgs の型定義 |
