# 機能設計書 49-キーボードレイアウト

## 概要

本ドキュメントは、VS Codeのキーボードレイアウト機能に関する機能設計書である。プラットフォーム固有のキーボードレイアウト検出とキーマッピング解決を担当するサービスを定義する。

### 本機能の処理概要

キーボードレイアウト機能は、ユーザーが使用しているキーボードレイアウトを検出し、キーバインディングを正しく解決するためのプラットフォームサービスである。Windows、Linux、Macの各プラットフォーム固有のキーボードレイアウト情報を抽象化する。

**業務上の目的・背景**：ユーザーのキーボードレイアウト（US、JIS、ドイツ語等）に応じて、キーバインディングを正確に処理する。異なるキーボード配列でも一貫したショートカット体験を提供する。

**機能の利用シーン**：
- キーバインディングの解決（例：Ctrl+Shift+P）
- キーボードショートカットエディタでの表示
- プラットフォーム間でのキーバインディング移植
- 入力メソッド使用時の処理

**主要な処理内容**：
1. 現在のキーボードレイアウトの取得
2. キーボードマッピングの解決
3. キーボードレイアウト変更の監視
4. キーボードイベントの検証

**関連システム・外部連携**：
- キーバインディングサービス（キーバインド解決）
- キーボードショートカットエディタ（レイアウト表示）
- Electronメインプロセス（ネイティブAPI）

**権限による制御**：プラットフォーム固有の情報はネイティブ層で取得される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | キーボードショートカットエディタ | API連携 | キーバインド表示とレイアウト検出 |

## 機能種別

プラットフォームサービス / キーボード処理

## 入力仕様

### 入力パラメータ

#### IKeyboardEvent

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|-----|------|
| keyCode | number | Yes | キーコード |
| code | string | Yes | 物理キーコード |
| ctrlKey | boolean | Yes | Ctrlキー押下状態 |
| shiftKey | boolean | Yes | Shiftキー押下状態 |
| altKey | boolean | Yes | Altキー押下状態 |
| metaKey | boolean | Yes | Metaキー押下状態 |

### プラットフォーム別キーマッピング

#### Windows (IWindowsKeyMapping)

| フィールド | 型 | 説明 |
|-----------|-----|------|
| vkey | string | 仮想キーコード |
| value | string | 通常の文字 |
| withShift | string | Shift押下時の文字 |
| withAltGr | string | AltGr押下時の文字 |
| withShiftAltGr | string | Shift+AltGr押下時の文字 |

#### Linux (ILinuxKeyMapping)

| フィールド | 型 | 説明 |
|-----------|-----|------|
| value | string | 通常の文字 |
| withShift | string | Shift押下時の文字 |
| withAltGr | string | AltGr押下時の文字 |
| withShiftAltGr | string | Shift+AltGr押下時の文字 |

#### Mac (IMacKeyMapping)

| フィールド | 型 | 説明 |
|-----------|-----|------|
| value | string | 通常の文字 |
| valueIsDeadKey | boolean | デッドキーかどうか |
| withShift | string | Shift押下時の文字 |
| withShiftIsDeadKey | boolean | Shift時デッドキーか |
| withAltGr | string | AltGr押下時の文字 |
| withAltGrIsDeadKey | boolean | AltGr時デッドキーか |
| withShiftAltGr | string | Shift+AltGr押下時の文字 |
| withShiftAltGrIsDeadKey | boolean | Shift+AltGr時デッドキーか |

### キーボードレイアウト情報

#### Windows (IWindowsKeyboardLayoutInfo)

| フィールド | 型 | 説明 |
|-----------|-----|------|
| name | string | レイアウト名 |
| id | string | レイアウトID |
| text | string | 表示テキスト |

#### Linux (ILinuxKeyboardLayoutInfo)

| フィールド | 型 | 説明 |
|-----------|-----|------|
| model | string | キーボードモデル |
| group | number | グループ番号 |
| layout | string | レイアウト名 |
| variant | string | バリアント |
| options | string | オプション |
| rules | string | ルール |

