# 通知設計書 61-SignalSelectionChanged

## 概要

本ドキュメントは、Windows Terminal における SignalSelectionChanged 通知の設計仕様を記載する。この通知は、ターミナル上のテキスト選択状態が変更されたことを UI Automation (UIA) クライアントに通知するためのイベントである。

### 本通知の処理概要

SignalSelectionChanged は、ターミナルコントロール内でユーザーがテキスト選択を変更した際に、スクリーンリーダーなどの支援技術にその変更を伝達する UIA 通知である。

**業務上の目的・背景**：視覚障害を持つユーザーがスクリーンリーダー（NVDA、JAWS、ナレーターなど）を使用してターミナルを操作する場合、テキスト選択の変更をリアルタイムに把握する必要がある。この通知により、UIA クライアントが選択範囲の変更を検知し、ユーザーに適切なフィードバックを提供できるようになる。Microsoft の MSAA/UIA アクセシビリティフレームワークに準拠するために必須の通知である。

**通知の送信タイミング**：レンダラーの描画サイクル（Paint cycle）において、選択範囲の変更が検出された場合に送信される。具体的には、`UiaEngine::InvalidateSelection()` が呼ばれて `_selectionChanged` フラグが true に設定された後、`UiaEngine::Present()` メソッドの実行時に `IUiaEventDispatcher::SignalSelectionChanged()` が呼び出される。

**通知の受信者**：UIA クライアント（スクリーンリーダー、自動テストフレームワークなど）が受信者である。XAML ベースの Windows Terminal では `TermControlAutomationPeer` が、WPF/HwndTerminal ベースでは `HwndTerminalAutomationPeer` が UIA イベントを発火し、OS の UIA インフラストラクチャを通じてクライアントに配信される。

**通知内容の概要**：`AutomationEvents::TextPatternOnTextSelectionChanged`（UIA_Text_TextSelectionChangedEventId）イベントが発火される。選択範囲の具体的なテキスト内容は含まず、選択が変更されたという事実のみを通知する。UIA クライアントは必要に応じて `ITextProvider::GetSelection()` を呼び出して選択範囲の詳細を取得する。

**期待されるアクション**：UIA クライアント（スクリーンリーダー等）は、このイベントを受信した後、`GetSelection()` メソッドを通じて現在の選択範囲を再取得し、ユーザーに選択内容を音声やブライユ点字で伝達する。

## 通知種別

アプリ内通知（UI Automation イベント）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（`Dispatcher.RunAsync` による UIスレッドへのディスパッチ） |
| 優先度 | Normal（`CoreDispatcherPriority::Normal`） |
| リトライ | 無し |

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

送信先は OS の UIA インフラストラクチャにより自動的に決定される。UIA イベントをリッスンしているすべてのクライアント（スクリーンリーダー、自動テストツール等）に対してブロードキャストされる。TermControl が UI ツリーから削除されている場合（`_termControl` が null の場合）はイベントの発火をスキップする。

## 通知テンプレート

### UIA イベント情報

| 項目 | 内容 |
|-----|------|
| イベント種別 | `AutomationEvents::TextPatternOnTextSelectionChanged` |
| UIA イベントID | `UIA_Text_TextSelectionChangedEventId` |
| 形式 | UIA イベント通知（データペイロードなし） |

### 本文テンプレート

