# 通知設計書 26-CM_UPDATE_CLIPBOARD

## 概要

本ドキュメントは、Windows Terminalのコンソールホスト（conhost）におけるCM_UPDATE_CLIPBOARDウィンドウメッセージ通知の設計を記述する。コンソールの出力テキストをシステムクリップボードにコピーする必要がある際に、メインGUIスレッドでのクリップボード操作を要求するカスタムWindowsメッセージである。

### 本通知の処理概要

CM_UPDATE_CLIPBOARDは、コンソールからテキストをシステムクリップボードにコピーする際に、PostMessageWを使用してウィンドウメッセージキューに投入されるカスタムメッセージである。

**業務上の目的・背景**：Windowsのクリップボード操作はメインGUIスレッドからしか行えない制約がある。コンソール内部の処理スレッドでクリップボードへのコピーが必要になった場合、直接クリップボードAPIを呼び出すことができない。このクロススレッド通信を実現するためにCM_UPDATE_CLIPBOARDメッセージが使用される。ペンディングデータの管理により、短時間に複数回のコピー要求が発生した場合でもメッセージの重複送信を回避する。

**通知の送信タイミング**：CONSOLE_INFORMATION::CopyTextToClipboardメソッド内で、ペンディングクリップボードテキストがまだ設定されていない場合にPostMessageWで送信される。既にペンディングテキストがある場合はテキストのみ更新し、メッセージは再送信しない。

**通知の受信者**：コンソールウィンドウのウィンドウプロシージャ（Window::ConsoleWindowProc）。

**通知内容の概要**：クリップボード更新要求のシグナルのみ。コピー対象のテキストはCONSOLE_INFORMATION::_pendingClipboardTextメンバ変数に保持される。

**期待されるアクション**：ウィンドウプロシージャがUsePendingClipboardTextでテキストを取得し、Clipboard::Instance().CopyTextを呼び出してシステムクリップボードにテキストをコピーする。

## 通知種別

ウィンドウメッセージ通知（カスタムWindowsメッセージ: WM_USER + 20）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（PostMessageW） |
| 優先度 | 中 |
| リトライ | 無 |

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

コンソールウィンドウハンドルに対して直接PostMessageWで送信する。ウィンドウハンドルはServiceLocator::LocateConsoleWindow()->GetWindowHandle()で取得する。

## 通知テンプレート

### メッセージパラメータ

| 項目 | 内容 |
|-----|------|
| メッセージID | CM_UPDATE_CLIPBOARD (WM_USER + 20) |
| wParam | 0 |
| lParam | 0 |

### 本文テンプレート

```
PostMessageW(window->GetWindowHandle(), CM_UPDATE_CLIPBOARD, 0, 0)
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| _pendingClipboardText | コピー対象のテキスト | CONSOLE_INFORMATION メンバ変数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部処理 | CONSOLE_INFORMATION::CopyTextToClipboard | ウィンドウが存在し、ペンディングテキストが未設定 | OSC 52（クリップボード操作VTシーケンス）等でクリップボードコピーが要求された際 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ウィンドウなし | ServiceLocator::LocateConsoleWindow() が null の場合 |
| ペンディングテキスト既存 | _pendingClipboardText が既に has_value() の場合（テキストのみ更新、メッセージ不要） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[クリップボードコピー要求] --> B[CopyTextToClipboard呼び出し]
    B --> C{ウィンドウが存在?}
    C -->|No| D[何もしない]
    C -->|Yes| E{ペンディングテキスト既存?}
    E -->|Yes| F[テキストのみ更新、メッセージ不要]
    E -->|No| G[_pendingClipboardTextにテキスト設定]
    G --> H[PostMessageW CM_UPDATE_CLIPBOARD]
    H --> I[ウィンドウプロシージャで受信]
    I --> J[UsePendingClipboardTextでテキスト取得]
    J --> K[Clipboard::Instance().CopyText実行]
    K --> L[クリップボード更新完了]
    F --> L
    D --> L
```

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

### 参照テーブル一覧

該当なし

### 更新テーブル一覧

