danoniplus 48.4.0 → 48.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/js/danoni_main.js +270 -295
  2. package/package.json +1 -1
package/js/danoni_main.js CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2026/06/02
7
+ * Revised : 2026/06/05
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 48.4.0`;
12
- const g_revisedDate = `2026/06/02`;
11
+ const g_version = `Ver 48.4.2`;
12
+ const g_revisedDate = `2026/06/06`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -9070,14 +9070,15 @@ const resetGroupList = (_type, _keyCtrlPtn) => {
9070
9070
  let k = 1;
9071
9071
  g_keycons[`${_type}Groups`] = [0];
9072
9072
 
9073
- if (g_keyObj.currentPtn === -1) {
9074
- g_keycons[`${_type}Groups`] = addValtoArray(g_keycons[`${_type}Groups`], -1);
9075
- }
9076
- g_keycons[`${_type}GroupNum`] = Math.min(g_keyObj.currentPtn, 0);
9077
9073
  while (g_keyObj[`${_type}${_keyCtrlPtn}_${k}`] !== undefined) {
9078
9074
  g_keycons[`${_type}Groups`].push(k);
9079
9075
  k++;
9080
9076
  }
9077
+ if (g_keyObj.currentPtn === -1
9078
+ && (_type !== `stepRtn` || (_type === `stepRtn` && g_keycons[`${_type}Groups`].length > 1))) {
9079
+ g_keycons[`${_type}Groups`] = addValtoArray(g_keycons[`${_type}Groups`], -1);
9080
+ }
9081
+ g_keycons[`${_type}GroupNum`] = Math.min(g_keyObj.currentPtn, 0);
9081
9082
  };
9082
9083
 
9083
9084
  /*-----------------------------------------------------------*/
@@ -9341,30 +9342,67 @@ const buildPreviewUI = (_frame, _playW, _playH) => {
9341
9342
  x: Math.round(_playW / 2 - 220), y: Math.round((_playH + (g_posObj?.stepYR ?? 0)) / 2 - 60), w: 440, h: 120,
9342
9343
  }));
9343
9344
  } else {
9344
- const jX0 = Math.round(_playW / 2 - 220) + (g_diffObj.arrowJdgX ?? 0);
9345
- const jY0 = Math.round((_playH + (g_posObj?.stepYR ?? 0)) / 2 - 60) + (g_diffObj.arrowJdgY ?? 0);
9346
- const fX0 = Math.round(_playW / 2 - 120) + (g_diffObj.frzJdgX ?? 0);
9347
- const fY0 = Math.round((_playH + (g_posObj?.stepYR ?? 0)) / 2 + 10) + (g_diffObj.frzJdgY ?? 0);
9348
-
9349
- const jdgInitX = g_previewPos.arrowJdg.x ?? jX0;
9350
- const jdgInitY = g_previewPos.arrowJdg.y ?? jY0;
9351
- const jdgFInitX = g_previewPos.frzJdg.x ?? fX0;
9352
- const jdgFInitY = g_previewPos.frzJdg.y ?? fY0;
9353
-
9354
- // 通常判定グループ
9355
- buildDraggableJudgGroup(_frame, `arrowJdg`, jdgInitX, jdgInitY, _playW, _playH, {
9356
- charaText: d.judgment === C_FLG_ON ? g_lblNameObj.j_ii : ``,
9357
- comboText: d.judgment === C_FLG_ON ? `5 Combo!!` : ``,
9358
- diffText: `Fast 3 Frames`,
9359
- charaColor: `#66ffff`,
9360
- });
9345
+ const opacity = g_stateObj.opacity / 100;
9346
+ const jdgCenterY = Math.round((_playH + (g_posObj?.stepYR ?? 0)) / 2);
9347
+ const groupW = 370;
9348
+ const groupH = 51;
9349
+
9350
+ const jdgSettings = [
9351
+ {
9352
+ key: `arrowJdg`,
9353
+ stdYOffset: -60,
9354
+ offsetX: g_diffObj.arrowJdgX ?? 0,
9355
+ offsetY: g_diffObj.arrowJdgY ?? 0,
9356
+ chara: d.judgment === C_FLG_ON ? g_lblNameObj.j_ii : ``,
9357
+ css: [g_cssObj.common_ii, g_cssObj.common_kita], // [chara, combo]
9358
+ toast: g_lblNameObj.arrowJdgUpdate,
9359
+ },
9360
+ {
9361
+ key: `frzJdg`,
9362
+ stdYOffset: 10,
9363
+ offsetX: g_diffObj.frzJdgX ?? 0,
9364
+ offsetY: g_diffObj.frzJdgY ?? 0,
9365
+ chara: d.judgment === C_FLG_ON ? g_lblNameObj.j_kita : ``,
9366
+ css: [g_cssObj.common_kita, g_cssObj.common_ii],
9367
+ toast: g_lblNameObj.frzJdgUpdate,
9368
+ }
9369
+ ];
9370
+
9371
+ jdgSettings.forEach(item => {
9361
9372
 
9362
- // フリーズ判定グループ
9363
- buildDraggableJudgGroup(_frame, `frzJdg`, jdgFInitX, jdgFInitY, _playW, _playH, {
9364
- charaText: d.judgment === C_FLG_ON ? g_lblNameObj.j_kita : ``,
9365
- comboText: d.judgment === C_FLG_ON ? `5 Combo!!` : ``,
9366
- diffText: `Fast 2 Frames`,
9367
- charaColor: `#ffff99`,
9373
+ const stdX = Math.round(_playW / 2 - (item.key === `arrowJdg` ? 220 : 120));
9374
+ const initX = g_previewPos[item.key].x ?? (stdX + item.offsetX);
9375
+ const initY = g_previewPos[item.key].y ?? (jdgCenterY + item.offsetY + item.stdYOffset);
9376
+
9377
+ // グループコンテナの生成
9378
+ const group = createEmptySprite(_frame, `previewGrp_${item.key}`, {
9379
+ x: initX, y: initY, w: groupW, h: groupH, pointerEvents: C_DIS_AUTO,
9380
+ });
9381
+
9382
+ // ラベル類の配置
9383
+ multiAppend(group,
9384
+ createDivCss2Label(`previewChara_${item.key}`, item.chara, {
9385
+ x: 0, y: 0, w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight,
9386
+ siz: g_limitObj.jdgCharaSiz, opacity,
9387
+ }, item.css[0]),
9388
+ createDivCss2Label(`previewCombo_${item.key}`, d.judgment === C_FLG_ON ? `5 Combo!!` : ``, {
9389
+ x: 170, y: 0, w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight,
9390
+ siz: g_limitObj.jdgCharaSiz, opacity,
9391
+ }, item.css[1]),
9392
+ createDivCss2Label(`previewDiff_${item.key}`, `Fast 3 Frames`, {
9393
+ x: 170, y: 25, w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight,
9394
+ siz: g_limitObj.mainSiz, color: `#ff9966`, opacity,
9395
+ }, g_cssObj.common_fast),
9396
+ );
9397
+
9398
+ // ドラッグ機能を付与
9399
+ makeElementDraggable(group, item.key, _playW, _playH, { w: groupW, h: groupH }, {
9400
+ toastTitle: item.toast,
9401
+ getStdPos: () => ({
9402
+ x: stdX,
9403
+ y: Math.round(jdgCenterY + item.stdYOffset),
9404
+ }),
9405
+ });
9368
9406
  });
9369
9407
  }
9370
9408
 
@@ -9467,8 +9505,10 @@ const buildPreviewUI = (_frame, _playW, _playH) => {
9467
9505
  );
9468
9506
  const scConfig = {
9469
9507
  toastTitle: g_lblNameObj.shortcutUpdate,
9470
- getStdX: (pw) => g_sWidth + g_headerObj.scAreaWidth - 85,
9471
- getStdY: (ph, syr) => _playH - 65,
9508
+ getStdPos: () => ({
9509
+ x: g_sWidth + g_headerObj.scAreaWidth - 85,
9510
+ y: _playH - 65
9511
+ }),
9472
9512
  };
9473
9513
  makeElementDraggable(scGroup, `shortcut`, _playW, _playH, { w: 80, h: 65 }, scConfig);
9474
9514
 
@@ -9602,65 +9642,6 @@ const makeElementDraggable = (_target, _key, _playW, _playH, _bounds, _config) =
9602
9642
  _target.setAttribute(`lsnrkeyTE`, keyUp);
9603
9643
  };