```
(テンプレートなし - UIA イベントはペイロードを持たない純粋なシグナルイベント)
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| （なし） | 本通知はペイロードを持たないイベント通知のため、テンプレート変数は存在しない | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| レンダラー内部イベント | `InvalidateSelection()` 呼び出し | `_isEnabled == true` かつ `_selectionChanged == true` | レンダラーが選択領域の変更を検出した際に `_selectionChanged` フラグを設定し、`Present()` 時にイベントを発火する |
| 描画サイクル完了 | `UiaEngine::Present()` 実行 | `_isEnabled == true` かつ `_isPainting == true` | 描画サイクル終了時にフラグを確認してイベントをディスパッチする |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `_isEnabled == false` | `UiaEngine::Disable()` が呼ばれ、エンジンが無効化されている場合、イベントは発火されない |
| `_selectionChanged == false` | 選択範囲に変更がない場合、イベントは発火されない |
| TermControl が UI ツリーから削除済み | `_termControl` の weak_ref が null を返す場合、`RaiseAutomationEvent` は呼び出されない |
| Dispatcher が null | XAML Dispatcher が利用できない場合、イベントはスキップされる |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[選択範囲変更の検出] --> B[InvalidateSelection呼び出し]
    B --> C[_selectionChanged = true]
    C --> D[StartPaint - 描画サイクル開始]
    D -->|somethingToDo == true| E[EndPaint - 描画サイクル終了]
    D -->|somethingToDo == false| F[S_FALSE - スキップ]
    E --> G[Present実行]
    G --> H{_selectionChanged?}
    H -->|true| I[dispatcher->SignalSelectionChanged]
    H -->|false| J[スキップ]
    I --> K[InteractivityAutomationPeer::SignalSelectionChanged]
    K --> L[SelectionChanged.raise - イベント発火]
    L --> M[TermControlAutomationPeer::SignalSelectionChanged]
    M --> N[UiaTracing::Signal::SelectionChanged - トレース記録]
    N --> O[Dispatcher.RunAsync - UIスレッドへディスパッチ]
    O --> P{_termControl有効?}
    P -->|Yes| Q[RaiseAutomationEvent - TextPatternOnTextSelectionChanged]
    P -->|No| R[処理終了]
    Q --> S[_selectionChanged = false - フラグリセット]
    S --> T[終了]
    F --> T
    J --> T
    R --> T
```

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

### 参照テーブル一覧

該当なし（UIA通知はデータベースを使用しない）

### 更新テーブル一覧

該当なし（UIA通知はデータベースを使用しない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Dispatcher取得失敗 | XAML UIスレッドの Dispatcher が null | イベント発火をスキップ（早期リターン） |
| TermControl参照失敗 | weak_ref からの TermControl 取得失敗 | イベント発火をスキップ |
| RaiseAutomationEvent例外 | UIA イベント発火時の例外 | CATCH_LOG() でログ記録後、処理を継続 |
| UiaRaiseAutomationEvent失敗（HWND版） | Win32 UIA API 呼び出し失敗 | `LOG_IF_FAILED` でログ記録 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（レンダラーの描画サイクルに依存） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。アプリケーション実行中は常時送信可能。ただし、`UiaEngine` が `Disable()` されている場合はイベントが抑止される。複数の TermControl が存在する場合、フォーカスを持つコントロールのみが `Enable()` 状態となり、他は `Disable()` される。

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

- 本通知は選択変更という事実のみを通知し、選択内容（テキストデータ）は含まない。そのため、通知自体に個人情報や機密情報は含まれない。
- UIA クライアントが `GetSelection()` を通じて選択内容を取得する際は、OS の UIA セキュリティモデル（UIPI: User Interface Privilege Isolation）に従い、適切な権限を持つプロセスのみがアクセス可能。

## 備考

- `HwndTerminalAutomationPeer`（WPF/HWND版）では、`UiaRaiseAutomationEvent()` Win32 API を直接呼び出してイベントを発火する。XAML 版とは異なり、Dispatcher を介さず同期的に処理される。
- `UiaTracing::Signal::SelectionChanged()` によりETW（Event Tracing for Windows）にトレースログが記録される（WINEVENT_LEVEL_VERBOSE レベル）。
- レンダラーの `InvalidateSelection()` は、実際に選択範囲が変更された場合にのみ呼び出される（レンダラー側で差分チェック済み）。

---

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

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

### 推奨読解順序

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

IUiaEventDispatcher インターフェースが定義するメソッドシグネチャを理解することが出発点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | IUiaEventDispatcher.h | `src/types/IUiaEventDispatcher.h` | 24行目: `SignalSelectionChanged()` の純粋仮想関数宣言。引数なし・戻り値なしのシンプルなインターフェースであることを確認 |

