# 通知設計書 19-RegionChanged

## 概要

コンソール領域の更新をスクリーンリーダー等のアクセシビリティクライアントに通知するアクセシビリティイベントの設計書である。MSAAのEVENT_CONSOLE_UPDATE_REGIONイベント（またはEVENT_CONSOLE_UPDATE_SIMPLE）とUIAのUIA_Text_TextChangedEventIdイベントを発火する。

### 本通知の処理概要

RegionChangedは、ターミナルのテキストバッファ内の領域が更新された際に、MSAA/UIAを通じてアクセシビリティクライアントに通知するイベントである。テキスト出力、画面クリア、スクロール操作などでバッファ内容が変更された場合にトリガーされる。

**業務上の目的・背景**：スクリーンリーダーは、コンソール領域の更新を検知してユーザーに新しいテキスト内容を読み上げる。EVENT_CONSOLE_UPDATE_REGIONは更新領域の範囲をスクリーンリーダーに通知し、スクリーンリーダーが更新されたテキストのみを効率的に再読み込みできるようにする。UIAのTextChangedイベントも同様の目的で発火され、最新のスクリーンリーダー（UIA対応版のNVDA等）で利用される。

**通知の送信タイミング**：テキストバッファの任意の領域が変更された時点でトリガーされる。パフォーマンス最適化のため、`WantsRegionChangedEvents()`メソッドで事前にイベントの必要性をチェックし、不要な場合は呼び出し自体が回避される。

**通知の受信者**：MSAA/UIAを通じて、システムに登録されたアクセシビリティクライアント。

**通知内容の概要**：更新領域の開始座標と終了座標（バッファ座標、包含的）がEVENT_CONSOLE_UPDATE_REGIONのパラメータとして含まれる。1文字のみの更新の場合はEVENT_CONSOLE_UPDATE_SIMPLEが代わりに発火され、文字と属性が含まれる。UIAではUIA_Text_TextChangedEventIdが発火される。

**期待されるアクション**：スクリーンリーダーが更新領域のテキストを再取得し、新しい出力内容をユーザーに音声で通知する。

## 通知種別

アクセシビリティ通知（MSAA EVENT_CONSOLE_UPDATE_REGION / EVENT_CONSOLE_UPDATE_SIMPLE, UIA UIA_Text_TextChangedEventId）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（タイマーベースのデバウンス後、バックグラウンドスレッドで発火） |
| 優先度 | 中 |
| リトライ | 無し |

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

システムに登録された全てのアクセシビリティクライアントに対してブロードキャストされる。

## 通知テンプレート

### イベント情報

| 項目 | 内容 |
|-----|------|
| MSAA Event ID（通常） | EVENT_CONSOLE_UPDATE_REGION |
| MSAA Event ID（1文字） | EVENT_CONSOLE_UPDATE_SIMPLE |
| MSAA idObject（通常） | MAKELONG(beginX, beginY) |
| MSAA idChild（通常） | MAKELONG(endX, endY) |
| MSAA idObject（1文字） | MAKELONG(x, y) |
| MSAA idChild（1文字） | MAKELONG(character, attributes) |
| UIA Event ID | UIA_Text_TextChangedEventId |

### 本文テンプレート

```
（テキストメッセージは含まない。構造化されたイベントデータのみ。）
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| begin | 更新領域の開始座標 | til::point | Yes |
| end | 更新領域の終了座標（包含的） | til::point | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| システム内部 | テキストバッファ更新 | `WantsRegionChangedEvents() == true` | テキスト出力、画面クリア等 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| WantsRegionChangedEventsがfalse | MSAAのEVENT_CONSOLE_UPDATE_REGIONフックが未設置かつUIAプロバイダが未設定の場合 |
| begin > end | 不正な座標範囲の場合は早期リターン |
| MSAAとUIAの両方が対象外 | 個別のフラグチェックで両方がfalseの場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[テキストバッファ更新] --> B{WantsRegionChangedEvents?}
    B -->|No| C[スキップ]
    B -->|Yes| D[AccessibilityNotifier::RegionChanged]
    D --> E{begin > end?}
    E -->|Yes| C
    E -->|No| F[MSAA/UIAフラグチェック]
    F --> G[排他ロック取得]
    G --> H{MSAA有効?}
    H -->|Yes| I[更新領域の和集合を計算]
    H -->|No| J{UIA有効?}
    I --> J
    J -->|Yes| K[textChanged=true記録]
    J -->|No| L[_timerSet呼び出し]
    K --> L
    L --> M[タイマーまたは即座にイベント発火]
    M --> N{1文字更新?}
    N -->|Yes| O[EVENT_CONSOLE_UPDATE_SIMPLE]
    N -->|No| P[EVENT_CONSOLE_UPDATE_REGION]
    O --> Q[UIA_Text_TextChangedEventId]
    P --> Q
```

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

### 参照テーブル一覧

該当なし。テキストバッファ（メモリ）から文字と属性の情報を取得する。

