# 通知設計書 55-FocusRequested

## 概要

本ドキュメントは、Windows Terminal における FocusRequested イベント通知の設計仕様を記述する。ペインコンテンツからフォーカスが要求された際に発火し、当該ペインにUIフォーカスを移動させるためのアクション通知である。

### 本通知の処理概要

FocusRequested は、IPaneContent インターフェースで定義されたイベントであり、ペインコンテンツがフォーカスを要求する際に発火する。具体的には、TerminalPaneContent において「フォーカスフォローマウス」（Focus Follow Mouse）機能が有効な場合に、マウスポインタがペイン上に移動した際にトリガーされる。受信した Tab は当該ペインにフォーカスを設定する。

**業務上の目的・背景**：Windows Terminal は複数のペインを同時に表示できるため、ユーザーがマウスカーソルを移動するだけでペイン間のフォーカスを切り替えられる「フォーカスフォローマウス」機能を提供している。FocusRequested イベントはこの機能の中核を担い、マウスの移動に応じてペインのフォーカス状態を自動的に更新する仕組みを実現する。

**通知の送信タイミング**：TermControl の PointerMoved イベントハンドラ内で、コントロールが未フォーカスかつ FocusFollowMouse 設定が有効な場合に、FocusFollowMouseRequested イベントが発火される。TerminalPaneContent はこれを受信し、FocusRequested イベントに変換して上位層に伝搬する。

**通知の受信者**：Tab クラスが FocusRequested イベントを購読し、UIスレッドで当該ペインコンテンツにフォーカスを設定する。フォーカスの種類は FocusState::Pointer である。

**通知内容の概要**：引数なし（nullptr）のシンプルなイベント通知。sender として IPaneContent インスタンスが渡される。

**期待されるアクション**：Tab は受信したペインコンテンツに対して Focus(FocusState::Pointer) を呼び出し、当該ペインにUIフォーカスを移動させる。ただし、Tab 自身がフォーカスされている場合にのみフォーカス移動を行う。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（UIスレッドへのディスパッチ） |
| 優先度 | 中 |
| リトライ | 無 |

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

BasicPaneEvents 構造体の FocusRequested イベントに登録されたハンドラに通知。Tab クラスが各ペインコンテンツの FocusRequested イベントにハンドラを登録する。

## 通知テンプレート

### イベント引数

| 項目 | 内容 |
|-----|------|
| イベント型 | `TypedEventHandler<IPaneContent, Object>` |
| 定義元 | `IPaneContent.idl` L48, `BasicPaneEvents.h` L17 |
| プロパティ | なし（sender=IPaneContent, args=nullptr） |

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

