# 機能設計書 70-グローバル呼び出し

## 概要

本ドキュメントは、Windows Terminalにおけるグローバル呼び出し機能（GlobalSummon）の設計を記述する。

### 本機能の処理概要

グローバルホットキーを使用して、任意のアプリケーションからTerminalウィンドウを呼び出す（前面に持ってくる）機能である。名前指定でのウィンドウ呼び出し、デスクトップ間移動、モニタ間移動、可視性のトグル、ドロップダウンアニメーションに対応する。

**業務上の目的・背景**：ターミナルを頻繁に使用する開発者が、どのアプリケーションを使用中でもグローバルホットキーでTerminalウィンドウを即座に呼び出すための機能である。QuakeスタイルのドロップダウンターミナルのようなUXを実現する。

**機能の利用シーン**：他のアプリケーション（ブラウザ、エディタなど）で作業中に、素早くターミナルに切り替えてコマンドを実行し、再び元のアプリケーションに戻る場合に利用される。ウィンドウ名を指定して特定のTerminalウィンドウを呼び出すことも可能。

**主要な処理内容**：
1. WindowEmperorがグローバルホットキーを登録する（RegisterHotKey API）
2. ホットキーが押下されると`_hotkeyPressed`が呼び出される
3. `GlobalSummonArgs`からウィンドウ名、デスクトップ動作、モニタ動作、トグル設定、ドロップダウン時間を取得する
4. `_summonWindow`が対象ウィンドウを検索（名前/ID/最新ウィンドウ）し、呼び出す
5. IslandWindow::SummonWindowが実際のウィンドウ表示/非表示/移動を実行する
6. 対象ウィンドウが見つからない場合は、新しいウィンドウを作成する

**関連システム・外部連携**：Win32 API（RegisterHotKey/UnregisterHotKey）によるシステム全体のグローバルホットキー登録。IslandWindowでのウィンドウ表示制御（SetForegroundWindow、ShowWindow、SetWindowPos等）。

**権限による制御**：グローバルホットキーの登録はプロセス全体に影響する。他のアプリケーションが同じホットキーを登録している場合は失敗する可能性がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | TerminalPage（メイン画面） | 主画面 | _HandleGlobalSummonによりグローバルホットキーでウィンドウを呼び出し |

## 機能種別

ウィンドウ呼び出し操作 / グローバルホットキー処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Name | winrt::hstring | No | 呼び出すウィンドウの名前。空の場合は最新ウィンドウ | - |
| Desktop | Model::DesktopBehavior | No | デスクトップ動作。デフォルト: ToCurrent | ToCurrent/OnCurrent/Any |
| Monitor | Model::MonitorBehavior | No | モニタ動作。デフォルト: ToMouse | ToMouse/ToCurrent/Any |
| ToggleVisibility | bool | No | 前面にある場合の可視性トグル。デフォルト: true | - |
| DropdownDuration | uint32_t | No | ドロップダウンアニメーション時間（ミリ秒）。デフォルト: 0 | - |

### 入力データソース

システムグローバルホットキー（RegisterHotKey API）。settings.jsonのグローバルホットキー設定。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ウィンドウ表示状態 | - | ウィンドウの前面表示/非表示/移動 |

### 出力先

対象ウィンドウの表示状態に反映。対象ウィンドウが存在しない場合は新しいウィンドウが作成される。

## 処理フロー

### 処理シーケンス

```
1. アプリケーション起動時/設定変更時にグローバルホットキーを登録
   └─ WindowEmperor::_setupGlobalHotkeys() で RegisterHotKey API を呼び出す
2. ユーザーがグローバルホットキーを押下
   └─ WM_HOTKEY メッセージが WindowEmperor に配信される
3. _hotkeyPressed(hotkeyIndex) が呼び出される
   └─ _hotkeys[hotkeyIndex] から GlobalSummonArgs を取得
4. SummonWindowSelectionArgs を構築
   └─ Name, Desktop, Monitor, ToggleVisibility, DropdownDuration を設定
5. _summonWindow(args) で対象ウィンドウを検索
   └─ WindowID指定 → ID一致するウィンドウを検索
   └─ WindowName指定 → 名前一致するウィンドウを検索
   └─ どちらも未指定 → 最新ウィンドウ(_mostRecentWindow)を使用
6a. [ウィンドウ発見] AppHost::HandleSummon → IslandWindow::SummonWindow
   └─ ToggleVisibility, MonitorBehavior, DropdownDuration に基づきウィンドウを操作
6b. [ウィンドウ未発見] 新しいウィンドウを作成
   └─ "wt -w {Name}" コマンドラインで CreateNewWindow を呼び出す
```

### フローチャート