### 更新テーブル一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| NotifyWinEvent失敗 | システムエラー | エラーは無視 |
| UiaRaiseAutomationEvent失敗 | UIAプロバイダのエラー | `LOG_IF_FAILED`でログ記録 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| デバウンス | タイマーベースのデバウンス。複数の領域更新がタイマー発火までに和集合としてマージされる |
| 事前チェック | `WantsRegionChangedEvents()`による呼び出し元でのフィルタリング |

### 配信時間帯

制限なし。

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

更新領域の座標と文字内容がアクセシビリティAPIを通じて公開される。EVENT_CONSOLE_UPDATE_SIMPLEの場合は文字そのものがイベントに含まれる。

## 備考

- 領域の和集合計算：連続する複数のRegionChanged呼び出しでは、更新領域がマージされる。開始座標は最小値、終了座標は最大値が採用される（AccessibilityNotifier.cpp 行222-233）。
- EVENT_CONSOLE_UPDATE_SIMPLEの特殊処理：1文字のみの更新（beg == end）の場合、NVDAのレガシーモードで読み上げが行われないため、代わりにEVENT_CONSOLE_UPDATE_SIMPLEを発火する（行417-424）。このイベントには文字（UCS-2）と旧来の属性が含まれる。
- `WantsRegionChangedEvents()`は高頻度で呼び出される可能性があるため、`IsWinEventHookInstalled`のチェックを含めたパフォーマンス最適化が施されている。
- ScrollBufferイベントが発生した場合、既にプライムされた領域座標のY座標がスクロールデルタ分だけ調整される（行266-269）。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AccessibilityNotifier.h | `src/host/AccessibilityNotifier.h` | 行49-54: State構造体のeventConsoleUpdateRegion関連フィールド（BeginX/Y, EndX/Y, Primed）。行66: textChangedフラグ |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AccessibilityNotifier.cpp | `src/host/AccessibilityNotifier.cpp` | 行186-191: `WantsRegionChangedEvents`メソッド。イベントの必要性を事前判定 |
| 2-2 | AccessibilityNotifier.cpp | `src/host/AccessibilityNotifier.cpp` | 行195-242: `RegionChanged`メソッド。begin/end座標の受け取り、領域和集合の計算、textChangedフラグの設定 |

**主要処理フロー**:
1. **行197-199**: `begin > end`の範囲チェック
2. **行202-203**: MSAAとUIAの有効性チェック
3. **行212-233**: MSAA有効時の領域和集合計算。初回は初期化、2回目以降は和集合を取る
4. **行237-239**: UIA有効時の`textChanged = true`設定
5. **行241**: `_timerSet()`呼び出し

#### Step 3: イベント発火処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AccessibilityNotifier.cpp | `src/host/AccessibilityNotifier.cpp` | 行386-489: `_emitEvents`内のregion処理。座標変換、1文字判定、SIMPLE/REGION切り替え |
| 3-2 | AccessibilityNotifier.cpp | `src/host/AccessibilityNotifier.cpp` | 行491-495: TextChangedイベントの発火 |

**主要処理フロー**:
- **行391-426**: 更新領域の準備。1文字更新の場合はUpdateSimple用のデータを準備
- **行473-489**: EVENT_CONSOLE_UPDATE_SIMPLE / EVENT_CONSOLE_UPDATE_REGIONの発火
- **行491-495**: UIA_Text_TextChangedEventIdの発火

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

```
呼び出し元（host/_stream.cpp等）
    |
    +-- WantsRegionChangedEvents() チェック
    |       |
    |       +-- IsWinEventHookInstalled(EVENT_CONSOLE_UPDATE_REGION)
    |       +-- _uiaProvider != nullptr
    |
    +-- RegionChanged(begin, end)
            |
            +-- 範囲チェック (begin > end)
            +-- MSAA: 領域和集合計算
            +-- UIA: textChanged = true
            +-- _timerSet()
                    |
                    +-- _emitEvents()
                            |
                            +-- [1文字] NotifyWinEvent(EVENT_CONSOLE_UPDATE_SIMPLE)
                            +-- [複数文字] NotifyWinEvent(EVENT_CONSOLE_UPDATE_REGION)
                            +-- UiaRaiseAutomationEvent(UIA_Text_TextChangedEventId)
```

### データフロー図

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

テキストバッファ更新        AccessibilityNotifier
(begin, end座標)     -----> RegionChanged()
        |                       |
        v                  領域和集合計算                     [MSAA]
    til::point             (マージ)                          EVENT_CONSOLE_UPDATE_REGION
    til::point                  |                            または
                           _timerSet()                       EVENT_CONSOLE_UPDATE_SIMPLE
                                |
                           _emitEvents()                     [UIA]
                                |                            UIA_Text_TextChangedEventId
                           1文字判定
                           文字・属性取得
                           (コンソールロック下)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AccessibilityNotifier.h | `src/host/AccessibilityNotifier.h` | ヘッダー | RegionChanged・WantsRegionChangedEventsメソッド宣言 |
| AccessibilityNotifier.cpp | `src/host/AccessibilityNotifier.cpp` | ソース | RegionChanged・_emitEvents実装 |
| _stream.cpp | `src/host/_stream.cpp` | ソース | RegionChangedの主要呼び出し元の一つ |