```cpp
// IPaneContent.idl
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> FocusRequested;

// BasicPaneEvents.h
til::typed_event<IPaneContent> FocusRequested;
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| （なし） | イベント引数を持たない | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| マウス操作 | PointerMoved | コントロール未フォーカス AND FocusFollowMouse 設定有効 | TermControl.cpp L2008-2010: マウスが未フォーカスペイン上に移動した際 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| コントロールがフォーカス済み | `!_focused` が false の場合はイベント不発火 |
| FocusFollowMouse 設定が無効 | `_core.Settings().FocusFollowMouse()` が false の場合はイベント不発火 |
| Tab が未フォーカス | Tab._focused() が false の場合、受信してもフォーカス移動しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[マウスが TermControl 上に移動] --> B{_focused チェック}
    B -->|未フォーカス| C{FocusFollowMouse 設定チェック}
    B -->|フォーカス済み| D[処理なし]
    C -->|有効| E[FocusFollowMouseRequested.raise]
    C -->|無効| D
    E --> F[TerminalPaneContent._controlFocusFollowMouseRequested]
    F --> G[FocusRequested.raise]
    G --> H[Tab: FocusRequested ハンドラ]
    H --> I[co_await resume_foreground]
    I --> J{Tab._focused チェック}
    J -->|フォーカス中| K[sender.Focus FocusState::Pointer]
    J -->|未フォーカス| L[処理なし]
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ハンドラ未登録 | TerminalPaneContent が破棄済み | weak_ref チェックによりスキップ |
| UIスレッド不正 | ディスパッチャーが利用不可 | co_await 失敗時にコルーチン終了 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（ただしマウス移動ごとの発火は未フォーカス時のみ） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

- FocusFollowMouse は設定で無効化できるため、意図しないフォーカス移動を防止可能
- Tab._focused() チェックにより、バックグラウンドタブでの不正なフォーカス奪取を防止

## 備考

- FocusFollowMouse はプロファイル設定の一部であり、設定ファイルで有効/無効を切り替えられる
- TermControl の FocusFollowMouseRequested イベント（TermControl.idl L75）と IPaneContent の FocusRequested イベントは名前が異なるが、TerminalPaneContent が中間で変換を行う
- Tab のハンドラは safe_void_coroutine であり、UIスレッドへの切り替え（co_await resume_foreground）を行ってからフォーカス設定を実行する

---

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

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

### 推奨読解順序

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

FocusRequested イベントの定義を2箇所で確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | IPaneContent.idl | `src/cascadia/TerminalApp/IPaneContent.idl` | L48: IPaneContent インターフェースでの FocusRequested 宣言。sender=IPaneContent |
| 1-2 | BasicPaneEvents.h | `src/cascadia/TerminalApp/BasicPaneEvents.h` | L17: til::typed_event<IPaneContent> FocusRequested の定義 |
| 1-3 | TermControl.idl | `src/cascadia/TerminalControl/TermControl.idl` | L75: FocusFollowMouseRequested イベント宣言 |

**読解のコツ**: FocusFollowMouseRequested（TermControl レベル）と FocusRequested（IPaneContent レベル）の対応関係を理解することが重要。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | L2003-2011: PointerMoved ハンドラ内の FocusFollowMouse チェックと FocusFollowMouseRequested.raise |

**主要処理フロー**:
1. **L2008**: `!_focused && _core.Settings().FocusFollowMouse()` の条件チェック
2. **L2010**: `FocusFollowMouseRequested.raise(*this, nullptr)` でイベント発火

#### Step 3: 変換層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TerminalPaneContent.cpp | `src/cascadia/TerminalApp/TerminalPaneContent.cpp` | L44: _setupControlEvents で FocusFollowMouseRequested ハンドラ登録 |
| 3-2 | TerminalPaneContent.cpp | `src/cascadia/TerminalApp/TerminalPaneContent.cpp` | L180-182: _controlFocusFollowMouseRequested で FocusRequested.raise に変換 |

#### Step 4: 受信・処理層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | L1123-1133: FocusRequested ハンドラ登録。co_await で UIスレッドに切り替え、_focused チェック後に Focus(FocusState::Pointer) を呼び出し |

**主要処理フロー**:
- **L1127**: `co_await wil::resume_foreground(dispatcher)` でUIスレッドへ
- **L1130-1132**: `tab->_focused()` チェック後、`sender.Focus(FocusState::Pointer)` を呼び出し

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

```
TermControl::PointerMoved
    |
    +-- _focused チェック & FocusFollowMouse 設定チェック
    +-- FocusFollowMouseRequested.raise(*this, nullptr)
            |
            v
TerminalPaneContent::_controlFocusFollowMouseRequested
    |
    +-- FocusRequested.raise(*this, nullptr)
            |
            v
Tab::FocusRequested ハンドラ (coroutine)
    |
    +-- co_await resume_foreground(dispatcher)
    +-- _focused() チェック
    +-- sender.Focus(FocusState::Pointer)
```

### データフロー図

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

マウス移動 -----------> TermControl                   UIフォーカス移動
(PointerMoved)         (FocusFollowMouse チェック)
                              |
                              v
                         TerminalPaneContent
                         (FocusRequested に変換)
                              |
                              v
                         Tab
                         (Focus(FocusState::Pointer))
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| IPaneContent.idl | `src/cascadia/TerminalApp/IPaneContent.idl` | IDL定義 | FocusRequested イベント宣言 |
| BasicPaneEvents.h | `src/cascadia/TerminalApp/BasicPaneEvents.h` | ヘッダ | FocusRequested イベントのC++定義 |
| TermControl.idl | `src/cascadia/TerminalControl/TermControl.idl` | IDL定義 | FocusFollowMouseRequested イベント宣言 |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | PointerMoved 内でのイベント発火 |
| TerminalPaneContent.cpp | `src/cascadia/TerminalApp/TerminalPaneContent.cpp` | ソース | FocusFollowMouseRequested -> FocusRequested 変換 |
| TerminalPaneContent.h | `src/cascadia/TerminalApp/TerminalPaneContent.h` | ヘッダ | ハンドラ宣言 |
| Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | ソース | FocusRequested 受信・フォーカス設定 |
| Tab.h | `src/cascadia/TerminalApp/Tab.h` | ヘッダ | Tab クラス宣言 |