```mermaid
flowchart TD
    A[グローバルホットキー押下] --> B[_hotkeyPressed]
    B --> C[GlobalSummonArgs取得]
    C --> D[SummonWindowSelectionArgs構築]
    D --> E[_summonWindow]
    E --> F{WindowID指定?}
    F -->|Yes| G[ID一致検索]
    F -->|No| H{WindowName指定?}
    H -->|Yes| I[名前一致検索]
    H -->|No| J[最新ウィンドウ取得]
    G --> K{ウィンドウ発見?}
    I --> K
    J --> K
    K -->|Yes| L[HandleSummon → SummonWindow]
    K -->|No| M[新しいウィンドウ作成]
    L --> N{ToggleVisibility & 前面?}
    N -->|Yes| O[ウィンドウ非表示]
    N -->|No| P[ウィンドウ前面表示]
    O --> Q[終了]
    P --> Q
    M --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-70-01 | グローバルホットキー登録 | GlobalSummonアクションに紐づくキーバインドがRegisterHotKey APIで登録される | アプリ起動時/設定変更時 |
| BR-70-02 | ウィンドウ検索優先順位 | WindowID > WindowName > 最新ウィンドウの順で検索する | 常に適用 |
| BR-70-03 | トグル動作 | ToggleVisibility=trueで、ウィンドウが前面にある場合は非表示にする | 前面ウィンドウ操作時 |
| BR-70-04 | モニタ移動 | ToMouse=マウスカーソルのモニタに移動、ToCurrent=現在のモニタに維持、InPlace=移動しない | ウィンドウ呼び出し時 |
| BR-70-05 | デスクトップ移動 | ToCurrent=現在のデスクトップに移動、OnCurrent=現在のデスクトップのみ対象、Any=任意のデスクトップ | ウィンドウ呼び出し時 |
| BR-70-06 | ドロップダウンアニメーション | DropdownDuration>0の場合、スライドダウンアニメーションを実行。OSのアニメーション設定を尊重 | DropdownDuration指定時 |
| BR-70-07 | ウィンドウ未発見時の新規作成 | 指定された名前のウィンドウが見つからない場合、新しいウィンドウを作成する | ウィンドウ未発見時 |
| BR-70-08 | TerminalPage側のフォールバック | グローバルホットキー登録に失敗した場合、_HandleGlobalSummonがargs.Handled(false)を返し、キーを通常入力として処理する | ホットキー登録失敗時 |
| BR-70-09 | QuakeMode特別処理 | QuakeModeFromJsonで_Name="_quake"、_DropdownDuration=200のデフォルト値が設定される | quakeModeアクション使用時 |

### 計算ロジック

特別な計算ロジックはない。

## データベース操作仕様

データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ホットキー登録失敗 | 他のアプリケーションが同じホットキーを使用中 | TerminalPage側で args.Handled(false) を返し、通常のキー入力として処理 |
| - | ウィンドウ未発見 | 指定された名前のウィンドウが存在しない | 新しいウィンドウを作成 |

### リトライ仕様

リトライ処理は不要。ホットキー登録失敗時はユーザーが設定を変更する。

## トランザクション仕様

トランザクション管理は不要。

## パフォーマンス要件

グローバルホットキーの応答は即座に行われること。DropdownDurationが指定されている場合、アニメーション中はUIスレッドがブロックされる。

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

- グローバルホットキーはシステム全体に影響するため、他のアプリケーションとの競合に注意が必要。
- RegisterHotKey APIは通常のユーザー権限で使用可能。

## 備考

- `_HandleGlobalSummon`（TerminalPage側）は、グローバルホットキー登録に失敗した場合のフォールバック処理のみを行う。通常はWindowEmperor側で直接処理される。
- QuakeMode（No.71）はGlobalSummonの特殊なケースで、`_quake`という名前のウィンドウを`DropdownDuration=200`で呼び出す。
- 設定変更時に`_setupGlobalHotkeys`が呼ばれ、既存のホットキーを全て解除してから再登録する。
- IslandWindow::SummonWindowでは、OSのアニメーション設定（SPI_GETCLIENTAREAANIMATION）を確認し、無効の場合はドロップダウンアニメーションを実行しない。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ActionArgs.h | `src/cascadia/TerminalSettingsModel/ActionArgs.h` | `GLOBAL_SUMMON_ARGS`マクロ（254-259行目）: Name, Desktop, Monitor, ToggleVisibility, DropdownDurationの5つのパラメータ |
| 1-2 | ActionArgs.h | `src/cascadia/TerminalSettingsModel/ActionArgs.h` | `GlobalSummonArgs`構造体（945-961行目）: QuakeModeFromJsonによる特殊デシリアライゼーション |
| 1-3 | WindowEmperor.h | `src/cascadia/WindowsTerminal/WindowEmperor.h` | `SummonWindowSelectionArgs`構造体（40-44行目）: WindowID, WindowName, OnCurrentDesktop, SummonBehavior |

**読解のコツ**: `GlobalSummonArgs`はActionArgsの中でも特殊で、`QuakeModeFromJson`という専用のデシリアライザを持つ。QuakeModeは`_Name="_quake"`, `_DropdownDuration=200`のデフォルト値を持つGlobalSummonの特殊ケース。

#### Step 2: グローバルホットキー登録を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WindowEmperor.cpp | `src/cascadia/WindowsTerminal/WindowEmperor.cpp` | `_setupGlobalHotkeys`（1375-1395行目付近）: ホットキーの解除と再登録 |

**主要処理フロー**:
- **1378-1381行目**: 既存のホットキーを全て解除
- **1386-1394行目**: GlobalSummonArgs型のアクションをフィルタし、RegisterHotKeyで登録

#### Step 3: ホットキー押下処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WindowEmperor.cpp | `src/cascadia/WindowsTerminal/WindowEmperor.cpp` | `_hotkeyPressed`（1295-1334行目）: ホットキーインデックスからSummonWindowSelectionArgsを構築 |

**主要処理フロー**:
- **1302行目**: `_hotkeys[hotkeyIndex]`から`GlobalSummonArgs`を取得
- **1307-1312行目**: `SummonWindowSelectionArgs`を構築
- **1314-1325行目**: Monitor動作のマッピング（Any/ToCurrent/ToMouse）
- **1327行目**: `_summonWindow(args)`でウィンドウを呼び出す
- **1332行目**: ウィンドウ未発見時に新ウィンドウ作成

#### Step 4: ウィンドウ検索・呼び出しを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | WindowEmperor.cpp | `src/cascadia/WindowsTerminal/WindowEmperor.cpp` | `_summonWindow`（712-752行目）: ウィンドウ検索とHandleSummon呼び出し |

**主要処理フロー**:
- **718-728行目**: WindowID指定時のID一致検索
- **729-738行目**: WindowName指定時の名前一致検索
- **740-743行目**: どちらも未指定時の最新ウィンドウ取得
- **750行目**: `window->HandleSummon(args.SummonBehavior)`で呼び出し

#### Step 5: 実際のウィンドウ表示処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | IslandWindow.cpp | `src/cascadia/WindowsTerminal/IslandWindow.cpp` | `SummonWindow`（1248-1308行目）: ウィンドウの表示/非表示/移動/アニメーション処理 |

**主要処理フロー**:
- **1250-1252行目**: SummonWindowBehaviorからtoggleVisibility, toMonitor, dropdownDurationを取得
- **1255-1271行目**: OSのアニメーション設定を確認し、無効時はdropdownDurationを0にする
- **1280-1302行目**: ToggleVisibility時の前面/非前面判定とモニタ間移動の処理

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

```
RegisterHotKey (グローバルホットキー登録)
    |
    +-- WindowEmperor::_setupGlobalHotkeys()      [WindowEmperor.cpp:1375]
            |
            +-- _registerHotKey(index, keyChord)

