# 機能設計書 21-キーボードショートカット

## 概要

本ドキュメントは、選曲画面（select.hsp）におけるCtrlキー併用のキーボードショートカット機能の設計を記述する。Ctrl+C / Ctrl+E / Ctrl+O / Ctrl+I の4種類のショートカットにより、譜面パスのコピー、エディタ起動、フォルダ表示、IRページ表示を行う。

### 本機能の処理概要

**業務上の目的・背景**：楽曲制作者や上級ユーザーが選曲画面から直接、譜面ファイルの操作やインターネットランキング参照を行えるようにするための機能である。マウス操作やメニュー階層を辿ることなく、キーボード操作のみで素早く目的の処理にアクセスできるため、制作ワークフローの効率化に貢献する。

**機能の利用シーン**：選曲画面で楽曲を選択中に、その譜面ファイルのパスを別アプリケーションに貼り付けたい場合（Ctrl+C）、譜面エディタで編集を開始したい場合（Ctrl+E）、譜面ファイルが格納されたフォルダをエクスプローラで確認したい場合（Ctrl+O）、インターネットランキングで他プレイヤーのスコアを確認したい場合（Ctrl+I）に利用される。

**主要な処理内容**：
1. Ctrlキーの押下状態を検出（getkey命令でキーコード17を監視）
2. Ctrl押下中に各アルファベットキー（C/E/O/I）の押下を検出
3. 押下されたキーに応じて、クリップボードコピー/エディタ起動/フォルダ表示/IRページ表示を実行
4. 各キーの前フレーム状態を保持し、エッジ検出（押下の瞬間のみ反応）を行う

**関連システム・外部連携**：Ctrl+Eではeditor.exe（譜面エディタ）をexec命令で起動する。Ctrl+Iではir.kshootmania.comのIRページをブラウザで開く。Ctrl+Cではclipset命令でWindowsクリップボードにアクセスする。

**権限による制御**：楽曲種別（通常楽曲:minfo.selnow.0.0=0、コースモード:minfo.selnow.0.0=4）によって利用可能なショートカットが異なる。Ctrl+Eは通常楽曲のみ、Ctrl+C/Ctrl+Oは通常楽曲とコースモード、Ctrl+Iは通常楽曲のみで利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | 曲選択画面 | 主画面 | Ctrl+C/E/O/Iの4種類のショートカット操作 |

## 機能種別

ユーザーインタラクション / キー入力ハンドリング / 外部アプリケーション連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ctrlKey | int | Yes | Ctrlキー押下状態（キーコード17） | 0または1 |
| ctrlCKey | int | No | Cキー押下状態 | 0または1 |
| ctrlEKey | int | No | Eキー押下状態 | 0または1 |
| ctrlOKey | int | No | Oキー押下状態 | 0または1 |
| ctrlIKey | int | No | Iキー押下状態 | 0または1 |
| minfo.selnow.0.0 | int | Yes | 選択中アイテムの種別 | 0=通常楽曲, 4=コースモード |
| minfostr.selnow.levm.0 | str | Yes | 選択中楽曲のディレクトリパス | 空文字でないこと |
| minfostr.selnow.levm.5 | str | Yes | 選択中楽曲のファイル名 | 空文字でないこと |

### 入力データソース

画面入力（キーボード）、ゲーム内部状態（選択中楽曲情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| クリップボードテキスト | str | Ctrl+C時に設定される譜面パス文字列 |
| exec命令実行 | - | Ctrl+E時にeditor.exeを起動、Ctrl+O時にexplorerを起動、Ctrl+I時にブラウザでIRページを表示 |

### 出力先

- Ctrl+C: Windowsクリップボード（clipset命令経由）
- Ctrl+E: editor.exeプロセス起動（exec命令経由）
- Ctrl+O: Windowsエクスプローラ起動（exec explorer命令経由）
- Ctrl+I: デフォルトブラウザでIRページ表示（exec命令経由、URL指定）