9604
9644
 
9605
- /**
9606
- * ドラッグ可能な判定グループを生成する
9607
- * @param {HTMLElement} _parent 親要素
9608
- * @param {string} _groupId `arrowJdg` または `frzJdg`
9609
- * @param {number} _initX 初期X座標(frame相対)
9610
- * @param {number} _initY 初期Y座標(frame相対)
9611
- * @param {number} _playW プレイ幅
9612
- * @param {number} _playH プレイ高さ
9613
- * @param {object} _opts 表示テキスト・色オプション
9614
- */
9615
- const buildDraggableJudgGroup = (_parent, _groupId, _initX, _initY, _playW, _playH, _opts) => {
9616
- const groupW = 370;
9617
- const groupH = 51;
9618
-
9619
- const group = createEmptySprite(_parent, `previewGrp_${_groupId}`, {
9620
- x: _initX, y: _initY, w: groupW, h: groupH, pointerEvents: C_DIS_AUTO,
9621
- });
9622
- const opacity = g_stateObj.opacity / 100;
9623
-
9624
- // 内包要素の生成 (省略:元のコードの multiAppend 部分と同一)
9625
- multiAppend(
9626
- group,
9627
- // キャラクタ
9628
- createDivCss2Label(`previewChara_${_groupId}`, _opts.charaText, {
9629
- x: 0, y: 0, w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight,
9630
- siz: g_limitObj.jdgCharaSiz, opacity,
9631
- }, _groupId === `arrowJdg` ? g_cssObj.common_ii : g_cssObj.common_kita),
9632
- // コンボ
9633
- createDivCss2Label(`previewCombo_${_groupId}`, _opts.comboText, {
9634
- x: 170, y: 0, w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight,
9635
- siz: g_limitObj.jdgCharaSiz, opacity,
9636
- }, _groupId === `arrowJdg` ? g_cssObj.common_kita : g_cssObj.common_ii),
9637
- // Fast/Slow
9638
- createDivCss2Label(`previewDiff_${_groupId}`, _opts.diffText, {
9639
- x: 170, y: 25, w: g_limitObj.jdgCharaWidth, h: g_limitObj.jdgCharaHeight,
9640
- siz: g_limitObj.mainSiz, color: `#ff9966`, opacity,
9641
- }, g_cssObj.common_fast),
9642
- );
9643
-
9644
- // ============================================================
9645
- // 判定グループ固有の「座標反映ルール」を定義
9646
- // ============================================================
9647
- const configMap = {
9648
- arrowJdg: {
9649
- toastTitle: g_lblNameObj.arrowJdgUpdate,
9650
- getStdX: (pw) => Math.round(pw / 2 - 220),
9651
- getStdY: (ph, syr) => Math.round((ph + syr) / 2 - 60),
9652
- },
9653
- frzJdg: {
9654
- toastTitle: g_lblNameObj.frzJdgUpdate,
9655
- getStdX: (pw) => Math.round(pw / 2 - 120),
9656
- getStdY: (ph, syr) => Math.round((ph + syr) / 2 + 10),
9657
- }
9658
- };
9659
-
9660
- // 汎用ドラッグ及びドラッグ枠作成、差分適用処理
9661
- makeElementDraggable(group, _groupId, _playW, _playH, { w: groupW, h: groupH }, configMap[_groupId]);
9662
- };
9663
-
9664
9645
  /**
9665
9646
  * ドラッグ結果の座標をゲーム本体の設定に汎用的に反映する
9666
9647
  * @param {number} _x 確定したframe相対X
@@ -9669,17 +9650,13 @@ const buildDraggableJudgGroup = (_parent, _groupId, _initX, _initY, _playW, _pla
9669
9650
  * @param {string} _key 保存用キー(g_diffObjのプロパティ名の接頭辞)
9670
9651
  */
