ルール策定前に書かれた設計ドキュメント7点を、以降の基準点として そのままの状態で記録する。CLAUDE.md のルール1〜4は未適用。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MdLT5x5ka5y6CaWLeE3EKb
454 lines
14 KiB
Markdown
454 lines
14 KiB
Markdown
# PHYレイヤーとKLE(Keyboard Layout Editor)の互換性分析
|
||
|
||
## 概要
|
||
|
||
検討中のPHYレイヤー構造とKeyboard Layout Editor(KLE)の互換性について詳細に分析した結果をまとめます。KLEをベースとしたフロントエンドの実現可能性を評価します。
|
||
|
||
## KLEデータモデルの特徴
|
||
|
||
### KLEで対応可能な主要プロパティ
|
||
|
||
KLEの`Key`オブジェクトは以下の構造を持ちます:
|
||
|
||
```typescript
|
||
export class Key {
|
||
// 位置・サイズ関連
|
||
x: number; // 絶対位置 (U単位)
|
||
y: number; // 絶対位置 (U単位)
|
||
width: number; // サイズ (U単位)
|
||
height: number; // サイズ (U単位)
|
||
|
||
// 回転関連
|
||
rotation_x: number; // 回転中心X座標
|
||
rotation_y: number; // 回転中心Y座標
|
||
rotation_angle: number; // 回転角度
|
||
|
||
// 複雑な形状対応
|
||
x2: number; // 第2矩形の相対位置
|
||
y2: number; // 第2矩形の相対位置
|
||
width2: number; // 第2矩形のサイズ
|
||
height2: number; // 第2矩形のサイズ
|
||
|
||
// 表示・装飾関連
|
||
color: string; // キーキャップ色
|
||
labels: string[]; // 最大12個のラベル
|
||
textColor: Array<string | undefined>;
|
||
textSize: Array<number | undefined>;
|
||
profile: string; // キープロファイル
|
||
|
||
// フラグ類
|
||
decal: boolean; // デカールモード
|
||
ghost: boolean; // ゴーストモード
|
||
stepped: boolean; // ステップキー
|
||
nub: boolean; // ホーミング突起
|
||
|
||
// スイッチ情報
|
||
sm: string; // スイッチマウント
|
||
sb: string; // スイッチブランド
|
||
st: string; // スイッチタイプ
|
||
}
|
||
```
|
||
|
||
## 互換性マトリックス
|
||
|
||
### ✅ 完全対応可能
|
||
|
||
| PHYレイヤー機能 | KLEプロパティ | 備考 |
|
||
|---|---|---|
|
||
| キー座標(x,y) | `x`, `y` | 1:1対応、U単位 |
|
||
| キーサイズ(w,h) | `width`, `height` | 1:1対応、U単位 |
|
||
| 回転角度 | `rotation_angle` | 1:1対応 |
|
||
| 回転中心 | `rotation_x`, `rotation_y` | 1:1対応 |
|
||
| 0.25U単位スナップ | - | KLEも小数点座標対応 |
|
||
| 複雑形状キー | `x2`, `y2`, `width2`, `height2` | ISO Enter等に対応 |
|
||
| プロファイル設定 | `profile` | SA、DCS、OEM等対応 |
|
||
|
||
### ⚠️ 部分対応・要改造
|
||
|
||
| PHYレイヤー機能 | KLE対応状況 | 改造内容 |
|
||
|---|---|---|
|
||
| クラスター管理 | 非対応 | カスタムメタデータとしてlabelsに格納 |
|
||
| 複数プロファイル | 一部対応 | メタデータで管理、UI拡張必要 |
|
||
| ユニットサイズ設定 | 非対応 | グローバル設定として追加実装 |
|
||
| ビジュアルオフセット | 非対応 | レンダリング層で独自実装 |
|
||
|
||
### ❌ 対応困難・KLE制約
|
||
|
||
| PHYレイヤー機能 | KLE制約 | 回避策 |
|
||
|---|---|---|
|
||
| 15度以外の回転角度 | UI制約(内部は対応可能) | UI改造またはAPI直接操作 |
|
||
| 階層的クラスター | データモデル非対応 | ゴーストキーによるメタデータ保存 |
|
||
| クラスター別回転中心 | 直接非対応 | 各キーの回転中心で代替 |
|
||
|
||
## 具体的な実装戦略
|
||
|
||
### 1. KLEベースデータ変換
|
||
|
||
PHYレイヤーからKLE形式への変換:
|
||
|
||
```typescript
|
||
// PHYレイヤー → KLE変換例
|
||
function convertToKLE(phyData: PHYLayer): KLEData {
|
||
return phyData.elements.map(element => {
|
||
if (element.type === 'key') {
|
||
return {
|
||
x: element.position.x,
|
||
y: element.position.y,
|
||
width: element.size.width,
|
||
height: element.size.height,
|
||
rotation_x: element.position.rotationOrigin?.x || 0,
|
||
rotation_y: element.position.rotationOrigin?.y || 0,
|
||
rotation_angle: element.position.rotation || 0,
|
||
// クラスター情報をlabelsの特定位置に格納
|
||
labels: [element.clusterId || '', '', '', '', '', '', '', '', '', '', '', ''],
|
||
// プロファイル情報
|
||
profile: element.profile || 'OEM'
|
||
};
|
||
}
|
||
// クラスターの場合は展開処理
|
||
});
|
||
}
|
||
```
|
||
|
||
### 2. KLE UI改造点
|
||
|
||
#### 必要な改造項目
|
||
|
||
1. **クラスター管理UI**
|
||
- クラスター作成・編集パネル
|
||
- クラスター単位の選択・移動
|
||
- クラスター階層表示
|
||
|
||
2. **プロファイル管理**
|
||
- 複数プロファイル切り替えUI
|
||
- プロファイル別ユニットサイズ設定
|
||
|
||
3. **メタデータ拡張**
|
||
- PHYレイヤー固有情報の保存
|
||
- 互換性情報の管理
|
||
|
||
#### UI改造の難易度
|
||
|
||
- **低難易度**: 既存プロパティパネルの拡張
|
||
- **中難易度**: クラスター管理機能の追加
|
||
- **高難易度**: レンダリングエンジンの改造
|
||
|
||
### 3. 制限事項と回避策
|
||
|
||
#### 現在のKLE制約
|
||
|
||
1. **データモデル制約**
|
||
- フラットな配列構造のみ対応
|
||
- 階層的クラスター管理は困難
|
||
|
||
2. **レンダリング制約**
|
||
- HTMLベースのレンダリング
|
||
- 複雑な視覚効果には限界
|
||
|
||
#### 回避策
|
||
|
||
1. **段階的対応**
|
||
- Phase 1: 基本的な位置・サイズ・回転のみ対応
|
||
- Phase 2: クラスター管理機能追加
|
||
- Phase 3: 高度なビジュアル機能
|
||
|
||
2. **ハイブリッドアプローチ**
|
||
- KLEをベースエディタとして使用
|
||
- 独自機能は別パネルで管理
|
||
- 最終出力時にPHYレイヤー形式で統合
|
||
|
||
## 推奨実装アプローチ
|
||
|
||
### フェーズ1: KLE最小改造アプローチ(推奨)
|
||
|
||
1. **KLEの既存機能をそのまま活用**
|
||
- 基本的な配置・サイズ・回転
|
||
- プロファイル設定
|
||
- 色・ラベル設定
|
||
|
||
2. **最小限の拡張**
|
||
- カスタムメタデータ保存機能
|
||
- PHYレイヤー形式エクスポート
|
||
|
||
3. **段階的機能追加**
|
||
- クラスター管理(Phase 2)
|
||
- 高度なビジュアル機能(Phase 3)
|
||
|
||
### 実装優先順位
|
||
|
||
1. **高優先度** - 即座に対応可能
|
||
- ✅ 基本位置・サイズ・回転
|
||
- ✅ プロファイル設定
|
||
- ✅ KLE→PHYレイヤー変換
|
||
|
||
2. **中優先度** - 改造が必要だが実現可能
|
||
- ⚠️ 簡易クラスター管理
|
||
- ⚠️ 複数プロファイル対応
|
||
- ⚠️ カスタムユニットサイズ
|
||
|
||
3. **低優先度** - 大規模改造が必要
|
||
- ❌ 階層的クラスター
|
||
- ❌ 高度なビジュアルオフセット
|
||
- ❌ リアルタイム3Dプレビュー
|
||
|
||
## 結論
|
||
|
||
**KLEをベースとしたPHYレイヤーエディタの実現は十分可能**です。
|
||
|
||
### 対応可能な機能(約80%)
|
||
|
||
- 基本的なキー配置・サイズ・回転
|
||
- 複雑形状キー(ISO Enter等)
|
||
- プロファイル管理
|
||
- 基本的なクラスター管理
|
||
|
||
### 改造が必要な機能(約15%)
|
||
|
||
- 高度なクラスター管理
|
||
- 複数プロファイル切り替え
|
||
- カスタムユニットサイズ
|
||
|
||
### 対応困難な機能(約5%)
|
||
|
||
- 完全階層的クラスター構造
|
||
- 高度なビジュアルエフェクト
|
||
|
||
PHYレイヤーの主要機能はKLEで十分実現可能であり、段階的な改造により完全対応も期待できます。
|
||
|
||
## 階層型クラスターの実装戦略
|
||
|
||
### 問題提起
|
||
|
||
ユーザーからの要求:
|
||
|
||
- **階層型クラスター管理は絶対に実装したい**
|
||
- 出力時はフラット化してもOK(階層情報を何らかの形で記録できれば)
|
||
- ラベルに突っ込むと見づらくなる懸念
|
||
- **ゴーストキーによる情報保存**のアイデア
|
||
|
||
### ゴーストキーアプローチの詳細設計
|
||
|
||
#### 基本概念
|
||
|
||
クラスター情報を`ghost: true`のキーとして保存し、実際のキーレンダリングには影響を与えずにメタデータとして扱う。
|
||
|
||
```typescript
|
||
// クラスター情報保存用ゴーストキー
|
||
type ClusterGhostKey = {
|
||
ghost: true,
|
||
decal: false,
|
||
x: number, // クラスター範囲の左上角
|
||
y: number, // クラスター範囲の左上角
|
||
width: number, // クラスター範囲の幅
|
||
height: number, // クラスター範囲の高さ
|
||
rotation_x: number, // クラスター回転中心
|
||
rotation_y: number, // クラスター回転中心
|
||
rotation_angle: number, // クラスター回転角度
|
||
color: "#transparent", // 透明
|
||
labels: [
|
||
"CLUSTER_META", // [0] 識別子
|
||
clusterId, // [1] クラスターID
|
||
parentClusterId, // [2] 親クラスターID(階層用)
|
||
clusterName, // [3] クラスター名
|
||
JSON.stringify(metadata), // [4] その他メタデータ
|
||
"", "", "", "", "", "", "" // [5-11] 予約
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 階層構造の表現
|
||
|
||
```typescript
|
||
// 例:分割キーボードの左右ブロック + 各ブロック内のキークラスター
|
||
const clusterHierarchy = {
|
||
"root": {
|
||
children: ["left_block", "right_block"]
|
||
},
|
||
"left_block": {
|
||
parent: "root",
|
||
children: ["left_alpha", "left_modifiers"]
|
||
},
|
||
"right_block": {
|
||
parent: "root",
|
||
children: ["right_alpha", "right_modifiers"]
|
||
},
|
||
"left_alpha": {
|
||
parent: "left_block",
|
||
keyIds: ["Q", "W", "E", "R", "T", "A", "S", "D", "F", "G", ...]
|
||
}
|
||
// ...
|
||
}
|
||
```
|
||
|
||
#### KLE UI拡張による階層管理
|
||
|
||
1. **クラスター管理パネル**
|
||
|
||
```html
|
||
<!-- 新しいサイドパネル -->
|
||
<div id="cluster-manager">
|
||
<tree-view>
|
||
<cluster-node id="root">
|
||
<cluster-node id="left_block">
|
||
<cluster-node id="left_alpha" />
|
||
<cluster-node id="left_modifiers" />
|
||
</cluster-node>
|
||
<cluster-node id="right_block">
|
||
<cluster-node id="right_alpha" />
|
||
<cluster-node id="right_modifiers" />
|
||
</cluster-node>
|
||
</cluster-node>
|
||
</tree-view>
|
||
</div>
|
||
```
|
||
|
||
2. **クラスター操作機能**
|
||
- ドラッグ&ドロップによるキーのクラスター移動
|
||
- 階層ツリーでのクラスター選択
|
||
- クラスター単位での一括変換(移動・回転・リサイズ)
|
||
- クラスター単位でのコピー&ペースト
|
||
|
||
### データフロー設計
|
||
|
||
#### 1. 編集時(UI → 内部データ)
|
||
|
||
```javascript
|
||
// クラスター作成時
|
||
function createCluster(name, parentId, selectedKeys) {
|
||
const clusterId = generateUniqueId();
|
||
|
||
// ゴーストキーを作成
|
||
const ghostKey = createClusterGhostKey({
|
||
id: clusterId,
|
||
name: name,
|
||
parentId: parentId,
|
||
boundingBox: calculateBoundingBox(selectedKeys)
|
||
});
|
||
|
||
// 選択されたキーにクラスターIDを付与
|
||
selectedKeys.forEach(key => {
|
||
key.clusterId = clusterId; // カスタムプロパティとして追加
|
||
});
|
||
|
||
// KLEのキー配列に追加
|
||
scope.keys().push(ghostKey);
|
||
}
|
||
```
|
||
|
||
#### 2. 保存時(内部データ → KLE JSON)
|
||
|
||
```javascript
|
||
function serializeWithClusters(keyboard) {
|
||
const kleData = serial.serialize(keyboard);
|
||
|
||
// 通常のキーとゴーストキーが混在した状態で保存
|
||
// ゴーストキーがクラスター情報を保持
|
||
return kleData;
|
||
}
|
||
```
|
||
|
||
#### 3. 読み込み時(KLE JSON → 内部データ)
|
||
|
||
```javascript
|
||
function deserializeWithClusters(kleData) {
|
||
const keyboard = serial.deserialize(kleData);
|
||
|
||
// ゴーストキーからクラスター情報を復元
|
||
const clusterMap = new Map();
|
||
const normalKeys = [];
|
||
|
||
keyboard.keys.forEach(key => {
|
||
if (key.ghost && key.labels[0] === 'CLUSTER_META') {
|
||
const clusterId = key.labels[1];
|
||
const parentId = key.labels[2];
|
||
const metadata = JSON.parse(key.labels[4]);
|
||
|
||
clusterMap.set(clusterId, {
|
||
ghostKey: key,
|
||
parentId: parentId,
|
||
metadata: metadata,
|
||
children: new Set()
|
||
});
|
||
} else {
|
||
normalKeys.push(key);
|
||
}
|
||
});
|
||
|
||
// 階層構造を再構築
|
||
buildClusterHierarchy(clusterMap);
|
||
|
||
return { keyboard: { ...keyboard, keys: normalKeys }, clusters: clusterMap };
|
||
}
|
||
```
|
||
|
||
### 15度回転制約について
|
||
|
||
#### 現在の制約の詳細
|
||
|
||
KLEのソースコード分析結果:
|
||
|
||
```javascript
|
||
$scope.rotateStep = 15; // UI上のデフォルト回転ステップ
|
||
|
||
// 実際の制約チェック(kb.js内)
|
||
rotation_angle: function() {
|
||
return Math.max(-180, Math.min(180, value)); // ±180度の範囲制約のみ
|
||
}
|
||
```
|
||
|
||
**つまり:**
|
||
|
||
- **UIでは15度ステップで回転操作**(ユーザビリティのため)
|
||
- **内部データには制約なし**(任意の角度を保存可能)
|
||
- **JSON出力も制約なし**(小数点を含む任意の角度値)
|
||
|
||
#### PHYレイヤーでの対応
|
||
|
||
```javascript
|
||
// PHY → KLE変換時に任意角度をそのまま渡す
|
||
function convertRotation(phyRotation) {
|
||
return phyRotation; // 制約なし、そのまま変換
|
||
}
|
||
|
||
// KLE UI拡張で任意角度入力を許可
|
||
function enableCustomRotation() {
|
||
// 既存の15度ステップに加えて、直接入力機能を追加
|
||
scope.customRotateStep = 1; // 1度ステップ
|
||
scope.allowCustomAngle = true; // 任意角度入力許可
|
||
}
|
||
```
|
||
|
||
## 実装優先度の再評価
|
||
|
||
### 修正版優先度
|
||
|
||
1. **最高優先度** - 即座に対応可能
|
||
- ✅ 基本位置・サイズ・回転(任意角度対応)
|
||
- ✅ プロファイル設定
|
||
- ✅ KLE→PHYレイヤー変換
|
||
|
||
2. **高優先度** - ゴーストキーアプローチで対応
|
||
- 🔶 階層型クラスター管理(ゴーストキー方式)
|
||
- 🔶 クラスターメタデータ保存
|
||
- 🔶 クラスター単位操作UI
|
||
|
||
3. **中優先度** - UI改造が必要
|
||
- ⚠️ 複数プロファイル対応
|
||
- ⚠️ カスタムユニットサイズ
|
||
- ⚠️ 15度以外の回転角度UI対応
|
||
|
||
4. **低優先度** - 大規模改造が必要
|
||
- ❌ 高度なビジュアルオフセット
|
||
- ❌ リアルタイム3Dプレビュー
|
||
|
||
### 実装結論
|
||
|
||
**ゴーストキーアプローチにより、階層型クラスター管理は実現可能**です。この方法なら:
|
||
|
||
- KLEの既存データモデルを活用
|
||
- 見た目に影響しない形でメタデータ保存
|
||
- 階層構造の完全な再現が可能
|
||
- 段階的な実装が可能
|
||
|
||
階層型クラスターが「絶対実装したい」要求に対して、技術的に実現可能な解決策を提供できます。
|