## 処理フロー

### 処理シーケンス

```
1. Ctrlキー押下状態を取得
   └─ getkey ctrlKey, 17
2. Ctrlキーが押下されている場合
   ├─ filePathを構築（dir_default + "\\songs\\" + ディレクトリ + "\\" + ファイル名）
   ├─ Ctrl+C: 譜面パスをクリップボードにコピー
   │     └─ clipset命令でバックスラッシュをスラッシュに変換したパスを設定
   ├─ Ctrl+E: エディタで譜面を開く
   │     └─ editor.exeが存在する場合のみexec命令で起動
   ├─ Ctrl+O: エクスプローラで譜面フォルダを表示
   │     └─ exec "explorer /select,\"filepath\""
   └─ Ctrl+I: IRページをブラウザで表示
         └─ 譜面ファイルを読み込み、getChartIRHashでハッシュ計算後、IRページURLを開く
3. Ctrlキーが押下されていない場合
   └─ 全てのprev変数をリセット（ctrlCKeyPrev=0等）
```

### フローチャート

```mermaid
flowchart TD
    A[Ctrlキー状態取得] --> B{Ctrl押下中?}
    B -->|Yes| C[filePathを構築]
    C --> D{Ctrl+C?}
    D -->|Yes| E{通常楽曲 or コース?}
    E -->|Yes| F[clipsetでパスをコピー]
    E -->|No| G[何もしない]
    D -->|No| H{Ctrl+E?}
    H -->|Yes| I{通常楽曲?}
    I -->|Yes| J{editor.exe存在?}
    J -->|Yes| K[exec editor.exe]
    J -->|No| G
    I -->|No| G
    H -->|No| L{Ctrl+O?}
    L -->|Yes| M{通常楽曲 or コース?}
    M -->|Yes| N[exec explorer]
    M -->|No| G
    L -->|No| O{Ctrl+I?}
    O -->|Yes| P{通常楽曲?}
    P -->|Yes| Q[譜面読み込み+IRハッシュ計算]
    Q --> R[exec IRページURL]
    P -->|No| G
    O -->|No| G
    B -->|No| S[prev変数をリセット]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-21-01 | エッジ検出 | 各キーは押下の瞬間（前フレームで未押下、今フレームで押下）のみ反応する | 全ショートカット |
| BR-21-02 | 楽曲種別制限 | Ctrl+E/Ctrl+Iは通常楽曲(minfo.selnow.0.0=0)のみ有効 | Ctrl+E, Ctrl+I |
| BR-21-03 | パス変換 | Ctrl+Cではバックスラッシュをスラッシュに変換する | Ctrl+C |
| BR-21-04 | エディタ存在確認 | Ctrl+Eはeditor.exeが存在する場合のみ実行 | Ctrl+E |
| BR-21-05 | BOM処理 | Ctrl+I時に譜面ファイルを読み込む際、UTF-8 BOMが存在すれば削除する | Ctrl+I |

### 計算ロジック

Ctrl+I時のIR URLは以下の形式で構築される:
```
https://ir.kshootmania.com/md5/{getChartIRHash(buf)}
```
getChartIRHashはメタデータ行を除外した正規化譜面データのMD5ハッシュ。

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

### 操作別データベース影響一覧

本機能ではデータベース操作は発生しない。ファイルシステムへの読み取りアクセスのみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル不存在 | Ctrl+Eでeditor.exeが存在しない場合 | fileExistsで事前チェックし、不在時は何もしない |
| - | ファイル不存在 | Ctrl+Iで譜面ファイルが存在しない場合 | fileExistsで事前チェックし、不在時は何もしない |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要（ファイル読み取り・外部プロセス起動のみ）。

## パフォーマンス要件

Ctrl+I時に譜面ファイルの読み込みとMD5ハッシュ計算を行うため、大きな譜面ファイルでは一瞬の遅延が生じる可能性があるが、体感的には即時応答レベルである。

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

- Ctrl+Eではexec命令で外部プロセスを起動するため、editor.exeのパスがdir_defaultに固定されている点で安全性が確保されている。
- Ctrl+Iではexec命令でURLを開くが、URLはir.kshootmania.comドメインに固定されている。

## 備考

- Ctrlキーの前フレーム状態リセットは、Ctrlキーが離された瞬間に行われる（266-318行目）。
- 4つのショートカットは独立して動作し、同フレーム内で複数が同時に発火することはない（逐次チェック）。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.hsp | `src/scene/select.hsp` | minfo/minfostr配列による楽曲情報管理構造を理解する |

**読解のコツ**: HSP3ではminfo.selnow.0.0のように多次元配列でデータを管理する。selnowは現在選択中のインデックス、levmは難易度インデックス。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.hsp | `src/scene/select.hsp` | 選曲画面のメインループ内でCtrlキー処理が呼ばれる箇所 |

**主要処理フロー**:
1. **264-265行目**: Ctrlキーの押下状態取得（getkey ctrlKey, 17）
2. **266行目**: Ctrlキー押下中の分岐開始
3. **267行目**: filePathの構築
4. **269-276行目**: Ctrl+C処理（clipsetでパスコピー）
5. **278-287行目**: Ctrl+E処理（editor.exe起動）
6. **289-296行目**: Ctrl+O処理（explorerでフォルダ表示）
7. **298-312行目**: Ctrl+I処理（IRページ表示、BOM処理・ハッシュ計算含む）
8. **313-318行目**: Ctrl未押下時のprev変数リセット

#### Step 3: IR用ハッシュ計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ir.hsp | `src/ir.hsp` | getChartIRHash関数の実装（メタデータ除外・MD5計算） |

**主要処理フロー**:
- **51-68行目**: getChartIRHash関数 - ignoreListで指定されたメタデータ行を除外し、残りの行のMD5ハッシュを計算

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

```
select.hsp (メインループ)
    |
    +-- getkey ctrlKey, 17          (Ctrlキー検出)
    +-- getkey ctrlCKey, 'C'        (Cキー検出)
    |     +-- clipset ...           (クリップボードコピー)
    +-- getkey ctrlEKey, 'E'        (Eキー検出)
    |     +-- fileExists(...)       (editor.exe存在確認)
    |     +-- exec editor.exe       (エディタ起動)
    +-- getkey ctrlOKey, 'O'        (Oキー検出)
    |     +-- exec explorer         (フォルダ表示)
    +-- getkey ctrlIKey, 'I'        (Iキー検出)
          +-- noteload filePath     (譜面ファイル読み込み)
          +-- DeleteUTF8BOM buf     (BOM削除)
          +-- getChartIRHash(buf)   (IR用ハッシュ計算)
          +-- exec IRページURL       (ブラウザ表示)
```

### データフロー図

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

キーボード入力 -----> Ctrlキー検出 ----+
                                      |
選曲中楽曲情報 -----> filePath構築 ---+
                                      |
                      +-- Ctrl+C --> clipset --> クリップボード
                      +-- Ctrl+E --> exec -----> editor.exe起動
                      +-- Ctrl+O --> exec -----> explorer起動
                      +-- Ctrl+I --> noteload + getChartIRHash
                                     --> exec --> ブラウザ起動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.hsp | `src/scene/select.hsp` | ソース | キーボードショートカットの実装（264-318行目） |
| ir.hsp | `src/ir.hsp` | ソース | getChartIRHash関数（51-68行目）、IRページURL構築 |
| kshlib.as | `src/kshlib.as` | ソース | KSHLib_GetChartMD5Hash等のDLL関数宣言 |
| filesystem_utils.as | `src/filesystem_utils.as` | ソース | fileExists関数の実装 |
