# 通知設計書 57-WriteToClipboard

## 概要

本ドキュメントは、Windows Terminal における WriteToClipboard イベント通知の設計仕様を記述する。ターミナルコントロールからクリップボードへの書き込みが要求された際に発火し、テキスト（プレーンテキスト、HTML、RTF）をシステムクリップボードに書き込むためのアクション通知である。

### 本通知の処理概要

WriteToClipboard は、ターミナルバッファからテキストをコピーする操作やターミナル内部からのクリップボードコピー要求時に ControlCore から発火するイベントである。プレーンテキスト、HTML形式、RTF形式の3種類のデータ形式を同時にクリップボードに書き込む。イベントは TermControl を経由して TerminalPage に伝搬し、最終的にシステムクリップボードへの書き込みが実行される。

**業務上の目的・背景**：ターミナル出力やコマンド結果をユーザーがコピーして他のアプリケーションに貼り付ける操作は日常的に必要とされる。WriteToClipboard イベントは、ユーザーによるコピー操作（Ctrl+C、右クリックコピー等）およびターミナルプロセスからの OSC 52 クリップボード操作を統一的に処理し、複数のデータ形式（プレーン、HTML、RTF）を同時にクリップボードに書き込むことで、貼り付け先アプリケーションの書式対応に応じた最適な表示を可能にする。

**通知の送信タイミング**：2つのパスがある。(1) ユーザーによるコピー操作時（CopySelectionToClipboard メソッド経由、ControlCore.cpp L1365）、(2) ターミナルプロセスからのクリップボード書き込みコールバック経由（ControlCore.cpp L109）。

**通知の受信者**：TermControl がバブリングにより受信し、さらに TerminalPage._copyToClipboard が最終受信者となる。

**通知内容の概要**：WriteToClipboardEventArgs オブジェクトが渡され、Plain（UTF-16 プレーンテキスト）、Html（UTF-8 HTML 形式）、Rtf（UTF-8 RTF 形式）の3つのプロパティを持つ。

**期待されるアクション**：TerminalPage はシステムクリップボードを開き、3つの形式のデータを clipboard::write 関数を使って書き込む。

## 通知種別

アプリ内イベント通知（WinRT TypedEventHandler）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（バックグラウンドスレッドから呼ばれ得る） |
| 優先度 | 高 |
| リトライ | 無 |

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

TermControl が ControlCore の WriteToClipboard イベントに _bubbleWriteToClipboard ハンドラを登録（L332）。TerminalPage が TermControl の WriteToClipboard イベントに _copyToClipboard ハンドラを登録（L1957）。

## 通知テンプレート

### イベント引数

| 項目 | 内容 |
|-----|------|
| イベント型 | `TypedEventHandler<Object, WriteToClipboardEventArgs>` |
| 定義元 | `ControlCore.idl` L192, `EventArgs.idl` L58-63 |
| プロパティ | Plain, Html, Rtf |

### イベントデータ構造

```cpp
// EventArgs.idl
runtimeclass WriteToClipboardEventArgs
{
    String Plain { get; };    // UTF-16, CF_UNICODETEXT 形式
    byte[] Html { get; };     // UTF-8, "HTML Format" 形式
    byte[] Rtf { get; };      // UTF-8, "Rich Text Format" 形式
}
```

