# 通知設計書 32-KeySentEventArgs

## 概要

本ドキュメントは、Windows Terminal におけるキー入力通知（KeySentEventArgs）の設計仕様を記述する。KeySentEventArgs は、ユーザーがキーボードでキーを押下または解放した際に TermControl から発火されるイベントであり、仮想キーコード、スキャンコード、修飾キー状態、キー押下/解放の情報をブロードキャストする。

### 本通知の処理概要

KeySentEventArgs は、ターミナルコントロールへのキー入力をリスナーにブロードキャストするための通知機構である。入力ブロードキャスト機能（複数ペインへの同時入力）を実現するために使用される。

**業務上の目的・背景**：Windows Terminal はマルチペイン環境を提供しており、ユーザーが複数のターミナルペインに対して同時にキー入力を送信したい場合がある。KeySentEventArgs は、キー入力イベントを他のコントロールにブロードキャストすることで、入力の同時送信（ブロードキャスト入力モード）を実現するためのイベントである。

**通知の送信タイミング**：TermControl の `_TrySendKeyEvent` メソッド内で、キー入力がターミナルに送信される直前に発火する。KeySent イベントにリスナーが登録されている場合のみ、KeySentEventArgs オブジェクトが生成されイベントが発火する。これはパフォーマンス最適化のためである。

**通知の受信者**：KeySent イベントをサブスクライブしているリスナー。主にブロードキャスト入力機能を利用する TerminalPage や TerminalPaneContent 等のアプリケーション層のコンポーネントが受信する。

**通知内容の概要**：仮想キーコード（VKey, WORD型）、スキャンコード（ScanCode, WORD型）、修飾キー状態（Modifiers, ControlKeyStates型）、キー押下/解放フラグ（KeyDown, Boolean型）の4つの情報を含む。

**期待されるアクション**：受信側は、受け取ったキー入力情報を自身のターミナル接続に転送（RawWriteKeyEvent 経由）することで、ブロードキャスト入力を実現する。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（イベント raise は呼び出し元スレッド上で即時実行） |
| 優先度 | 高（ユーザー入力のリアルタイム処理） |
| リトライ | なし |

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

KeySent イベントにリスナーが登録されているかどうかを `if (KeySent)` で確認し、リスナーがある場合のみ KeySentEventArgs を生成してイベントを発火する。リスナーの登録は外部コンポーネント（TerminalPage 等）が行う。

## 通知テンプレート

### メール通知の場合

該当なし（アプリ内イベント通知）

### 本文テンプレート

該当なし（構造化データとしてイベント引数を伝達）

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| VKey | 仮想キーコード（WORD） | _TrySendKeyEvent の引数 vkey | Yes |
| ScanCode | ハードウェアスキャンコード（WORD） | _TrySendKeyEvent の引数 scanCode | Yes |
| Modifiers | 修飾キー状態（ControlKeyStates） | _TrySendKeyEvent の引数 modifiers | Yes |
| KeyDown | キー押下（true）/ 解放（false） | _TrySendKeyEvent の引数 keyDown | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| キーボード入力 | _TrySendKeyEvent メソッド呼び出し | KeySent イベントにリスナーが存在する場合 | キー押下・解放時にブロードキャスト |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| リスナー未登録 | KeySent イベントにリスナーがない場合、オブジェクト生成とイベント発火をスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがキーを押下/解放] --> B[_KeyHandler / _KeyDownHandler / _KeyUpHandler]
    B --> C[_TrySendKeyEvent 呼び出し]
    C --> D{KeySent リスナー存在?}
    D -->|Yes| E[KeySentEventArgs 生成<br/>VKey, ScanCode, Modifiers, KeyDown]
    D -->|No| F[スキップ]
    E --> G[KeySent.raise イベント発火]
    G --> H[RawWriteKeyEvent でターミナルに送信]
    F --> H
    H --> I[終了]