WM_HOTKEY メッセージ
    |
    +-- WindowEmperor::_hotkeyPressed()            [WindowEmperor.cpp:1295]
            |
            +-- SummonWindowSelectionArgs 構築
            +-- WindowEmperor::_summonWindow()      [WindowEmperor.cpp:712]
            |       |
            |       +-- AppHost::HandleSummon()
            |               |
            |               +-- IslandWindow::SummonWindow() [IslandWindow.cpp:1248]
            |                       |
            |                       +-- _globalActivateWindow()  (前面表示)
            |                       +-- _globalDismissWindow()   (非表示)
            |
            +-- [ウィンドウ未発見時] CreateNewWindow()

TerminalPage::_HandleGlobalSummon()                [AppActionHandlers.cpp:1147]
    |
    +-- args.Handled(false)  (フォールバック - ホットキー登録失敗時)
```

### データフロー図

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

settings.json                  _setupGlobalHotkeys()          RegisterHotKey
(globalSummon設定) ---------->  _registerHotKey()

グローバルホットキー            _hotkeyPressed()               ウィンドウ前面表示
(WM_HOTKEY) ------------------>  _summonWindow() ------------->  または非表示
                                HandleSummon()                  または新規作成
                                SummonWindow()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ActionArgs.h | `src/cascadia/TerminalSettingsModel/ActionArgs.h` | ヘッダー | GlobalSummonArgs定義、GLOBAL_SUMMON_ARGSマクロ |
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | _HandleGlobalSummonフォールバックハンドラ |
| WindowEmperor.h | `src/cascadia/WindowsTerminal/WindowEmperor.h` | ヘッダー | SummonWindowSelectionArgs構造体、_hotkeysベクタ |
| WindowEmperor.cpp | `src/cascadia/WindowsTerminal/WindowEmperor.cpp` | ソース | _setupGlobalHotkeys、_hotkeyPressed、_summonWindow実装 |
| IslandWindow.h | `src/cascadia/WindowsTerminal/IslandWindow.h` | ヘッダー | SummonWindow宣言 |
| IslandWindow.cpp | `src/cascadia/WindowsTerminal/IslandWindow.cpp` | ソース | SummonWindow実装、ウィンドウ表示/非表示/アニメーション処理 |