**読解のコツ**: C++ の純粋仮想関数（`= 0`）は Java の interface メソッドに相当する。このインターフェースを実装するクラスが実際の通知処理を担う。

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

UiaEngine がレンダラーとして選択変更を検出し、イベントをディスパッチする流れを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | UiaRenderer.hpp | `src/renderer/uia/UiaRenderer.hpp` | 69行目: `_selectionChanged` フラグの定義。75行目: `_dispatcher` ポインタの保持 |
| 2-2 | UiaRenderer.cpp | `src/renderer/uia/UiaRenderer.cpp` | 112-118行目: `InvalidateSelection()` で `_selectionChanged = true` を設定。224-231行目: `Present()` 内で `_dispatcher->SignalSelectionChanged()` を呼び出し |

**主要処理フロー**:
1. **112行目**: `InvalidateSelection()` - 選択変更フラグの設定
2. **170行目**: `StartPaint()` - 描画サイクル開始、`_selectionChanged` を含む `somethingToDo` チェック
3. **190行目**: `EndPaint()` - 描画サイクル終了
4. **219行目**: `Present()` - フラグ確認とディスパッチャ呼び出し
5. **224-231行目**: `SignalSelectionChanged()` の呼び出し
6. **262行目**: `_selectionChanged = false` でフラグリセット

#### Step 3: InteractivityAutomationPeer の中継処理を理解する

InteractivityAutomationPeer が UiaEngine からのシグナルを受け取り、XAML イベントとして中継する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | InteractivityAutomationPeer.h | `src/cascadia/TerminalControl/InteractivityAutomationPeer.h` | 49行目: `SignalSelectionChanged()` のオーバーライド宣言。73行目: `SelectionChanged` イベントの定義 |
| 3-2 | InteractivityAutomationPeer.cpp | `src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp` | 65-68行目: `SignalSelectionChanged()` の実装 - `SelectionChanged.raise()` でイベントを発火 |

**主要処理フロー**:
- **67行目**: `SelectionChanged.raise(*this, nullptr)` - til::typed_event を使ってイベントを発火

#### Step 4: TermControlAutomationPeer の UIA イベント発火を理解する

TermControlAutomationPeer が最終的に XAML の AutomationEvent を発火する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TermControlAutomationPeer.h | `src/cascadia/TerminalControl/TermControlAutomationPeer.h` | 67行目: `SignalSelectionChanged()` のオーバーライド宣言 |
| 4-2 | TermControlAutomationPeer.cpp | `src/cascadia/TerminalControl/TermControlAutomationPeer.cpp` | 81行目: コンストラクタでの `SelectionChanged` イベントハンドラ登録。132-150行目: `SignalSelectionChanged()` の実装 |

**主要処理フロー**:
- **81行目**: `_contentAutomationPeer.SelectionChanged([this](auto&&, auto&&) { SignalSelectionChanged(); })` - イベントハンドラ登録
- **134行目**: `UiaTracing::Signal::SelectionChanged()` - ETWトレース記録
- **140行目**: `dispatcher.RunAsync(...)` - UIスレッドへの非同期ディスパッチ
- **146行目**: `RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged)` - UIA イベント発火

#### Step 5: HwndTerminalAutomationPeer の代替実装を理解する

WPF/HWND ベースの代替実装パスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | HwndTerminalAutomationPeer.hpp | `src/cascadia/TerminalControl/HwndTerminalAutomationPeer.hpp` | 35行目: `SignalSelectionChanged()` のオーバーライド宣言 |
| 5-2 | HwndTerminalAutomationPeer.cpp | `src/cascadia/TerminalControl/HwndTerminalAutomationPeer.cpp` | 104-108行目: Win32 UIA API を直接呼び出す実装 |

**主要処理フロー**:
- **106行目**: `UiaTracing::Signal::SelectionChanged()` - ETWトレース
- **107行目**: `UiaRaiseAutomationEvent(this, UIA_Text_TextSelectionChangedEventId)` - Win32 UIA API直接呼び出し