```

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

### 参照テーブル一覧

該当なし（インメモリイベント処理のみ）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 特になし | KeySentEventArgs の生成は単純なデータコピーであり失敗しない | - |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（キー入力頻度に依存） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（キー入力発生時に即座に通知）

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

- キー入力情報にはパスワード等の機密情報が含まれる可能性があるが、プロセス内のイベント通知であり外部送信は行わない
- ブロードキャスト入力はユーザーが明示的に有効化する機能であり、デフォルトでは他のペインへの入力転送は行われない

## 備考

- パフォーマンス最適化として、リスナーが未登録の場合は KeySentEventArgs のオブジェクト生成自体をスキップする実装になっている
- KeySent イベントは TermControl.idl で宣言されており、ControlCore.idl には含まれない（TermControl レベルのイベント）
- ブロードキャスト入力は KeySent / CharSent / StringSent の3種のイベントで構成される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | KeySentEventArgs の IDL 定義（行131-137）。VKey, ScanCode, Modifiers, KeyDown の4プロパティ |
| 1-2 | EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | KeySentEventArgs の C++ 実装（行207-220）。コンストラクタで WORD, WORD, ControlKeyStates, bool を受け取る |

**読解のコツ**: `WINRT_PROPERTY` マクロは自動的にバッキングフィールド `_VKey` 等とアクセサ `VKey()` を生成する。ControlKeyStates は修飾キー（Shift, Ctrl, Alt 等）のビットフラグ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | _TrySendKeyEvent メソッド（行1877-1891）。KeySent リスナー存在チェックと イベント発火 |

**主要処理フロー**:
1. **行1884**: `if (KeySent)` でリスナー存在チェック
2. **行1886**: `winrt::make<KeySentEventArgs>(vkey, scanCode, modifiers, keyDown)` で引数オブジェクト生成
3. **行1887**: `KeySent.raise(*this, keySentArgs)` でイベント発火
4. **行1890**: `RawWriteKeyEvent` でターミナル接続に入力を送信

#### Step 3: イベント宣言と登録

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TermControl.idl | `src/cascadia/TerminalControl/TermControl.idl` | KeySent イベント宣言（行80）|
| 3-2 | TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | til::typed_event 宣言（行215）|

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

```
TermControl::_KeyHandler (キーイベントハンドラー)
    |
    +-- TermControl::_TrySendKeyEvent(vkey, scanCode, modifiers, keyDown)
           |
           +-- [if KeySent リスナー存在]
           |       KeySentEventArgs 生成
           |       KeySent.raise(*this, args)
           |           |
           |           +-- [リスナー側] ブロードキャスト先の RawWriteKeyEvent
           |
           +-- RawWriteKeyEvent(vkey, scanCode, modifiers, keyDown)
                  |
                  +-- ControlCore::TrySendKeyEvent
```

### データフロー図

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

キーボードイベント           TermControl                     リスナー / ターミナル接続
(vkey, scanCode,     -->  _TrySendKeyEvent() -------->  KeySent イベント発火
 modifiers, keyDown)       KeySentEventArgs生成           -> ブロードキャスト先へ転送
                           RawWriteKeyEvent               -> ControlCore -> Terminal
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EventArgs.idl | `src/cascadia/TerminalControl/EventArgs.idl` | IDL定義 | KeySentEventArgs の WinRT インターフェース定義 |
| EventArgs.h | `src/cascadia/TerminalControl/EventArgs.h` | ソース | KeySentEventArgs の C++ 実装 |
| EventArgs.cpp | `src/cascadia/TerminalControl/EventArgs.cpp` | ソース | WinRT 生成コードのインクルード |
| TermControl.idl | `src/cascadia/TerminalControl/TermControl.idl` | IDL定義 | KeySent イベントの宣言 |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ソース | KeySent の til::typed_event 宣言 |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | _TrySendKeyEvent 内での KeySent イベント発火ロジック |