該当なし（システムクリップボードを更新）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| PostMessageW失敗 | ウィンドウが既に破棄されている等 | PostMessageWの戻り値はチェックされない |
| クリップボードアクセス失敗 | 他のアプリケーションがクリップボードをロック中 | Clipboard::CopyText内部で処理される |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

ペンディングテキストのメカニズムにより、実質的にメッセージの重複送信が防止される。前のCM_UPDATE_CLIPBOARDメッセージが処理される前に新しいコピー要求が来た場合、テキストのみが更新されてメッセージは再送信されない。

### 配信時間帯

制限なし

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

- クリップボードに書き込まれるテキストは、コンソールアプリケーションが生成した内容である
- クリップボード操作はOS標準のセキュリティモデルに従う
- _pendingClipboardTextはプロセス内メモリに保持されるため、外部からのアクセスリスクは低い

## 備考

- UsePendingClipboardTextはstd::exchangeを使用して、ペンディングテキストを取得すると同時にクリアする。これにより、次のCopyTextToClipboard呼び出しが新しいメッセージを送信できるようになる
- CM_UPDATE_CLIPBOARDメッセージIDはWM_USER+20であり、conhost専用のメッセージである

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CustomWindowMessages.h | `src/interactivity/win32/CustomWindowMessages.h` | CM_UPDATE_CLIPBOARDの定義（行32: WM_USER+20） |

**読解のコツ**: CM_UPDATE_CLIPBOARDはconhost専用のメッセージで、Windows Terminal（BaseWindow）には定義されていない。

#### Step 2: 送信側を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | consoleInformation.cpp | `src/host/consoleInformation.cpp` | CopyTextToClipboard関数（行183-198） |

**主要処理フロー**:
1. **行185**: ウィンドウの存在確認
2. **行192**: 既存ペンディングテキストの有無チェック
3. **行193**: `_pendingClipboardText = text` でテキスト設定
4. **行196**: `PostMessageW(window->GetWindowHandle(), CM_UPDATE_CLIPBOARD, 0, 0)` でメッセージ送信

#### Step 3: 受信側を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | windowproc.cpp | `src/interactivity/win32/windowproc.cpp` | CM_UPDATE_CLIPBOARDハンドラ（行776-783） |
| 3-2 | consoleInformation.cpp | `src/host/consoleInformation.cpp` | UsePendingClipboardText関数（行201-206） |

**主要処理フロー**:
- **windowproc.cpp 行778**: `gci.UsePendingClipboardText()` でペンディングテキスト取得
- **windowproc.cpp 行780**: `Clipboard::Instance().CopyText(clipboardText.value())` でクリップボードにコピー
- **consoleInformation.cpp 行206**: `std::exchange(_pendingClipboardText, {})` でペンディングテキストをクリア

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

```
CONSOLE_INFORMATION::CopyTextToClipboard (consoleInformation.cpp:183)
    |
    +-- PostMessageW(CM_UPDATE_CLIPBOARD)
           |
           +-- Window::ConsoleWindowProc (windowproc.cpp:776)
                  |
                  +-- CONSOLE_INFORMATION::UsePendingClipboardText()
                  |      |
                  |      +-- std::exchange(_pendingClipboardText, {})
                  |
                  +-- Clipboard::Instance().CopyText()
```

### データフロー図

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

コピー対象テキスト         CopyTextToClipboard            システムクリップボード
(VTシーケンス等) -------> _pendingClipboardText  -------> Clipboard::CopyText()
                          PostMessageW                     テキストがクリップボードに
                          CM_UPDATE_CLIPBOARD               コピーされる
                               |
                               v
                          ConsoleWindowProc
                          UsePendingClipboardText()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CustomWindowMessages.h | `src/interactivity/win32/CustomWindowMessages.h` | ソース（ヘッダ） | CM_UPDATE_CLIPBOARDメッセージID定義 |
| consoleInformation.cpp | `src/host/consoleInformation.cpp` | ソース（実装） | CopyTextToClipboard、UsePendingClipboardText |
| windowproc.cpp | `src/interactivity/win32/windowproc.cpp` | ソース（実装） | CM_UPDATE_CLIPBOARDハンドラ |
| clipboard.hpp | `src/interactivity/win32/clipboard.hpp` | ソース（ヘッダ） | Clipboardクラス定義 |