```cpp
// EventArgs.h
struct WriteToClipboardEventArgs : WriteToClipboardEventArgsT<WriteToClipboardEventArgs>
{
    WriteToClipboardEventArgs(winrt::hstring&& plain, std::string&& html, std::string&& rtf);
    winrt::hstring Plain() const noexcept;
    winrt::com_array<uint8_t> Html() noexcept;
    winrt::com_array<uint8_t> Rtf() noexcept;
};
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Plain | コピーされたプレーンテキスト（UTF-16） | _terminal->RetrieveSelectedTextFromBuffer() の plainText | Yes |
| Html | HTML形式のコピーデータ（UTF-8） | _terminal->RetrieveSelectedTextFromBuffer() の html | No |
| Rtf | RTF形式のコピーデータ（UTF-8） | _terminal->RetrieveSelectedTextFromBuffer() の rtf | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ユーザー操作 | CopySelectionToClipboard | 選択テキストが存在する | ControlCore.cpp L1365: ユーザーコピー操作時。プレーン、HTML、RTF形式を含む |
| ターミナルプロセス | OSC 52 クリップボード操作 | ターミナルプロセスからの要求 | ControlCore.cpp L109: SetCopyToClipboardCallback 経由。プレーンテキストのみ |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 選択テキストなし | CopySelectionToClipboard パスでは HasSelection() が false の場合 false を返す |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A{送信元} -->|ユーザーコピー| B[CopySelectionToClipboard]
    A -->|OSC 52| C[SetCopyToClipboardCallback]
    B --> D[RetrieveSelectedTextFromBuffer]
    D --> E[WriteToClipboard.raise with Plain/Html/Rtf]
    C --> F[WriteToClipboard.raise with Plain only]
    E --> G[TermControl::_bubbleWriteToClipboard]
    F --> G
    G --> H[TerminalPage::_copyToClipboard]
    H --> I[clipboard::open]
    I --> J[clipboard::write Plain/Html/Rtf]
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

該当なし（システムクリップボードへの書き込みのみ）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| クリップボード開失敗 | 他のアプリケーションがクリップボードをロック中 | clipboard::open の戻り値チェック |
| 書き込み失敗 | クリップボードメモリ不足等 | clipboard::write 内部でエラー処理 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

- OSC 52 経由のクリップボード書き込みはターミナルプロセスから要求されるため、悪意あるプロセスによるクリップボード汚染の可能性がある。ただし、ユーザーが起動したプロセスからの要求であるため、信頼性はユーザーの判断に委ねられる
- クリップボードへの書き込みは _hostingHwnd を使用してウィンドウハンドルを指定するため、正しいウィンドウコンテキストで操作される

## 備考

- WriteToClipboardEventArgs は ControlCore.idl のコメントで「These events are called from some background thread」に分類されている（L190）。バックグラウンドスレッドから呼ばれる可能性がある
- CopySelectionToClipboard パスでは singleLine、withControlSequences、copyHtml、copyRtf のオプションにより出力データ形式が制御される
- OSC 52 パスではプレーンテキストのみが書き込まれ、HTML/RTF は空文字列となる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | L58-63: WriteToClipboardEventArgs の WinRT 定義。Plain(String), Html(byte[]), Rtf(byte[]) の3プロパティ |
| 1-2 | EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | L60-84: C++ 実装。コンストラクタで move セマンティクスを使用。_cast メソッドで string -> com_array<uint8_t> 変換 |

**読解のコツ**: Html と Rtf は byte[] 型（com_array<uint8_t>）で返されるが、内部的には std::string（UTF-8）で保持されている。WinRT のプロジェクション制約のため、この変換が必要である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | L108-110: SetCopyToClipboardCallback。OSC 52 経由のプレーンテキストコピー |
| 2-2 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | L1360-1371: CopySelectionToClipboard。ユーザー操作による選択テキストコピー。RetrieveSelectedTextFromBuffer でデータ取得 |

**主要処理フロー（CopySelectionToClipboard）**:
1. **L1361**: `RetrieveSelectedTextFromBuffer` でプレーン/HTML/RTF データ取得
2. **L1365-1370**: `WriteToClipboard.raise` で WriteToClipboardEventArgs を生成・発火

#### Step 3: バブリング・最終処理層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | L332: WriteToClipboard バブリング登録 |
| 3-2 | TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | L1957: WriteToClipboard ハンドラ登録 |
| 3-3 | TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | L3342-3355: _copyToClipboard 実装。clipboard::open -> clipboard::write の流れ |

**主要処理フロー**:
- **L3344**: `clipboard::open(_hostingHwnd.value_or(nullptr))` でクリップボードを開く
- **L3350-3353**: `clipboard::write` でプレーン/HTML/RTF を書き込む

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

```
ControlCore::CopySelectionToClipboard (ユーザーコピー)
    |
    +-- _terminal->RetrieveSelectedTextFromBuffer()
    +-- WriteToClipboard.raise(WriteToClipboardEventArgs)
    |
Terminal::SetCopyToClipboardCallback (OSC 52)
    |
    +-- WriteToClipboard.raise(WriteToClipboardEventArgs)
    |
    +----- 両方 ----->
            |
            v
TermControl::_bubbleWriteToClipboard
            |
            v
TerminalPage::_copyToClipboard
    |
    +-- clipboard::open(_hostingHwnd)
    +-- clipboard::write(plain, html, rtf)
```

### データフロー図

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

ユーザーコピー操作 ----> ControlCore                   システム
OSC 52 エスケープ       RetrieveSelectedText           クリップボード
                              |                            ^
                              v                            |
                         WriteToClipboardEventArgs         |
                         (Plain, Html, Rtf)                |
                              |                            |
                              v                            |
                         TerminalPage                      |
                         _copyToClipboard ----- write ---->|
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | IDL定義 | WriteToClipboardEventArgs の WinRT 定義 |
| EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | ソース | WriteToClipboardEventArgs の C++ 実装 |
| ControlCore.idl | `src/cascadia/TerminalControl/ControlCore.idl` | IDL定義 | WriteToClipboard イベント宣言 |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | イベント発火元（2箇所） |
| ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | ヘッダ | ControlCore クラス宣言 |
| TermControl.idl | `src/cascadia/TerminalControl/TermControl.idl` | IDL定義 | WriteToClipboard バブリング宣言（L65） |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | バブリング処理 |
| TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | ソース | クリップボード書き込み実行 |
| TerminalPage.h | `src/cascadia/TerminalApp/TerminalPage.h` | ヘッダ | ハンドラ宣言 |