9671
9652
  const applyElementPositionToGame = (_x, _y, _config, _key) => {
9672
- const playW = g_headerObj.playingWidth || g_sWidth;
9673
- const playH = g_headerObj.playingHeight || g_sHeight;
9674
- const stepYR = g_posObj?.stepYR ?? 0;
9675
9653
 
9676
9654
  // 1. 各要素固有の「標準座標(基準点)」を計算
9677
- const stdX = _config.getStdX(playW);
9678
- const stdY = _config.getStdY(playH, stepYR);
9655
+ const std = _config.getStdPos();
9679
9656
 
9680
9657
  // 2. オフセット(差分)を計算
9681
- const diffX = _x - stdX;
9682
- const diffY = _y - stdY;
9658
+ const diffX = _x - std.x;
9659
+ const diffY = _y - std.y;
9683
9660
 
9684
9661
  // 3. 指定された保存先にオフセットを格納
9685
9662
  g_diffObj[`${_key}X`] = diffX;
@@ -9816,7 +9793,7 @@ const createSettingsDisplayWindow = _sprite => {
9816
9793
 
9817
9794
  // ---------------------------------------------------
9818
9795
  // 矢印の見え方 (Appearance)
9819
- // 縦位置: 7.4
9796
+ // 縦位置: 5.8
9820
9797
  createGeneralSetting(spriteList.appearance, `appearance`, {
9821
9798
  addRFunc: () => dispAppearanceSlider(),
9822
9799
  });
@@ -9856,14 +9833,14 @@ const createSettingsDisplayWindow = _sprite => {
9856
9833
 
9857
9834
  // ---------------------------------------------------
9858
9835
  // 判定表示系の不透明度 (Opacity)
9859
- // 縦位置: 9
9836
+ // 縦位置: 7.4
9860
9837
  g_headerObj.opacityUse = g_headerObj.judgmentUse || g_headerObj.judgmentSet === C_FLG_ON;
9861
9838
 
9862
9839
  createGeneralSetting(spriteList.opacity, `opacity`, { unitName: g_lblNameObj.percent });
9863
9840
 
9864
9841
  // ---------------------------------------------------
9865
9842
  // タイミング調整 (HitPosition)
9866
- // 縦位置: 10
9843
+ // 縦位置: 8.4
9867
9844
  createGeneralSetting(spriteList.hitPosition, `hitPosition`, {
9868
9845
  skipTerms: g_settings.hitPositionTerms, scLabel: g_lblNameObj.sc_hitPosition, roundNum: 5,
9869
9846
  unitName: g_lblNameObj.pixel,
@@ -11066,34 +11043,31 @@ const keyconfigKeyboardPreview = (() => {
11066
11043
 
11067
11044
  // 色定義(既存ゲームの配色に合わせたダーク系)
11068
11045
  const C_COLOR = {
11069
- keyFill: `#1a1a2e`, // 通常キー背景
11070
- keyStroke: `#555577`, // 通常キー枠
11071
- keyText: `#ccccdd`, // 通常キー文字
11072
- keySubText: `#888899`, // サブラベル(Shift面)
11073
- mappedFill: `#003366`, // メインキー背景
11074
- mappedStroke: `#4488ff`, // メインキー枠
11075
- mappedText: `#aaddff`, // メインキー文字
11076
- altFill: `#3e3e1a`, // 代替キー背景
11077
- altStroke: `#777755`, // 代替キー枠
11078
- altText: `#eeeecc`, // 代替キー文字
11079
- shortcutFill: `#330011`, // ショートカットキー背景
11080
- shortcutStroke: `#ff4466`, // ショートカットキー枠
11081
- shortcutText: `#ffaacc`, // ショートカットキー文字
11082
- bgFill: `#0d0d1a`, // Canvas 背景
11083
- legendText: `#cccccc`, // 凡例テキスト
11046
+ normal: {
11047
+ fill: `#1a1a2e`, // 通常キー背景
11048
+ stroke: `#555577`, // 通常キー枠
11049
+ text: `#ccccdd`, // 通常キー文字
11050
+ subText: `#888899`, // サブラベル(Shift面)
11051
+ },
11052
+ mapped: {
11053
+ fill: `#003366`, // メインキー背景
11054
+ stroke: `#4488ff`, // メインキー枠
11055
+ text: `#aaddff`, // メインキー文字
11056
+ },
11057
+ alt: {
11058
+ fill: `#3e3e1a`, // 代替キー背景
11059
+ stroke: `#777755`, // 代替キー枠
11060
+ text: `#eeeecc`, // 代替キー文字
11061
+ },
11062
+ shortcut: {
11063
+ fill: `#330011`, // ショートカットキー背景
11064
+ stroke: `#ff4466`, // ショートカットキー枠
11065
+ text: `#ffaacc`, // ショートカットキー文字
11066
+ },
11067
+ bgFill: `#0d0d1a`, // Canvas 背景
11068
+ legendText: `#cccccc`, // 凡例テキスト
11084
11069
  };
11085
11070
 
11086
- // ボタン配置
11087
- // X・W は init() 内で動的計算(g_btnWidth() 依存)
11088
- // Y: KeyConfig テキスト上の余白に収まるよう小さく設定
11089
- const BTN_H = 18; // ボタン高さ
11090
- const BTN_Y = 3; // divRoot 内 Y 座標
11091
- const BTN_FS = 11; // ボタンのフォントサイズ(px)
11092
-
11093
- // プレビューエリア
11094
- // X: canvas を divRoot 内で水平センタリング(init で動的計算)
11095
- // Y: g_sHeight に対して垂直センタリング(init で動的計算)
11096
-
11097
11071
  // 凡例エリアの高さ
11098
11072
  const LEGEND_H = 25;
11099
11073
 
@@ -11104,15 +11078,12 @@ const keyconfigKeyboardPreview = (() => {
11104
11078
  // offsetX : 行左端の水平オフセット(単位: BASE_KEY_W)。未指定時は0
11105
11079
  // keys : キー定義の配列
11106
11080
  //
11107
- // 各キー: { kc, w?, h?, label? }
11108
- // kc : keyCode(数値)。-1 はスペーサー(描画・キャッシュなし)。
11109
- // w : 幅倍率(BASE_KEY_W 基準。省略時 1)
11110
- // h : 高さ倍率(BASE_KEY_H 基準。省略時 1)
11111
- // label : 省略時は g_kCd[kc] を参照。g_kCd が空文字のキーや
11112
- // 左右を区別したいキーに指定する。
11113
- //
11114
- // 右Shift/Ctrl/Alt は danoniplus 独自コード 256〜258 を使用。
11115
- // Appli キーは 93 を使用(g_kCd[93] = `Appli`)。
11081
+ // 各キー: { code, w?, h?, label? }
11082
+ // code : KeyboardEvent.code(文字列)。空文字 "" はスペーサー(描画・キャッシュなし)。
11083
+ // w : 幅倍率(BASE_KEY_W 基準。省略時 1)
11084
+ // h : 高さ倍率(BASE_KEY_H 基準。省略時 1)
11085
+ // label : 省略時は g_kCd[keyCode] を参照。g_kCd が空文字のキーや
11086
+ // 左右を区別したいキーに指定する。
11116
11087
  // -------------------------------------------------------------------------
11117
11088
  /**
11118
11089
  * g_localeObj.val に応じた MAIN_ROWS を生成して返す。
@@ -11126,106 +11097,106 @@ const keyconfigKeyboardPreview = (() => {
11126
11097
  // Row0: Fn キー行(JIS/US 共通)
11127
11098
  {
11128
11099
  keys: [
11129
- { kc: 27 }, // Esc
11130
- { kc: -1, w: 0.5 }, // スペーサー
11131
- { kc: 112 }, { kc: 113 }, { kc: 114 }, { kc: 115 },
11132
- { kc: -1, w: 0.25 }, // スペーサー
11133
- { kc: 116 }, { kc: 117 }, { kc: 118 }, { kc: 119 },
11134
- { kc: -1, w: 0.25 }, // スペーサー
11135
- { kc: 120 }, { kc: 121 }, { kc: 122 }, { kc: 123 },
11100
+ { code: `Escape` },
11101
+ { code: ``, w: 0.5 }, // スペーサー
11102
+ { code: `F1` }, { code: `F2` }, { code: `F3` }, { code: `F4` },
11103
+ { code: ``, w: 0.25 }, // スペーサー
11104
+ { code: `F5` }, { code: `F6` }, { code: `F7` }, { code: `F8` },
11105
+ { code: ``, w: 0.25 }, // スペーサー
11106
+ { code: `F9` }, { code: `F10` }, { code: `F11` }, { code: `F12` },
11136
11107
  ],
11137
11108
  },
11138
11109
  // Row1: 数字行
11139
- // JIS: ..., 220(intlYen), BS
11140
- // US : ..., BS
11110
+ // JIS: ..., Minus, Equal, IntlYen, BS
11111
+ // US : ..., Minus, Equal, BS
11141
11112
  {
11142
11113
  keys: [
11143
- { kc: 229 },
11144
- { kc: 49 }, { kc: 50 }, { kc: 51 }, { kc: 52 }, { kc: 53 }, { kc: 54 },
11145
- { kc: 55 }, { kc: 56 }, { kc: 57 }, { kc: 48 }, { kc: 189 }, { kc: 222 },
11114
+ { code: `Backquote` },
11115
+ { code: `Digit1` }, { code: `Digit2` }, { code: `Digit3` }, { code: `Digit4` }, { code: `Digit5` }, { code: `Digit6` },
11116
+ { code: `Digit7` }, { code: `Digit8` }, { code: `Digit9` }, { code: `Digit0` }, { code: `Minus` }, { code: `Equal` },
11146
11117
  ...(isJa
11147
- ? [{ kc: 220, w: 0.75 }, { kc: 8, label: `Back\nSpace` }] // JIS: intlYen + BS
11148
- : [{ kc: 8, w: 1.7 }] // US : BS のみ(広い)
11118
+ ? [{ code: `IntlYen`, w: 0.75 }, { code: `Backspace`, label: `Back\nSpace` }] // JIS: IntlYen + BS
11119
+ : [{ code: `Backspace`, w: 1.7 }] // US : BS のみ(広い)
11149
11120
  ),
11150
11121
  ],
11151
11122
  },
11152
11123
  // Row2: QWERTY
11153
- // JIS: ..., [, Enter(13)
11154
- // US : ..., [, ]
11124
+ // JIS: ..., BracketLeft, BracketRight, Enter(縦長)
11125
+ // US : ..., BracketLeft, BracketRight, Backslash
11155
11126
  {
11156
11127
  keys: [
11157
- { kc: 9, w: 1.5 },
11158
- { kc: 81 }, { kc: 87 }, { kc: 69 }, { kc: 82 }, { kc: 84 }, { kc: 89 },
11159
- { kc: 85 }, { kc: 73 }, { kc: 79 }, { kc: 80 }, { kc: 192 },
11128
+ { code: `Tab`, w: 1.5 },
11129
+ { code: `KeyQ` }, { code: `KeyW` }, { code: `KeyE` }, { code: `KeyR` }, { code: `KeyT` }, { code: `KeyY` },
11130
+ { code: `KeyU` }, { code: `KeyI` }, { code: `KeyO` }, { code: `KeyP` }, { code: `BracketLeft` },
11160
11131
  ...(isJa
11161
- ? [{ kc: 219 }, { kc: 13, w: 1.25, h: 2 }] // JIS: [, Enter縦長
11162
- : [{ kc: 219 }, { kc: 221, w: 1.2 }] // US : [, ]
11132
+ ? [{ code: `BracketRight` }, { code: `Enter`, w: 1.25, h: 2 }] // JIS: BracketRight + Enter縦長
11133
+ : [{ code: `BracketRight` }, { code: `Backslash`, w: 1.2 }] // US : BracketRight + Backslash
11163
11134
  ),
11164
11135
  ],
11165
11136
  },
11166
11137
  // Row3: ASDF
11167
- // JIS: ..., L, ;, ', ¥(221)
11168
- // US : ..., L, ;, ', Enter(13)
11138
+ // JIS: ..., KeyL, Semicolon, Quote, Backslash
11139
+ // US : ..., KeyL, Semicolon, Quote, Enter(横長)
11169
11140
  {
11170
11141
  keys: [
11171
- { kc: 20, w: 1.75, label: `Caps\nLock` },
11172
- { kc: 65 }, { kc: 83 }, { kc: 68 }, { kc: 70 }, { kc: 71 }, { kc: 72 },
11173
- { kc: 74 }, { kc: 75 }, { kc: 76 }, { kc: 187 }, { kc: 186 },
11142
+ { code: `CapsLock`, w: 1.75, label: `Caps\nLock` },
11143
+ { code: `KeyA` }, { code: `KeyS` }, { code: `KeyD` }, { code: `KeyF` }, { code: `KeyG` }, { code: `KeyH` },
11144
+ { code: `KeyJ` }, { code: `KeyK` }, { code: `KeyL` }, { code: `Semicolon` }, { code: `Quote` },
11174
11145
  ...(isJa
11175
- ? [{ kc: 221 }] // JIS: ¥
11176
- : [{ kc: 13, w: 1.9 }] // US : Enter横長
11146
+ ? [{ code: `Backslash` }] // JIS: Backslash(¥)
11147
+ : [{ code: `Enter`, w: 1.9 }] // US : Enter横長
11177
11148
  ),
11178
11149
  ],
11179
11150
  },
11180
11151
  // Row4: ZXCV
11181
11152
  // L)Shift の幅で行頭位置を揃える
11182
- // JIS: L)Shift, ..., intlRo(226), R)Shift
11183
- // US : L)Shift, ..., R)Shift
11153
+ // JIS: L)Shift, ..., IntlRo, R)Shift
11154
+ // US : L)Shift, ..., R)Shift
11184
11155
  {
11185
11156
  keys: [
11186
- { kc: 16, w: 2.25 },
11187
- { kc: 90 }, { kc: 88 }, { kc: 67 }, { kc: 86 }, { kc: 66 }, { kc: 78 },
11188
- { kc: 77 }, { kc: 188 }, { kc: 190 }, { kc: 191 },
11157
+ { code: `ShiftLeft`, w: 2.25 },
11158
+ { code: `KeyZ` }, { code: `KeyX` }, { code: `KeyC` }, { code: `KeyV` }, { code: `KeyB` }, { code: `KeyN` },
11159
+ { code: `KeyM` }, { code: `Comma` }, { code: `Period` }, { code: `Slash` },
11189
11160
  ...(isJa
11190
- ? [{ kc: 226 }, { kc: 256, w: 1.5 }] // JIS: intlRo + R)Shift
11191
- : [{ kc: 256, w: 2.4 }] // US : R)Shift のみ(広い)
11161
+ ? [{ code: `IntlRo` }, { code: `ShiftRight`, w: 1.5 }] // JIS: IntlRo + R)Shift
11162
+ : [{ code: `ShiftRight`, w: 2.4 }] // US : R)Shift のみ(広い)
11192
11163
  ),
11193
11164
  ],
11194
11165
  },
11195
11166
  // Row5: スペースバー行
11196
- // JIS: ..., NoConv(29), Space, Conv(28), カタカナひらがな(242), ...
11167
+ // JIS: ..., NonConvert, Space, Convert, KanaMode, ...
11197
11168
  // US : ..., Space, ...
11198
11169
  {
11199
11170
  keys: [
11200
- { kc: 17, w: 1.25 }, { kc: 91 }, { kc: 18 },
11171
+ { code: `ControlLeft`, w: 1.25 }, { code: `MetaLeft` }, { code: `AltLeft` },
11201
11172
  ...(isJa
11202
- // JIS: NoConv + Space + Conv + カタカナひらがな
11203
- ? [{ kc: 29 }, { kc: 32, w: 5.25 }, { kc: 28 }, { kc: 242 }]
11173
+ // JIS: NonConvert + Space + Convert + KanaMode
11174
+ ? [{ code: `NonConvert` }, { code: `Space`, w: 5.25 }, { code: `Convert` }, { code: `KanaMode` }]
11204
11175
  // US : Space のみ(広い)
11205
- : [{ kc: 32, w: 8.25 }]
11176
+ : [{ code: `Space`, w: 8.25 }]
11206
11177
  ),
11207
- { kc: 258 }, { kc: 93 },
11178
+ { code: `AltRight` }, { code: `ContextMenu` },
11208
11179
  ...(isJa
11209
- ? [{ kc: 257, w: 1.2 }]
11210
- : [{ kc: 257, w: 1.05 }]
11180
+ ? [{ code: `ControlRight`, w: 1.2 }]
11181
+ : [{ code: `ControlRight`, w: 1.05 }]
11211
11182
  ),
11212
11183
  ],
11213
11184
  },
11214
11185
  ];
11215
11186
  };
11187
+
11216
11188
  // 編集キークラスター(PrintSc/ScrollLk/Pause/Insert/Delete/Home/End/PgUp/PgDn + 矢印キー)
11217
11189
  // MAIN_ROWS と行インデックスを揃えて配置する。空行はスキップされる。
11218
11190
  const NAV_ROWS = [
11219
- { keys: [{ kc: 44, label: `Print\nScreen` }, { kc: 145, label: `Scroll\nLock` }, { kc: 19 }] },
11220
- { keys: [{ kc: 45 }, { kc: 36 }, { kc: 33, label: `Page\nUp` }] }, // Insert Home PgUp
11221
- { keys: [{ kc: 46 }, { kc: 35 }, { kc: 34, label: `Page\nDown` }] }, // Delete End PgDn
11222
- { keys: [] }, // ASDF行:空
11223
- { keys: [{ kc: -1 }, { kc: 38 }, { kc: -1 }] }, // ↑
11224
- { keys: [{ kc: 37 }, { kc: 40 }, { kc: 39 }] }, // ← ↓ →
11191
+ { keys: [{ code: `PrintScreen`, label: `Print\nScreen` }, { code: `ScrollLock`, label: `Scroll\nLock` }, { code: `Pause` }] },
11192
+ { keys: [{ code: `Insert` }, { code: `Home` }, { code: `PageUp`, label: `Page\nUp` }] }, // Insert Home PgUp
11193
+ { keys: [{ code: `Delete` }, { code: `End` }, { code: `PageDown`, label: `Page\nDown` }] }, // Delete End PgDn
11194
+ { keys: [] }, // ASDF行:空
11195
+ { keys: [{ code: `` }, { code: `ArrowUp` }, { code: `` }] }, // ↑
11196
+ { keys: [{ code: `ArrowLeft` }, { code: `ArrowDown` }, { code: `ArrowRight` }] }, // ← ↓ →
11225
11197
  ];
11226
11198
 
11227
11199
  // テンキー(MAIN_ROWS と行インデックスを揃えて配置。1行目は空行で Fn行に揃える)
11228
- // kc は g_kCd 定義に従う: 96〜111=テンキー各種, 144=NumLk
11229
11200
  // 標準テンキーレイアウト(2行目から):
11230
11201
  // [NumLk] [T/] [T*] [T-]
11231
11202
  // [T7][T8][T9] [T+]
@@ -11234,11 +11205,11 @@ const keyconfigKeyboardPreview = (() => {
11234
11205
  // [ T0 ][T.] [TEnter] ← T0 は横2u、TEnter は縦2u
11235
11206
  const NUM_ROWS = [
11236
11207
  { keys: [] },
11237
- { keys: [{ kc: 144, label: `Num\nLock` }, { kc: 111 }, { kc: 106 }, { kc: 109 }] }, // NumLk T/ T* T-
11238
- { keys: [{ kc: 103 }, { kc: 104 }, { kc: 105 }, { kc: 107, h: 2 }] }, // T7 T8 T9 T+(縦2u)
11239
- { keys: [{ kc: 100 }, { kc: 101 }, { kc: 102 }] }, // T4 T5 T6
11240
- { keys: [{ kc: 97 }, { kc: 98 }, { kc: 99 }, { kc: 108, h: 2 }] }, // T1 T2 T3 TEnter(縦2u)
11241
- { keys: [{ kc: 96, w: 2 }, { kc: 110 }] }, // T0(横2u) T.
11208
+ { keys: [{ code: `NumLock`, label: `Num\nLock` }, { code: `NumpadDivide` }, { code: `NumpadMultiply` }, { code: `NumpadSubtract` }] }, // NumLk T/ T* T-
11209
+ { keys: [{ code: `Numpad7` }, { code: `Numpad8` }, { code: `Numpad9` }, { code: `NumpadAdd`, h: 2 }] }, // T7 T8 T9 T+(縦2u)
11210
+ { keys: [{ code: `Numpad4` }, { code: `Numpad5` }, { code: `Numpad6` }] }, // T4 T5 T6
11211
+ { keys: [{ code: `Numpad1` }, { code: `Numpad2` }, { code: `Numpad3` }, { code: `NumpadEnter`, h: 2 }] }, // T1 T2 T3 TEnter(縦2u)
11212
+ { keys: [{ code: `Numpad0`, w: 2 }, { code: `NumpadDecimal` }] }, // T0(横2u) T.
11242
11213
  ];
11243
11214
 
11244
11215
  // -------------------------------------------------------------------------
@@ -11246,12 +11217,12 @@ const keyconfigKeyboardPreview = (() => {
11246
11217
  // -------------------------------------------------------------------------
11247
11218
  const _state = {
11248
11219
  visible: false,
11249
- mappedSet: new Set(), // メインキー(各矢印の index 0)
11250
- altSet: new Set(), // 代替キー(各矢印の index 1 以降)
11251
- shortcutSet: new Set(), // プレイ中ショートカット(keyRetry / keyTitleBack / PgDn / PgUp)
11220
+ mappedSet: new Set(), // メインキー(code文字列)
11221
+ altSet: new Set(), // 代替キー(code文字列)
11222
+ shortcutSet: new Set(), // ショートカットキー(code文字列)
11252
11223
  canvasBase: null,
11253
11224
  canvasMap: null,
11254
- keyRects: [], // { kc, x, y, w, h, label } — drawMap で照合するキャッシュ
11225
+ keyDataList: [], // { code, x, y, w, h, label } — drawMap で照合するキャッシュ
11255
11226
  scale: 1, // BASE_KEY_W/H に掛けるスケール係数
11256
11227
  cvsW: 500, // 実際の Canvas 幅(スケール計算後)
11257
11228
  cvsH: 240, // 実際の Canvas 高さ(スケール計算後)
@@ -11313,22 +11284,24 @@ const keyconfigKeyboardPreview = (() => {
11313
11284
  // -------------------------------------------------------------------------
11314
11285
 
11315
11286
  /**
11316
- * keyCode に対応する [primaryLabel, subLabel] を返す。
11317
- * kc が -1(スペーサー)の場合は [``, ``] を返す。
11318
- * g_kCd の値は `"primary"` または `"primary sub"` 形式の文字列。
11287
+ * code に対応する [primaryLabel, subLabel] を返す。
11319
11288
  *
11320
- * @param {number} kc
11289
+ * @param {string} code
11321
11290
  * @param {string|undefined} forcedLabel - ROWS の label 指定がある場合に優先
11322
11291
  * @returns {string[]} [primary, sub]
11323
11292
  */
11324
- const getKeyLabels = (kc, forcedLabel) => {
11325
- if (kc < 0) return [``, ``];
11293
+ const getKeyLabels = (code, forcedLabel) => {
11294
+ if (!code) return [``, ``];
11326
11295
  if (forcedLabel !== undefined) return [forcedLabel, ``];
11327
11296
 
11328
- const raw = g_kCd[kc];
11329
- if (raw && raw !== g_kCd[0] && raw !== g_kCd[1]) {
11330
- const parts = raw.split(` `);
11331
- return [parts[0] || ``, parts[1] || ``];
11297
+ // code 文字列から従来の keyCode を逆引きして g_kCd から取得
11298
+ const kc = g_kCdN.indexOf(code);
11299
+ if (kc >= 0) {
11300
+ const raw = g_kCd[kc];
11301
+ if (raw && raw !== g_kCd[0] && raw !== g_kCd[1]) {
11302
+ const parts = raw.split(` `);
11303
+ return [parts[0] || ``, parts[1] || ``];
11304
+ }
11332
11305
  }
11333
11306
  return [`?`, ``];
11334
11307
  };
@@ -11343,6 +11316,22 @@ const keyconfigKeyboardPreview = (() => {
11343
11316
  const kg = () => Math.max(1, Math.round(BASE_KEY_GAP * _state.scale));
11344
11317
  const kr = () => Math.max(2, Math.round(4 * _state.scale));
11345
11318
 
11319
+ /**
11320
+ * Canvasの共通初期化処理
11321
+ */
11322
+ const setupCanvasContext = (canvas) => {
11323
+ if (!canvas) return null;
11324
+ canvas.style.top = wUnit(40);
11325
+ canvas.width = _state.cvsW * g_dpr;
11326
+ canvas.height = _state.cvsH * g_dpr;
11327
+ canvas.style.width = wUnit(_state.cvsW);
11328
+ canvas.style.height = wUnit(_state.cvsH);
11329
+
11330
+ const ctx = canvas.getContext(`2d`);
11331
+ ctx.scale(g_dpr, g_dpr);
11332
+ return ctx;
11333
+ };
11334
+
11346
11335
  const roundRect = (ctx, x, y, w, h, r) => {
11347
11336
  ctx.beginPath();
11348
11337
  ctx.moveTo(x + r, y);
@@ -11357,23 +11346,47 @@ const keyconfigKeyboardPreview = (() => {
11357
11346
  ctx.closePath();
11358
11347
  };
11359
11348
 
11360
- const drawKeyLabel = (ctx, x, y, keyW, keyH, primary, sub, textColor, subColor) => {
11349
+ /**
11350
+ * 単一キーを描画する(枠の描画と内部テキストの書き込みを一括化)
11351
+ * @param {CanvasRenderingContext2D} ctx
11352
+ * @param {Object} keyData - 位置・サイズ・キーコードを含むキー情報
11353
+ * @param {Object} style - fill, stroke, text 等の色セット
11354
+ * @param {number} lw - 枠線の太さ(lineWidth)
11355
+ */
11356
+ const drawOneKey = (ctx, { keyData, style, lw = 1 }) => {
11357
+ const { x, y, w: keyW, h: keyH, code, label } = keyData;
11358
+
11359
+ // 1. キーの枠線・背景を描画
11360
+ roundRect(ctx, x + 0.5, y + 0.5, keyW - 1, keyH - 1, kr());
11361
+ ctx.fillStyle = style.fill;
11362
+ ctx.strokeStyle = style.stroke;
11363
+ ctx.lineWidth = lw;
11364
+ ctx.fill();
11365
+ ctx.stroke();
11366
+
11367
+ // 2. キー内部のテキスト(メイン・サブ)を描画
11368
+ const [primary, sub] = getKeyLabels(code, label);
11369
+
11361
11370
  const fs = (_textLen) => _textLen >= 5 * keyW / BASE_KEY_W
11362
11371
  ? Math.max(6, Math.floor(9 * _state.scale))
11363
11372
  : Math.max(7, Math.floor(11 * _state.scale));
11364
11373
 
11374
+ // サブラベル(Shift面などの表記)がある場合
11365
11375
  if (sub) {
11366
- ctx.fillStyle = subColor;
11376
+ ctx.fillStyle = style.subText || style.text;
11367
11377
  ctx.font = `bold ${Math.max(6, Math.floor(9 * _state.scale))}px monospace`;
11368
11378
  ctx.textAlign = `right`;
11369
11379
  ctx.textBaseline = `top`;
11370
11380
  ctx.fillText(sub, x + keyW - 2, y + 2);
11371
11381
  }
11382
+
11383
+ // メインラベルの描画(改行表記に対応)
11372
11384
  const [primary1, primary2] = primary.split(`\n`);
11373
- ctx.fillStyle = textColor;
11385
+ ctx.fillStyle = style.text;
11374
11386
  ctx.textAlign = `center`;
11375
11387
  ctx.textBaseline = `middle`;
11376
11388
  const subDiff = sub ? 2 : 0;
11389
+
11377
11390
  if (primary2) {
11378
11391
  const siz = fs(Math.max(primary1.length, primary2.length));
11379
11392
  ctx.font = `bold ${siz}px monospace`;
@@ -11385,23 +11398,13 @@ const keyconfigKeyboardPreview = (() => {
11385
11398
  }
11386
11399
  };
11387
11400
 
11388
- const drawOneKey = (ctx, x, y, keyW, keyH, fill, stroke, lw, primary, sub, textColor, subColor) => {
11389
- roundRect(ctx, x + 0.5, y + 0.5, keyW - 1, keyH - 1, kr());
11390
- ctx.fillStyle = fill;
11391
- ctx.strokeStyle = stroke;
11392
- ctx.lineWidth = lw;
11393
- ctx.fill();
11394
- ctx.stroke();
11395
- drawKeyLabel(ctx, x, y, keyW, keyH, primary, sub, textColor, subColor);
11396
- };
11397
-
11398
11401
  // -------------------------------------------------------------------------
11399
11402
  // レイアウト計算・描画
11400
11403
  // -------------------------------------------------------------------------
11401
11404
 
11402
11405
  /**
11403
11406
  * rows 配列から各キーの矩形座標を計算し、
11404
- * canvas に描画しながら keyRects へキャッシュする。
11407
+ * canvas に描画しながら keyDataList へキャッシュする。
11405
11408
  *
11406
11409
  * @param {CanvasRenderingContext2D} ctx
11407
11410
  * @param {Array} rows - MAIN_ROWS または NAV_ROWS({offsetX, keys} 形式)
@@ -11423,21 +11426,17 @@ const keyconfigKeyboardPreview = (() => {
11423
11426
  const keyW = kw(keyDef.w || 1);
11424
11427
  const keyH = kh(keyDef.h || 1);
11425
11428
 
11426
- if (keyDef.kc >= 0) {
11427
- _state.keyRects.push({
11428
- kc: keyDef.kc,
11429
+ if (keyDef.code !== ``) {
11430
+ const keyData = {
11431
+ code: keyDef.code,
11429
11432
  x: curX,
11430
11433
  y: rowY,
11431
11434
  w: keyW,
11432
11435
  h: keyH,
11433
11436
  label: keyDef.label,
11434
- });
11435
- const [primary, sub] = getKeyLabels(keyDef.kc, keyDef.label);
11436
- drawOneKey(
11437
- ctx, curX, rowY, keyW, keyH,
11438
- C_COLOR.keyFill, C_COLOR.keyStroke, 1,
11439
- primary, sub, C_COLOR.keyText, C_COLOR.keySubText
11440
- );
11437
+ };
11438
+ _state.keyDataList.push(keyData);
11439
+ drawOneKey(ctx, { keyData, style: C_COLOR.normal, lw: 1 });
11441
11440
  }
11442
11441
 
11443
11442
  curX += keyW + gap;
@@ -11446,26 +11445,18 @@ const keyconfigKeyboardPreview = (() => {
11446
11445
  };
11447
11446
 
11448
11447
  /**
11449
- * キーボード背景レイヤーを描画し keyRects をキャッシュする。
11448
+ * キーボード背景レイヤーを描画し keyDataList をキャッシュする。
11450
11449
  * init 時に呼ぶ。
11451
11450
  */
11452
11451
  const drawBase = () => {
11453
- const canvas = _state.canvasBase;
11454
- if (!canvas) return;
11452
+ const ctx = setupCanvasContext(_state.canvasBase);
11453
+ if (!ctx) return;
11455
11454
 
11456
- canvas.style.top = wUnit(40);
11457
- canvas.width = _state.cvsW * g_dpr;
11458
- canvas.height = _state.cvsH * g_dpr;
11459
- canvas.style.width = wUnit(_state.cvsW);
11460
- canvas.style.height = wUnit(_state.cvsH);
11461
-
11462
- const ctx = canvas.getContext(`2d`);
11463
- ctx.scale(g_dpr, g_dpr);
11464
11455
  ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
11465
11456
  ctx.fillStyle = C_COLOR.bgFill;
11466
11457
  ctx.fillRect(0, 0, _state.cvsW, _state.cvsH);
11467
11458
 
11468
- _state.keyRects = [];
11459
+ _state.keyDataList = [];
11469
11460
 
11470
11461
  const mainRows = buildMainRows();
11471
11462
  const gap = kg();
@@ -11487,25 +11478,26 @@ const keyconfigKeyboardPreview = (() => {
11487
11478
 
11488
11479
  // 凡例
11489
11480
  const ly = _state.cvsH - 10;
11490
- const fnt = `${Math.max(9, Math.floor(12 * _state.scale))}px ${getBasicFont()}`;
11491
- ctx.font = fnt;
11481
+ ctx.font = `${Math.max(9, Math.floor(12 * _state.scale))}px ${getBasicFont()}`;
11492
11482
  ctx.textAlign = `left`;
11493
11483
  ctx.textBaseline = `middle`;
11494
11484
 
11495
- const drawLegend = (x, fill, stroke, label) => {
11496
- roundRect(ctx, x, ly - 5, 10, 10, 2);
11497
- ctx.fillStyle = fill; ctx.fill();
11498
- ctx.strokeStyle = stroke; ctx.lineWidth = 1; ctx.stroke();
11499
- ctx.fillStyle = C_COLOR.legendText;
11500
- ctx.fillText(label, x + 14, ly);
11485
+ const legends = [
11486
+ { style: C_COLOR.normal, label: g_lblNameObj.unallocated },
11487
+ { style: C_COLOR.mapped, label: g_lblNameObj.allocated },
11488
+ { style: C_COLOR.alt, label: g_lblNameObj.altAllocated },
11489
+ { style: C_COLOR.shortcut, label: g_lblNameObj.shortcutKey }
11490
+ ];
11501
11491
 
11502
- return 14 + ctx.measureText(label).width + 14;
11503
- };
11504
11492
  let lx = 8;
11505
- lx += drawLegend(lx, C_COLOR.keyFill, C_COLOR.keyStroke, g_lblNameObj.unallocated);
11506
- lx += drawLegend(lx, C_COLOR.mappedFill, C_COLOR.mappedStroke, g_lblNameObj.allocated);
11507
- lx += drawLegend(lx, C_COLOR.altFill, C_COLOR.altStroke, g_lblNameObj.altAllocated);
11508
- lx += drawLegend(lx, C_COLOR.shortcutFill, C_COLOR.shortcutStroke, g_lblNameObj.shortcutKey);
11493
+ legends.forEach(item => {
11494
+ roundRect(ctx, lx, ly - 5, 10, 10, 2);
11495
+ ctx.fillStyle = item.style.fill; ctx.fill();
11496
+ ctx.strokeStyle = item.style.stroke; ctx.lineWidth = 1; ctx.stroke();
11497
+ ctx.fillStyle = C_COLOR.legendText;
11498
+ ctx.fillText(item.label, lx + 14, ly);
11499
+ lx += ctx.measureText(item.label).width + 28;
11500
+ });
11509
11501
  };
11510
11502
 
11511
11503
  /**
@@ -11514,47 +11506,25 @@ const keyconfigKeyboardPreview = (() => {
11514
11506
  * 同一キーにメインと代替が重なる場合はメインを優先する。
11515
11507
  */
11516
11508
  const drawMap = () => {
11517
- const canvas = _state.canvasMap;
11518
- if (!canvas) return;
11509
+ const ctx = setupCanvasContext(_state.canvasMap);
11510
+ if (!ctx) return;
11519
11511
 
11520
- canvas.style.top = wUnit(40);
11521
- canvas.width = _state.cvsW * g_dpr;
11522
- canvas.height = _state.cvsH * g_dpr;
11523
- canvas.style.width = wUnit(_state.cvsW);
11524
- canvas.style.height = wUnit(_state.cvsH);
11525
-
11526
- const ctx = canvas.getContext(`2d`);
11527
- ctx.scale(g_dpr, g_dpr);
11528
11512
  ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
11529
11513
 
11530
- // 優先度: ショートカット > メイン > 代替(後から描くほど優先)
11531
- const drawKey = (fill, stroke, text) => rect => {
11532
- const [primary, sub] = getKeyLabels(rect.kc, rect.label);
11533
- roundRect(ctx, rect.x + 0.5, rect.y + 0.5, rect.w - 1, rect.h - 1, kr());
11534
- ctx.fillStyle = fill;
11535
- ctx.strokeStyle = stroke;
11536
- ctx.lineWidth = 1.5;
11537
- ctx.fill();
11538
- ctx.stroke();
11539
- drawKeyLabel(ctx, rect.x, rect.y, rect.w, rect.h, primary, sub, text, text);
11514
+ // キー状態に応じた色取得ロジック(優先度: ショートカット > メイン > 代替)
11515
+ const getKeyStyle = (code) => {
11516
+ if (_state.shortcutSet.has(code)) return C_COLOR.shortcut;
11517
+ if (_state.mappedSet.has(code)) return C_COLOR.mapped;
11518
+ if (_state.altSet.has(code)) return C_COLOR.alt;
11519
+ return null;
11540
11520
  };
11541
11521
 
11542
- // 1. 代替キー(メイン・ショートカットと重複しない場合のみ)
11543
- _state.keyRects
11544
- .filter(rect => _state.altSet.has(rect.kc)
11545
- && !_state.mappedSet.has(rect.kc)
11546
- && !_state.shortcutSet.has(rect.kc))
11547
- .forEach(drawKey(C_COLOR.altFill, C_COLOR.altStroke, C_COLOR.altText));
11548
-
11549
- // 2. メインキー(ショートカットと重複しない場合のみ)
11550
- _state.keyRects
11551
- .filter(rect => _state.mappedSet.has(rect.kc) && !_state.shortcutSet.has(rect.kc))
11552
- .forEach(drawKey(C_COLOR.mappedFill, C_COLOR.mappedStroke, C_COLOR.mappedText));
11553
-
11554
- // 3. ショートカット(常に最前面)
11555
- _state.keyRects
11556
- .filter(rect => _state.shortcutSet.has(rect.kc))
11557
- .forEach(drawKey(C_COLOR.shortcutFill, C_COLOR.shortcutStroke, C_COLOR.shortcutText));
11522
+ _state.keyDataList.forEach(keyData => {
11523
+ const style = getKeyStyle(keyData.code);
11524
+ if (style) {
11525
+ drawOneKey(ctx, { keyData, style, lw: 1.5 });
11526
+ }
11527
+ });
11558
11528
  };
11559
11529
 
11560
11530
  // -------------------------------------------------------------------------
@@ -11627,12 +11597,17 @@ const keyconfigKeyboardPreview = (() => {
11627
11597
  const ctrl = g_keyObj[`keyCtrl${tkObj.keyCtrlPtn}`]
11628
11598
  .filter((val, idx) => tkObj.keyGroupMaps[idx].includes(configKeyGroupList[g_keycons.keySwitchNum]));
11629
11599
 
11630
- _state.mappedSet = new Set(ctrl.map(arr => arr[0]).filter(v => v > 0));
11631
- _state.altSet = new Set(ctrl.flatMap(arr => arr.slice(1)).filter(v => v > 0));
11600
+ // 数値から code 文字列へ安全に変換するヘルパー
11601
+ const toCodeStr = (num) => g_kCdN[num] || ``;
11602
+
11603
+ _state.mappedSet = new Set(ctrl.map(arr => toCodeStr(arr[0])).filter(v => v !== ``));
11604
+ _state.altSet = new Set(ctrl.flatMap(arr => arr.slice(1)).map(toCodeStr).filter(v => v !== ``));
11605
+
11632
11606
  // プレイ中ショートカット: keyRetry / keyTitleBack は g_headerObj から取得、PgDn(34) / PgUp(33) は固定
11633
11607
  _state.shortcutSet = new Set(
11634
- [g_headerObj.keyRetry, g_headerObj.keyTitleBack, 34, 33].filter(v => v > 0)
11608
+ [g_headerObj.keyRetry, g_headerObj.keyTitleBack, 34, 33].map(toCodeStr).filter(v => v !== ``)
11635
11609
  );
11610
+
11636
11611
  if (_state.visible) drawMap();
11637
11612
  };
11638
11613
 
@@ -11645,7 +11620,7 @@ const keyconfigKeyboardPreview = (() => {
11645
11620
  _state.mappedSet = new Set();
11646
11621
  _state.altSet = new Set();
11647
11622
  _state.shortcutSet = new Set();
11648
- _state.keyRects = [];
11623
+ _state.keyDataList = [];
11649
11624
  _state.canvasBase = null;
11650
11625
  _state.canvasMap = null;
11651
11626
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "48.4.0",
3
+ "version": "48.4.2",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "./js/danoni_main.js",
6
6
  "jsdelivr": "./js/danoni_main.js",