#### Mac (IMacKeyboardLayoutInfo)

| フィールド | 型 | 説明 |
|-----------|-----|------|
| id | string | レイアウトID（com.apple.keylayout.*） |
| lang | string | 言語コード |
| localizedName | string? | ローカライズ名 |

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| IKeyboardMapping | type | キーボードマッピング（プラットフォーム固有） |
| IKeyboardLayoutInfo | type | レイアウト情報（プラットフォーム固有） |
| ResolvedKeybinding | class | 解決済みキーバインド |

### 出力先

- 呼び出し元（レイアウト情報、マッピング）
- イベントリスナー（onDidChangeKeyboardLayout）

## 処理フロー

### 処理シーケンス

```
1. キーボードレイアウトの初期化
   └─ ネイティブAPIからレイアウト情報取得
   └─ キーボードマッピングを構築
   └─ IKeyboardMapperを作成

2. キーボードイベントの解決
   └─ resolveKeyboardEvent(event) で解決
   └─ IKeyboardMapperを使用
   └─ ResolvedKeybinding を返却

3. キーバインドの解決
   └─ resolveKeybinding(keybinding) で解決
   └─ キャッシュを活用
   └─ ResolvedKeybinding[] を返却

4. レイアウト変更の検出
   └─ OSからの変更通知を受信
   └─ onDidChangeKeyboardLayout イベント発火
   └─ IKeyboardMapper を再構築
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-49-01 | プラットフォーム判別 | OS固有のマッピングインターフェースを使用 | 初期化時 |
| BR-49-02 | デッドキー処理 | Macではデッドキーフラグを考慮 | Mac環境 |
| BR-49-03 | AltGr処理 | Windows/Linuxでは右AltをAltGrとして処理 | 該当キー入力時 |
| BR-49-04 | レイアウト比較 | プラットフォーム固有のフィールドで等価判定 | レイアウト変更検出時 |
| BR-49-05 | キャッシュ利用 | キーバインド解決結果をキャッシュ | 解決時 |

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

キーボードレイアウト情報はメモリ内で管理され、データベースには保存されない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UNKNOWN_LAYOUT | 業務エラー | 未知のレイアウト | US Standardにフォールバック |
| NATIVE_ERROR | システムエラー | ネイティブAPI失敗 | デフォルトマッピング使用 |

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

トランザクション制御は行わない。キーボードレイアウトの変更は即座に反映される。

## パフォーマンス要件

- キーバインド解決結果のキャッシュ（CachedKeyboardMapper）
- レイアウト変更時のみマッパー再構築
- ScanCodeベースの効率的なマッピング比較

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

- キーボード入力はローカルで処理
- キーロギングは行わない

## 備考

- カスタムキーボードレイアウトは`keyboard.json`で定義可能
- `isUSStandard`フラグで標準USレイアウト判定

---

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

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

### 推奨読解順序

#### Step 1: サービスインターフェースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | keyboardLayout.ts | `src/vs/platform/keyboardLayout/common/keyboardLayout.ts` | IKeyboardLayoutService（74-84行目） |

**主要処理フロー**:
1. **12行目**: `IKeyboardLayoutService = createDecorator<IKeyboardLayoutService>('keyboardLayoutService')` でサービスID定義
2. **74-84行目**: `IKeyboardLayoutService` インターフェース
   - `onDidChangeKeyboardLayout`: レイアウト変更イベント
   - `getRawKeyboardMapping()`: 生のマッピング取得
   - `getCurrentKeyboardLayout()`: 現在のレイアウト取得
   - `getAllKeyboardLayouts()`: 全レイアウト取得
   - `getKeyboardMapper()`: マッパー取得
   - `validateCurrentKeyboardMapping()`: マッピング検証

#### Step 2: プラットフォーム固有の型を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | keyboardLayout.ts | `src/vs/platform/keyboardLayout/common/keyboardLayout.ts` | 14-72行目のプラットフォーム固有型 |

**主要な型**:
- **14-23行目**: `IWindowsKeyMapping`, `IWindowsKeyboardMapping` - Windows用
- **24-32行目**: `ILinuxKeyMapping`, `ILinuxKeyboardMapping` - Linux用
- **33-48行目**: `IMacKeyMapping`, `IMacKeyboardMapping` - Mac用
- **51-72行目**: `IWindowsKeyboardLayoutInfo`, `ILinuxKeyboardLayoutInfo`, `IMacKeyboardLayoutInfo` - レイアウト情報

#### Step 3: マッパーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | keyboardMapper.ts | `src/vs/platform/keyboardLayout/common/keyboardMapper.ts` | IKeyboardMapper、CachedKeyboardMapper |

**主要処理フロー**:
- **9-13行目**: `IKeyboardMapper` インターフェース
  - `dumpDebugInfo()`: デバッグ情報出力
  - `resolveKeyboardEvent()`: キーボードイベント解決
  - `resolveKeybinding()`: キーバインド解決
- **15-43行目**: `CachedKeyboardMapper` - キャッシュ付きマッパー

#### Step 4: ユーティリティ関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | keyboardLayout.ts | `src/vs/platform/keyboardLayout/common/keyboardLayout.ts` | 86-237行目のユーティリティ関数 |

**主要関数**:
- **86-108行目**: `areKeyboardLayoutsEqual()` - レイアウト等価判定
- **110-158行目**: `parseKeyboardLayoutDescription()` - 説明文パース
- **160-170行目**: `getKeyboardLayoutId()` - レイアウトID取得
- **188-204行目**: `windowsKeyboardMappingEquals()` - Windowsマッピング比較
- **221-237行目**: `macLinuxKeyboardMappingEquals()` - Mac/Linuxマッピング比較

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

```
IKeyboardLayoutService
    │
    ├─ getCurrentKeyboardLayout() ──▶ IKeyboardLayoutInfo
    │
    ├─ getRawKeyboardMapping() ──▶ IKeyboardMapping
    │
    ├─ getKeyboardMapper() ──▶ IKeyboardMapper
    │      ├─ resolveKeyboardEvent() ──▶ ResolvedKeybinding
    │      └─ resolveKeybinding() ──▶ ResolvedKeybinding[]
    │
    ├─ getAllKeyboardLayouts() ──▶ IKeyboardLayoutInfo[]
    │
    ├─ validateCurrentKeyboardMapping() ──▶ void
    │
    └─ onDidChangeKeyboardLayout ──▶ 変更通知

