# 通知設計書 41-キー割当変更通知

## 概要

本ドキュメントは、StaxRipアプリケーションにおけるキーボードショートカット割り当て変更時に表示される通知「Key detached and assigned」の設計を記載する。

### 本通知の処理概要

本通知は、カスタムメニューエディタにおいてユーザーがキーボードショートカットを割り当てた際に、既に他のメニュー項目に割り当てられていたキーが解除され、新しいメニュー項目に再割り当てされた場合に表示される情報通知である。

**業務上の目的・背景**：キーボードショートカットはアプリケーション操作の効率化に不可欠な機能である。しかし、同一のキーを複数のコマンドに割り当てることはできないため、重複が発生した場合にユーザーに明確なフィードバックを提供し、どのコマンドからキーが解除され、どのコマンドに再割り当てされたかを把握できるようにする必要がある。この通知により、ユーザーは意図しないショートカットの変更を認識し、必要に応じて調整を行うことができる。

**通知の送信タイミング**：CustomMenuEditorにおいて、ユーザーがショートカットキーの入力フィールド（tbHotkey）でキーを押下した際に、そのキーが既に他のメニュー項目に割り当てられていた場合に即時表示される。

**通知の受信者**：カスタムメニューエディタを操作中のユーザー。アプリケーション内通知のため、現在のセッションで操作を行っているユーザーのみが受信する。

**通知内容の概要**：解除されたキー、解除元のメニュー項目名、新しく割り当てられたメニュー項目名が含まれるメッセージが表示される。例：「Ctrl+S detached from Save and assigned to SaveAs instead.」

**期待されるアクション**：ユーザーは通知内容を確認し、変更が意図通りであることを確認する。必要に応じて、解除されたコマンドに新しいショートカットキーを割り当て直す。

## 通知種別

アプリ内通知（TaskDialogによるモーダルダイアログ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 中 |
| リトライ | なし |

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

カスタムメニューエディタを操作中のアクティブユーザーに対して、即時モーダルダイアログとして表示される。

## 通知テンプレート

### アプリ内通知の場合

| 項目 | 内容 |
|-----|------|
| ダイアログ種別 | 情報（Information） |
| アイコン | Info |
| ボタン | OK |

### 本文テンプレート

```
{KeyString} detached from {PreviousMenuItem} and assigned to {NewMenuItem} instead.
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| KeyString | 割り当てられたキーの文字列表現 | KeysHelp.GetKeyString(item.KeyData) | Yes |
| PreviousMenuItem | キーが解除されたメニュー項目名 | current.Text.TrimEnd("."c) | Yes |
| NewMenuItem | キーが新しく割り当てられたメニュー項目名 | item.Text.TrimEnd("."c) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | tbHotkey_KeyDown | 入力されたキーが他のメニュー項目に既に割り当て済み | ショートカットキー入力時に重複チェックを実行 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 重複なし | 入力されたキーが他のメニュー項目に割り当てられていない場合 |
| 同一アイテムへの再入力 | 同じメニュー項目に対して同じキーを再度入力した場合（キー解除動作となる） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがショートカットキーを入力] --> B{修飾キーのみか?}
    B -->|Yes| I[処理終了]
    B -->|No| C{同一キーの再入力か?}
    C -->|Yes| D[キー解除]
    C -->|No| E[キー割り当て実行]
    E --> F{他のメニュー項目に同一キーが存在?}
    F -->|No| I
    F -->|Yes| G[既存割り当てを解除]
    G --> H[MsgInfo表示]
    H --> I[終了]
    D --> I
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| メモリ内TreeNode | メニュー項目とキー割り当て情報の参照 | 永続化はカスタムメニュー保存時 |

### テーブル別参照項目詳細

#### CustomMenuItem（メモリ内オブジェクト）

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| KeyData | 現在のキー割り当て | TreeViewの全ノードを走査 |
| Text | メニュー項目名 | 通知メッセージ生成用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| CustomMenuItem.KeyData | UPDATE | 重複キーの解除（Keys.None設定） |

#### キー割り当て更新

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| UPDATE | current.KeyData | Keys.None | 既存割り当ての解除 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| なし | 本通知は正常系の情報通知であり、エラーケースは存在しない | - |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（ユーザー操作に応じて即時表示）

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

本通知は個人情報や機密情報を含まない。メニュー項目名とキーの文字列のみを表示するため、セキュリティ上の懸念はない。

## 備考

- 本通知はMsgInfo関数を使用して表示される
- KeysHelp.GetKeyStringによりキーの文字列表現（例：「Ctrl+S」）が生成される
- メニュー項目名の末尾のピリオドは表示前にTrimEnd("."c)で除去される

---

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

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

### 推奨読解順序

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

まず、カスタムメニュー項目のデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CustomMenuItem | `Source/UI/Menu.vb` | メニュー項目のKeyData, Textプロパティの定義 |

**読解のコツ**: CustomMenuItemクラスはKeyDataプロパティでKeys列挙型を保持し、ショートカットキーの情報を管理している。

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

処理の起点となるイベントハンドラを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CustomMenuEditor.vb | `Source/UI/CustomMenuEditor.vb` | tbHotkey_KeyDownイベントハンドラ |

**主要処理フロー**:
1. **行896-900**: 修飾キーのみの入力をフィルタリング
2. **行902-909**: 同一キー再入力時のキー解除処理
3. **行911-919**: 他メニュー項目との重複チェックとキー解除
4. **行917**: MsgInfo呼び出しによる通知表示

#### Step 3: 通知表示メカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | General.vb | `Source/General/General.vb` | MsgInfo関数の実装 |
| 3-2 | TaskDialog.vb | `Source/UI/TaskDialog.vb` | TaskDialogによるダイアログ表示 |

**主要処理フロー**:
- MsgInfo関数はTaskDialogを使用して情報ダイアログを表示

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

```
CustomMenuEditor.tbHotkey_KeyDown (行896)
    │
    ├─ KeysHelp.GetKeyString(item.KeyData)
    │      └─ キー文字列の生成
    │
    ├─ tv.GetNodes (行911)
    │      └─ 全TreeNodeの取得
    │
    ├─ CustomMenuItem.KeyData比較 (行915)
    │      └─ 重複キーの検出
    │
    └─ MsgInfo (行917)
           └─ TaskDialog表示
```

### データフロー図

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

KeyDown Event ───▶ tbHotkey_KeyDown ───▶ MsgInfo表示
                          │
                          ├─ キー重複チェック
                          │
                          └─ 既存割り当て解除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CustomMenuEditor.vb | `Source/UI/CustomMenuEditor.vb` | ソース | キー割り当てUIとイベント処理 |
| Menu.vb | `Source/UI/Menu.vb` | ソース | CustomMenuItemクラス定義 |
| General.vb | `Source/General/General.vb` | ソース | MsgInfo関数定義 |
| TaskDialog.vb | `Source/UI/TaskDialog.vb` | ソース | ダイアログ表示機能 |
| KeysHelp | `Source/General/` | ソース | キー文字列変換ユーティリティ |