#### Step 6: トレーシング処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | UiaTracing.h | `src/types/UiaTracing.h` | 86行目: `Signal::SelectionChanged()` の宣言 |
| 6-2 | UiaTracing.cpp | `src/types/UiaTracing.cpp` | 720-731行目: ETW `TraceLoggingWrite` による `"Signal::SelectionChanged"` トレース出力 |

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

```
Renderer (描画サイクル)
    │
    ├─ UiaEngine::InvalidateSelection()          [UiaRenderer.cpp:112]
    │      └─ _selectionChanged = true
    │
    ├─ UiaEngine::StartPaint()                    [UiaRenderer.cpp:170]
    │      └─ somethingToDo チェック
    │
    ├─ UiaEngine::EndPaint()                      [UiaRenderer.cpp:190]
    │
    └─ UiaEngine::Present()                       [UiaRenderer.cpp:219]
           │
           └─ _dispatcher->SignalSelectionChanged()
                  │
                  ├─[XAML版] InteractivityAutomationPeer::SignalSelectionChanged()
                  │      └─ SelectionChanged.raise()
                  │             └─ TermControlAutomationPeer::SignalSelectionChanged()
                  │                    ├─ UiaTracing::Signal::SelectionChanged()
                  │                    └─ Dispatcher.RunAsync()
                  │                           └─ RaiseAutomationEvent(TextPatternOnTextSelectionChanged)
                  │
                  └─[HWND版] HwndTerminalAutomationPeer::SignalSelectionChanged()
                         ├─ UiaTracing::Signal::SelectionChanged()
                         └─ UiaRaiseAutomationEvent(UIA_Text_TextSelectionChangedEventId)
```

### データフロー図

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

選択範囲変更        ───▶  UiaEngine::InvalidateSelection()   ───▶  _selectionChanged = true
  (til::rect)                    │
                                 ▼
                           UiaEngine::Present()                ───▶  IUiaEventDispatcher
                                 │                                    ::SignalSelectionChanged()
                                 ▼
                           AutomationPeer                      ───▶  UIA イベント
                           (XAML or HWND)                             (TextPatternOnTextSelectionChanged)
                                 │
                                 ▼
                           OS UIA Infrastructure               ───▶  スクリーンリーダー等の
                                                                      UIA クライアント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| IUiaEventDispatcher.h | `src/types/IUiaEventDispatcher.h` | ソース（ヘッダー） | UIA イベントディスパッチャのインターフェース定義 |
| UiaRenderer.hpp | `src/renderer/uia/UiaRenderer.hpp` | ソース（ヘッダー） | UIA レンダラーエンジンのクラス定義 |
| UiaRenderer.cpp | `src/renderer/uia/UiaRenderer.cpp` | ソース | UIA レンダラーエンジンの実装（InvalidateSelection, Present） |
| InteractivityAutomationPeer.h | `src/cascadia/TerminalControl/InteractivityAutomationPeer.h` | ソース（ヘッダー） | Interactivity 層の AutomationPeer 定義 |
| InteractivityAutomationPeer.cpp | `src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp` | ソース | Interactivity 層の SignalSelectionChanged 実装 |
| TermControlAutomationPeer.h | `src/cascadia/TerminalControl/TermControlAutomationPeer.h` | ソース（ヘッダー） | TermControl の AutomationPeer 定義 |
| TermControlAutomationPeer.cpp | `src/cascadia/TerminalControl/TermControlAutomationPeer.cpp` | ソース | XAML UIA イベント発火の実装 |
| HwndTerminalAutomationPeer.hpp | `src/cascadia/TerminalControl/HwndTerminalAutomationPeer.hpp` | ソース（ヘッダー） | HWND 版 AutomationPeer 定義 |
| HwndTerminalAutomationPeer.cpp | `src/cascadia/TerminalControl/HwndTerminalAutomationPeer.cpp` | ソース | HWND 版の Win32 UIA イベント発火実装 |
| UiaTracing.h | `src/types/UiaTracing.h` | ソース（ヘッダー） | UIA トレーシングクラス定義 |
| UiaTracing.cpp | `src/types/UiaTracing.cpp` | ソース | ETW トレースログ出力の実装 |