CachedKeyboardMapper (decorator)
    └─ _actual: IKeyboardMapper
    └─ _cache: Map<hashCode, ResolvedKeybinding[]>
```

### データフロー図

```
OSネイティブAPI
    │
    ▼
INativeKeyboardLayoutService
    │ getKeyboardLayoutData()
    ▼
┌─────────────────────────────────┐
│ IKeyboardLayoutData             │
│  ├─ keyboardLayoutInfo          │
│  └─ keyboardMapping             │
└─────────────────────────────────┘
    │
    ▼
IKeyboardLayoutService
    │
    ├──▶ IKeyboardLayoutInfo (現在のレイアウト情報)
    │
    └──▶ IKeyboardMapper (キーバインド解決)
              │
              ▼
         ResolvedKeybinding
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| keyboardLayout.ts | `src/vs/platform/keyboardLayout/common/keyboardLayout.ts` | ソース | サービスインターフェース・型定義 |
| keyboardMapper.ts | `src/vs/platform/keyboardLayout/common/keyboardMapper.ts` | ソース | マッパーインターフェース・キャッシュ |
| keyboardLayoutService.ts | `src/vs/platform/keyboardLayout/common/keyboardLayoutService.ts` | ソース | ネイティブサービス型定義 |
| keyboardConfig.ts | `src/vs/platform/keyboardLayout/common/keyboardConfig.ts` | ソース | キーボード設定 |
| keyboardLayoutMainService.ts | `src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts` | ソース | Electronメイン実装 |
