danoniplus 47.5.3 → 47.6.1

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.
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/05/09
7
+ * Revised : 2026/05/13
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 47.5.3`;
12
- const g_revisedDate = `2026/05/09`;
11
+ const g_version = `Ver 47.6.1`;
12
+ const g_revisedDate = `2026/05/13`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -10194,6 +10194,9 @@ const keyConfigInit = (_kcType = g_kcType) => {
10194
10194
  // カーソル位置の初期化
10195
10195
  appearConfigSteps(g_keycons.keySwitchNum);
10196
10196
 
10197
+ keyconfigKeyboardPreview.dispose();
10198
+ keyconfigKeyboardPreview.init(divRoot);
10199
+
10197
10200
  // ラベル・ボタン描画
10198
10201
  multiAppend(divRoot,
10199
10202
 
@@ -10342,6 +10345,664 @@ const keyConfigInit = (_kcType = g_kcType) => {
10342
10345
  document.oncontextmenu = () => false;
10343
10346
  };
10344
10347
 
10348
+ /**
10349
+ * キーボードレイアウトプレビュー(Canvas版)
10350
+ *
10351
+ * キーコンフィグ画面(divRoot)配下に以下の要素を追加する:
10352
+ * - [Preview] ボタン (createCss2Button)
10353
+ * - プレビュー用コンテナ div (createEmptySprite)
10354
+ * ├ キーボード背景 canvas (_state.canvasBase) ← 起動時のみ描画
10355
+ * └ マッピング強調 canvas (_state.canvasMap) ← キー変更・表示時に再描画
10356
+ *
10357
+ * 前提:
10358
+ * - g_kCd : グローバル定義済み。ロケール切替後は g_lang_kCd がマージ済み。
10359
+ * 未設定キーは空文字列 `""` で初期化。
10360
+ * 右Shift/Ctrl/Alt は 256/257/258 の独自コードで定義。
10361
+ * - g_btnWidth() : 画面の横幅(px)を返すグローバル関数。
10362
+ * - g_sHeight : 画面の縦幅(px)を保持するグローバル変数。
10363
+ * - createCss2Button, createEmptySprite : danoniplus 本体のグローバル関数。
10364
+ *
10365
+ * 使い方:
10366
+ * 【初期化時】
10367
+ * keyconfigKeyboardPreview.init(divRoot);
10368
+ *
10369
+ * 【キー割り当てが変わった時】
10370
+ * keyconfigKeyboardPreview.refresh();
10371
+ * ※ g_keyObj.currentKey / currentPtn から自動取得する
10372
+ *
10373
+ * 【キーコンフィグ画面を離脱する時】
10374
+ * keyconfigKeyboardPreview.dispose();
10375
+ */
10376
+
10377
+ const keyconfigKeyboardPreview = (() => {
10378
+
10379
+ // -------------------------------------------------------------------------
10380
+ // 定数
10381
+ // -------------------------------------------------------------------------
10382
+ const C_PREVIEW_ID = `kbPreviewArea`;
10383
+ const C_BTN_ID = `btnKbPreview`;
10384
+ const C_CANVAS_BASE_ID = `kbCanvasBase`;
10385
+ const C_CANVAS_MAP_ID = `kbCanvasMap`;
10386
+
10387
+ // 色定義(既存ゲームの配色に合わせたダーク系)
10388
+ const C_COLOR = {
10389
+ keyFill: `#1a1a2e`, // 通常キー背景
10390
+ keyStroke: `#555577`, // 通常キー枠
10391
+ keyText: `#ccccdd`, // 通常キー文字
10392
+ keySubText: `#888899`, // サブラベル(Shift面)
10393
+ mappedFill: `#003366`, // メインキー背景
10394
+ mappedStroke: `#4488ff`, // メインキー枠
10395
+ mappedText: `#aaddff`, // メインキー文字
10396
+ altFill: `#3e3e1a`, // 代替キー背景
10397
+ altStroke: `#777755`, // 代替キー枠
10398
+ altText: `#eeeecc`, // 代替キー文字
10399
+ shortcutFill: `#330011`, // ショートカットキー背景
10400
+ shortcutStroke: `#ff4466`, // ショートカットキー枠
10401
+ shortcutText: `#ffaacc`, // ショートカットキー文字
10402
+ bgFill: `#0d0d1a`, // Canvas 背景
10403
+ legendText: `#888899`, // 凡例テキスト
10404
+ };
10405
+
10406
+ // ボタン配置
10407
+ // X・W は init() 内で動的計算(g_btnWidth() 依存)
10408
+ // Y: KeyConfig テキスト上の余白に収まるよう小さく設定
10409
+ const BTN_H = 18; // ボタン高さ
10410
+ const BTN_Y = 3; // divRoot 内 Y 座標
10411
+ const BTN_FS = 11; // ボタンのフォントサイズ(px)
10412
+
10413
+ // プレビューエリア
10414
+ // X: canvas を divRoot 内で水平センタリング(init で動的計算)
10415
+ // Y: g_sHeight に対して垂直センタリング(init で動的計算)
10416
+
10417
+ // 凡例エリアの高さ
10418
+ const LEGEND_H = 25;
10419
+
10420
+ // -------------------------------------------------------------------------
10421
+ // キーレイアウト定義
10422
+ //
10423
+ // 各行: { offsetX, keys }
10424
+ // offsetX : 行左端の水平オフセット(単位: BASE_KEY_W)。全行 0 で統一し、
10425
+ // L)Shift の幅で行頭位置を調整する。
10426
+ // keys : キー定義の配列
10427
+ //
10428
+ // 各キー: { kc, w?, h?, label? }
10429
+ // kc : keyCode(数値)。-1 はスペーサー(描画・キャッシュなし)。
10430
+ // w : 幅倍率(BASE_KEY_W 基準。省略時 1)
10431
+ // h : 高さ倍率(BASE_KEY_H 基準。省略時 1)
10432
+ // label : 省略時は g_kCd[kc] を参照。g_kCd が空文字のキーや
10433
+ // 左右を区別したいキーに指定する。
10434
+ //
10435
+ // 右Shift/Ctrl/Alt は danoniplus 独自コード 256〜258 を使用。
10436
+ // Appli キーは 93 を使用(g_kCd[93] = `Appli`)。
10437
+ // -------------------------------------------------------------------------
10438
+ /**
10439
+ * g_localeObj.val に応じた MAIN_ROWS を生成して返す。
10440
+ * drawBase / calcScale の都度呼び出し、locale 変化を反映する。
10441
+ *
10442
+ * @returns {Array} MAIN_ROWS 相当の配列
10443
+ */
10444
+ const buildMainRows = () => {
10445
+ const isJa = g_localeObj.val === `Ja`;
10446
+ return [
10447
+ // Row0: Fn キー行(JIS/US 共通)
10448
+ {
10449
+ offsetX: 0,
10450
+ keys: [
10451
+ { kc: 27 }, // Esc
10452
+ { kc: -1, w: 0.5 }, // スペーサー
10453
+ { kc: 112 }, { kc: 113 }, { kc: 114 }, { kc: 115 },
10454
+ { kc: -1, w: 0.25 }, // スペーサー
10455
+ { kc: 116 }, { kc: 117 }, { kc: 118 }, { kc: 119 },
10456
+ { kc: -1, w: 0.25 }, // スペーサー
10457
+ { kc: 120 }, { kc: 121 }, { kc: 122 }, { kc: 123 },
10458
+ ],
10459
+ },
10460
+ // Row1: 数字行
10461
+ // JIS: ..., 220(intlYen), BS
10462
+ // US : ..., BS
10463
+ {
10464
+ offsetX: 0,
10465
+ keys: [
10466
+ { kc: 229 },
10467
+ { kc: 49 }, { kc: 50 }, { kc: 51 },
10468
+ { kc: 52 }, { kc: 53 }, { kc: 54 },
10469
+ { kc: 55 }, { kc: 56 }, { kc: 57 },
10470
+ { kc: 48 }, { kc: 189 }, { kc: 222 },
10471
+ ...(isJa
10472
+ ? [{ kc: 220, w: 0.75 }, { kc: 8 }] // JIS: intlYen + BS
10473
+ : [{ kc: 8, w: 1.7 }] // US : BS のみ(広い)
10474
+ ),
10475
+ ],
10476
+ },
10477
+ // Row2: QWERTY
10478
+ // JIS: ..., [, Enter(13)
10479
+ // US : ..., [, ]
10480
+ {
10481
+ offsetX: 0,
10482
+ keys: [
10483
+ { kc: 9, w: 1.5 },
10484
+ { kc: 81 }, { kc: 87 }, { kc: 69 },
10485
+ { kc: 82 }, { kc: 84 }, { kc: 89 },
10486
+ { kc: 85 }, { kc: 73 }, { kc: 79 },
10487
+ { kc: 80 }, { kc: 192 },
10488
+ ...(isJa
10489
+ ? [{ kc: 219 }, { kc: 13, w: 1.25, h: 2 }] // JIS: [, Enter縦長
10490
+ : [{ kc: 219 }, { kc: 221, w: 1.2 }] // US : [, ]
10491
+ ),
10492
+ ],
10493
+ },
10494
+ // Row3: ASDF
10495
+ // JIS: ..., L, ;, ', ¥(221)
10496
+ // US : ..., L, ;, ', Enter(13)
10497
+ {
10498
+ offsetX: 0,
10499
+ keys: [
10500
+ { kc: 20, w: 1.75, label: `CapsLk` },
10501
+ { kc: 65 }, { kc: 83 }, { kc: 68 },
10502
+ { kc: 70 }, { kc: 71 }, { kc: 72 },
10503
+ { kc: 74 }, { kc: 75 }, { kc: 76 },
10504
+ { kc: 187 }, { kc: 186 },
10505
+ ...(isJa
10506
+ ? [{ kc: 221 }] // JIS: ¥
10507
+ : [{ kc: 13, w: 1.9 }] // US : Enter横長
10508
+ ),
10509
+ ],
10510
+ },
10511
+ // Row4: ZXCV
10512
+ // L)Shift の幅で行頭位置を揃える
10513
+ // JIS: L)Shift, ..., intlRo(226), R)Shift
10514
+ // US : L)Shift, ..., R)Shift
10515
+ {
10516
+ offsetX: 0,
10517
+ keys: [
10518
+ { kc: 16, w: 2.25 },
10519
+ { kc: 90 }, { kc: 88 }, { kc: 67 },
10520
+ { kc: 86 }, { kc: 66 }, { kc: 78 },
10521
+ { kc: 77 }, { kc: 188 }, { kc: 190 },
10522
+ { kc: 191 },
10523
+ ...(isJa
10524
+ ? [{ kc: 226 }, { kc: 256, w: 1.5 }] // JIS: intlRo + R)Shift
10525
+ : [{ kc: 256, w: 2.4 }] // US : R)Shift のみ(広い)
10526
+ ),
10527
+ ],
10528
+ },
10529
+ // Row5: スペースバー行
10530
+ // JIS: ..., NoConv(29), Space, Conv(28), カタカナひらがな(242), ...
10531
+ // US : ..., Space, ...
10532
+ {
10533
+ offsetX: 0,
10534
+ keys: [
10535
+ { kc: 17, w: 1.25 },
10536
+ { kc: 91 },
10537
+ { kc: 18 },
10538
+ ...(isJa
10539
+ ? [
10540
+ { kc: 29 },
10541
+ { kc: 32, w: 5.25 },
10542
+ { kc: 28 },
10543
+ { kc: 242 },
10544
+ ]
10545
+ : [
10546
+ { kc: 32, w: 8.25 },
10547
+ ]
10548
+ ),
10549
+ { kc: 258 },
10550
+ { kc: 93 },
10551
+ ...(isJa
10552
+ ? [{ kc: 257, w: 1.2 }]
10553
+ : [{ kc: 257, w: 1.05 }]
10554
+ ),
10555
+ ],
10556
+ },
10557
+ ];
10558
+ };
10559
+ // 編集キークラスター(PrintSc/ScrollLk/Pause/Insert/Delete/Home/End/PgUp/PgDn + 矢印キー)
10560
+ // MAIN_ROWS と行インデックスを揃えて配置する。空行はスキップされる。
10561
+ const NAV_ROWS = [
10562
+ { offsetX: 0, keys: [{ kc: 44, label: `PrintSc` }, { kc: 145, label: `ScrollLk` }, { kc: 19 }] }, // PrintSc ScrollLk Pause
10563
+ { offsetX: 0, keys: [{ kc: 45 }, { kc: 36 }, { kc: 33 }] }, // Insert Home PgUp
10564
+ { offsetX: 0, keys: [{ kc: 46 }, { kc: 35 }, { kc: 34 }] }, // Delete End PgDn
10565
+ { offsetX: 0, keys: [] }, // ASDF行:空
10566
+ { offsetX: 0, keys: [{ kc: -1 }, { kc: 38 }, { kc: -1 }] }, // ↑
10567
+ { offsetX: 0, keys: [{ kc: 37 }, { kc: 40 }, { kc: 39 }] }, // ← ↓ →
10568
+ ];
10569
+
10570
+ // テンキー(MAIN_ROWS と行インデックスを揃えて配置。1行目は空行で Fn行に揃える)
10571
+ // kc は g_kCd 定義に従う: 96〜111=テンキー各種, 144=NumLk
10572
+ // 標準テンキーレイアウト(2行目から):
10573
+ // [NumLk] [T/] [T*] [T-]
10574
+ // [T7][T8][T9] [T+]
10575
+ // [T4][T5][T6] [T+] ← T+ は縦2u
10576
+ // [T1][T2][T3] [TEnter]
10577
+ // [ T0 ][T.] [TEnter] ← T0 は横2u、TEnter は縦2u
10578
+ const NUM_ROWS = [
10579
+ { offsetX: 0, keys: [] },
10580
+ { offsetX: 0, keys: [{ kc: 144 }, { kc: 111 }, { kc: 106 }, { kc: 109 }] }, // NumLk T/ T* T-
10581
+ { offsetX: 0, keys: [{ kc: 103 }, { kc: 104 }, { kc: 105 }, { kc: 107, h: 2 }] }, // T7 T8 T9 T+(縦2u)
10582
+ { offsetX: 0, keys: [{ kc: 100 }, { kc: 101 }, { kc: 102 }] }, // T4 T5 T6
10583
+ { offsetX: 0, keys: [{ kc: 97 }, { kc: 98 }, { kc: 99 }, { kc: 108, h: 2 }] }, // T1 T2 T3 TEnter(縦2u)
10584
+ { offsetX: 0, keys: [{ kc: 96, w: 2 }, { kc: 110 }] }, // T0(横2u) T.
10585
+ ];
10586
+
10587
+ // -------------------------------------------------------------------------
10588
+ // 内部状態
10589
+ // -------------------------------------------------------------------------
10590
+ const _state = {
10591
+ visible: false,
10592
+ mappedSet: new Set(), // メインキー(各矢印の index 0)
10593
+ altSet: new Set(), // 代替キー(各矢印の index 1 以降)
10594
+ shortcutSet: new Set(), // プレイ中ショートカット(keyRetry / keyTitleBack / PgDn / PgUp)
10595
+ canvasBase: null,
10596
+ canvasMap: null,
10597
+ keyRects: [], // { kc, x, y, w, h, label } — drawMap で照合するキャッシュ
10598
+ scale: 1, // BASE_KEY_W/H に掛けるスケール係数
10599
+ cvsW: 500, // 実際の Canvas 幅(スケール計算後)
10600
+ cvsH: 240, // 実際の Canvas 高さ(スケール計算後)
10601
+ };
10602
+
10603
+ // -------------------------------------------------------------------------
10604
+ // スケール計算
10605
+ // -------------------------------------------------------------------------
10606
+
10607
+ /**
10608
+ * g_btnWidth() / g_sHeight を元にスケール係数と Canvas サイズを算出して
10609
+ * _state に書き込む。init 時に呼ぶ。
10610
+ *
10611
+ * 基準サイズ(フルキーボード = メイン + ナビクラスター):
10612
+ * 横: MAIN最大行幅 + ナビ幅(3キー) + 余白
10613
+ * 縦: 6行 × (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP
10614
+ * BASE_KEY_W = BASE_KEY_H = 28px、BASE_KEY_GAP = 3px を基準とする。
10615
+ */
10616
+ const BASE_KEY_W = 28;
10617
+ const BASE_KEY_H = 28;
10618
+ const BASE_KEY_GAP = 3;
10619
+ const MAIN_ROWS_LEN = 6; // MAIN_ROWS の行数(Fn行を含む)
10620
+
10621
+ // 行幅計算(スペーサー含む)
10622
+ const calcRowBaseW = row =>
10623
+ row.keys.reduce((acc, k) => acc + (k.w || 1) * BASE_KEY_W + BASE_KEY_GAP, -BASE_KEY_GAP);
10624
+
10625
+ const BASE_NAV_W = 3 * BASE_KEY_W + 2 * BASE_KEY_GAP; // NAV は 3列固定
10626
+ const BASE_ROW_H = MAIN_ROWS_LEN * (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP; // MAIN+NAV 分の高さ
10627
+ const NUM_ROWS_LEN = 6; // テンキーの行数(1行目は空行、2行目からテンキー配置)
10628
+ const NUM_GAP_H = BASE_KEY_H * 0.4; // テンキー上部の余白(基準キー高の40%)
10629
+ const BASE_NUM_ROW_H = NUM_ROWS_LEN * (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP; // テンキー部の高さ
10630
+ const BASE_NUM_W = 4 * BASE_KEY_W + 3 * BASE_KEY_GAP; // テンキー横幅(4列固定)
10631
+
10632
+ const calcScale = () => {
10633
+ // locale に依存した行幅を毎回計算する
10634
+ const rows = buildMainRows();
10635
+ const baseMainW = Math.max(...rows.map(calcRowBaseW));
10636
+ // 横幅: メイン + NAV + テンキー + 余白
10637
+ const totalW = baseMainW + BASE_KEY_GAP * 2 + BASE_NAV_W + BASE_KEY_GAP * 2
10638
+ + BASE_KEY_GAP * 3 + BASE_NUM_W;
10639
+
10640
+ const availW = g_btnWidth();
10641
+ const availH = g_sHeight - 200 - LEGEND_H; // 下部 UI ぶんを除いた高さ
10642
+
10643
+ // 縦幅基準: MAIN/NAV 高さ と テンキー高さ(余白込み)の大きい方
10644
+ const totalH = Math.max(BASE_ROW_H, BASE_NUM_ROW_H + Math.ceil(NUM_GAP_H));
10645
+
10646
+ const scaleW = availW / totalW;
10647
+ const scaleH = availH / totalH;
10648
+ _state.scale = Math.min(scaleW, scaleH, 1.5); // 最大 1.5 倍まで拡大可
10649
+
10650
+ _state.cvsW = Math.floor(totalW * _state.scale);
10651
+ _state.cvsH = Math.floor(totalH * _state.scale) + LEGEND_H;
10652
+ };
10653
+
10654
+ // -------------------------------------------------------------------------
10655
+ // ラベル取得
10656
+ // -------------------------------------------------------------------------
10657
+
10658
+ /**
10659
+ * keyCode に対応する [primaryLabel, subLabel] を返す。
10660
+ * kc が -1(スペーサー)の場合は [``, ``] を返す。
10661
+ * g_kCd の値は `"primary"` または `"primary sub"` 形式の文字列。
10662
+ *
10663
+ * @param {number} kc
10664
+ * @param {string|undefined} forcedLabel - ROWS の label 指定がある場合に優先
10665
+ * @returns {string[]} [primary, sub]
10666
+ */
10667
+ const getKeyLabels = (kc, forcedLabel) => {
10668
+ if (kc < 0) return [``, ``];
10669
+ if (forcedLabel !== undefined) return [forcedLabel, ``];
10670
+
10671
+ const raw = g_kCd[kc];
10672
+ if (raw && raw !== `- - -` && raw !== `Unknown`) {
10673
+ const parts = raw.split(` `);
10674
+ return [parts[0] || ``, parts[1] || ``];
10675
+ }
10676
+ return [`?`, ``];
10677
+ };
10678
+
10679
+ // -------------------------------------------------------------------------
10680
+ // Canvas ヘルパー
10681
+ // -------------------------------------------------------------------------
10682
+
10683
+ // スケール済みの各寸法を返すヘルパー
10684
+ const kw = w => Math.floor(w * BASE_KEY_W * _state.scale + (w - 1) * BASE_KEY_GAP * _state.scale);
10685
+ const kh = h => Math.floor(h * BASE_KEY_H * _state.scale + (h - 1) * BASE_KEY_GAP * _state.scale);
10686
+ const kg = () => Math.max(1, Math.round(BASE_KEY_GAP * _state.scale));
10687
+ const kr = () => Math.max(2, Math.round(4 * _state.scale));
10688
+
10689
+ const roundRect = (ctx, x, y, w, h, r) => {
10690
+ ctx.beginPath();
10691
+ ctx.moveTo(x + r, y);
10692
+ ctx.lineTo(x + w - r, y);
10693
+ ctx.quadraticCurveTo(x + w, y, x + w, y + r);
10694
+ ctx.lineTo(x + w, y + h - r);
10695
+ ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
10696
+ ctx.lineTo(x + r, y + h);
10697
+ ctx.quadraticCurveTo(x, y + h, x, y + h - r);
10698
+ ctx.lineTo(x, y + r);
10699
+ ctx.quadraticCurveTo(x, y, x + r, y);
10700
+ ctx.closePath();
10701
+ };
10702
+
10703
+ const drawKeyLabel = (ctx, x, y, keyW, keyH, primary, sub, textColor, subColor) => {
10704
+ const fs = primary.length >= 5
10705
+ ? Math.max(6, Math.floor(8 * _state.scale))
10706
+ : Math.max(7, Math.floor(11 * _state.scale));
10707
+
10708
+ if (sub) {
10709
+ ctx.fillStyle = subColor;
10710
+ ctx.font = `bold ${Math.max(6, Math.floor(8 * _state.scale))}px monospace`;
10711
+ ctx.textAlign = `right`;
10712
+ ctx.textBaseline = `top`;
10713
+ ctx.fillText(sub, x + keyW - 2, y + 2);
10714
+ }
10715
+ ctx.fillStyle = textColor;
10716
+ ctx.font = `bold ${fs}px monospace`;
10717
+ ctx.textAlign = `center`;
10718
+ ctx.textBaseline = `middle`;
10719
+ ctx.fillText(primary, x + keyW / 2, y + keyH / 2 + (sub ? 2 : 0));
10720
+ };
10721
+
10722
+ const drawOneKey = (ctx, x, y, keyW, keyH, fill, stroke, lw, primary, sub, textColor, subColor) => {
10723
+ roundRect(ctx, x + 0.5, y + 0.5, keyW - 1, keyH - 1, kr());
10724
+ ctx.fillStyle = fill;
10725
+ ctx.strokeStyle = stroke;
10726
+ ctx.lineWidth = lw;
10727
+ ctx.fill();
10728
+ ctx.stroke();
10729
+ drawKeyLabel(ctx, x, y, keyW, keyH, primary, sub, textColor, subColor);
10730
+ };
10731
+
10732
+ // -------------------------------------------------------------------------
10733
+ // レイアウト計算・描画
10734
+ // -------------------------------------------------------------------------
10735
+
10736
+ /**
10737
+ * rows 配列から各キーの矩形座標を計算し、
10738
+ * canvas に描画しながら keyRects へキャッシュする。
10739
+ *
10740
+ * @param {CanvasRenderingContext2D} ctx
10741
+ * @param {Array} rows - MAIN_ROWS または NAV_ROWS({offsetX, keys} 形式)
10742
+ * @param {number} originX - セクション左端の X 座標(canvas 座標)
10743
+ * @param {number} originY - セクション上端の Y 座標(canvas 座標)
10744
+ */
10745
+ const layoutSection = (ctx, rows, originX, originY) => {
10746
+ const gap = kg();
10747
+ const baseKeyH = kh(1);
10748
+
10749
+ rows.forEach((rowDef, rowIdx) => {
10750
+ if (rowDef.keys.length === 0) return;
10751
+
10752
+ const rowY = originY + rowIdx * (baseKeyH + gap);
10753
+ const startX = originX + Math.floor(rowDef.offsetX * BASE_KEY_W * _state.scale);
10754
+ let curX = startX;
10755
+
10756
+ rowDef.keys.forEach(keyDef => {
10757
+ const keyW = kw(keyDef.w || 1);
10758
+ const keyH = kh(keyDef.h || 1);
10759
+
10760
+ if (keyDef.kc >= 0) {
10761
+ _state.keyRects.push({
10762
+ kc: keyDef.kc,
10763
+ x: curX,
10764
+ y: rowY,
10765
+ w: keyW,
10766
+ h: keyH,
10767
+ label: keyDef.label,
10768
+ });
10769
+ const [primary, sub] = getKeyLabels(keyDef.kc, keyDef.label);
10770
+ drawOneKey(
10771
+ ctx, curX, rowY, keyW, keyH,
10772
+ C_COLOR.keyFill, C_COLOR.keyStroke, 1,
10773
+ primary, sub, C_COLOR.keyText, C_COLOR.keySubText
10774
+ );
10775
+ }
10776
+
10777
+ curX += keyW + gap;
10778
+ });
10779
+ });
10780
+ };
10781
+
10782
+ /**
10783
+ * キーボード背景レイヤーを描画し keyRects をキャッシュする。
10784
+ * init 時に呼ぶ。
10785
+ */
10786
+ const drawBase = () => {
10787
+ const canvas = _state.canvasBase;
10788
+ if (!canvas) return;
10789
+
10790
+ const dpr = window.devicePixelRatio || 1;
10791
+ canvas.style.top = wUnit(40);
10792
+ canvas.width = _state.cvsW * dpr;
10793
+ canvas.height = _state.cvsH * dpr;
10794
+ canvas.style.width = wUnit(_state.cvsW);
10795
+ canvas.style.height = wUnit(_state.cvsH);
10796
+
10797
+ const ctx = canvas.getContext(`2d`);
10798
+ ctx.scale(dpr, dpr);
10799
+ ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
10800
+ ctx.fillStyle = C_COLOR.bgFill;
10801
+ ctx.fillRect(0, 0, _state.cvsW, _state.cvsH);
10802
+
10803
+ _state.keyRects = [];
10804
+
10805
+ const mainRows = buildMainRows();
10806
+ const gap = kg();
10807
+ const baseMainW = Math.max(...mainRows.map(calcRowBaseW));
10808
+ const mainW = Math.floor(baseMainW * _state.scale);
10809
+ const originY = gap;
10810
+ const navOriginX = mainW + gap * 3;
10811
+
10812
+ // テンキー: NAV クラスターの右に gap*3 の余白を空けて配置
10813
+ const numOriginX = navOriginX + Math.floor(BASE_NAV_W * _state.scale) + gap * 3;
10814
+ // テンキーは MAIN 全体に対して縦方向センタリング
10815
+ const numH = Math.floor(BASE_NUM_ROW_H * _state.scale);
10816
+ const mainH = Math.floor(BASE_ROW_H * _state.scale);
10817
+ const numOriginY = originY + Math.floor((mainH - numH) / 2);
10818
+
10819
+ layoutSection(ctx, mainRows, 0, originY);
10820
+ layoutSection(ctx, NAV_ROWS, navOriginX, originY);
10821
+ layoutSection(ctx, NUM_ROWS, numOriginX, numOriginY);
10822
+
10823
+ // 凡例
10824
+ const ly = _state.cvsH - 10;
10825
+ const fnt = `${Math.max(9, Math.floor(10 * _state.scale))}px ${getBasicFont()}`;
10826
+ ctx.font = fnt;
10827
+ ctx.textAlign = `left`;
10828
+ ctx.textBaseline = `middle`;
10829
+
10830
+ const drawLegend = (x, fill, stroke, label) => {
10831
+ roundRect(ctx, x, ly - 5, 10, 10, 2);
10832
+ ctx.fillStyle = fill; ctx.fill();
10833
+ ctx.strokeStyle = stroke; ctx.lineWidth = 1; ctx.stroke();
10834
+ ctx.fillStyle = C_COLOR.legendText;
10835
+ ctx.fillText(label, x + 14, ly);
10836
+
10837
+ return 14 + ctx.measureText(label).width + 14;
10838
+ };
10839
+ let lx = 8;
10840
+ lx += drawLegend(lx, C_COLOR.keyFill, C_COLOR.keyStroke, g_lblNameObj.unallocated);
10841
+ lx += drawLegend(lx, C_COLOR.mappedFill, C_COLOR.mappedStroke, g_lblNameObj.allocated);
10842
+ lx += drawLegend(lx, C_COLOR.altFill, C_COLOR.altStroke, g_lblNameObj.altAllocated);
10843
+ lx += drawLegend(lx, C_COLOR.shortcutFill, C_COLOR.shortcutStroke, g_lblNameObj.shortcutKey);
10844
+ };
10845
+
10846
+ /**
10847
+ * マッピング強調レイヤーを再描画する。
10848
+ * メインキー(mappedSet)を青系、代替キー(altSet)を黄系で色分けする。
10849
+ * 同一キーにメインと代替が重なる場合はメインを優先する。
10850
+ */
10851
+ const drawMap = () => {
10852
+ const canvas = _state.canvasMap;
10853
+ if (!canvas) return;
10854
+
10855
+ const dpr = window.devicePixelRatio || 1;
10856
+ canvas.style.top = wUnit(40);
10857
+ canvas.width = _state.cvsW * dpr;
10858
+ canvas.height = _state.cvsH * dpr;
10859
+ canvas.style.width = wUnit(_state.cvsW);
10860
+ canvas.style.height = wUnit(_state.cvsH);
10861
+
10862
+ const ctx = canvas.getContext(`2d`);
10863
+ ctx.scale(dpr, dpr);
10864
+ ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
10865
+
10866
+ // 優先度: ショートカット > メイン > 代替(後から描くほど優先)
10867
+ const drawKey = (fill, stroke, text) => rect => {
10868
+ const [primary, sub] = getKeyLabels(rect.kc, rect.label);
10869
+ roundRect(ctx, rect.x + 0.5, rect.y + 0.5, rect.w - 1, rect.h - 1, kr());
10870
+ ctx.fillStyle = fill;
10871
+ ctx.strokeStyle = stroke;
10872
+ ctx.lineWidth = 1.5;
10873
+ ctx.fill();
10874
+ ctx.stroke();
10875
+ drawKeyLabel(ctx, rect.x, rect.y, rect.w, rect.h, primary, sub, text, text);
10876
+ };
10877
+
10878
+ // 1. 代替キー(メイン・ショートカットと重複しない場合のみ)
10879
+ _state.keyRects
10880
+ .filter(rect => _state.altSet.has(rect.kc)
10881
+ && !_state.mappedSet.has(rect.kc)
10882
+ && !_state.shortcutSet.has(rect.kc))
10883
+ .forEach(drawKey(C_COLOR.altFill, C_COLOR.altStroke, C_COLOR.altText));
10884
+
10885
+ // 2. メインキー(ショートカットと重複しない場合のみ)
10886
+ _state.keyRects
10887
+ .filter(rect => _state.mappedSet.has(rect.kc) && !_state.shortcutSet.has(rect.kc))
10888
+ .forEach(drawKey(C_COLOR.mappedFill, C_COLOR.mappedStroke, C_COLOR.mappedText));
10889
+
10890
+ // 3. ショートカット(常に最前面)
10891
+ _state.keyRects
10892
+ .filter(rect => _state.shortcutSet.has(rect.kc))
10893
+ .forEach(drawKey(C_COLOR.shortcutFill, C_COLOR.shortcutStroke, C_COLOR.shortcutText));
10894
+ };
10895
+
10896
+ // -------------------------------------------------------------------------
10897
+ // 公開 API
10898
+ // -------------------------------------------------------------------------
10899
+
10900
+ /**
10901
+ * キーボードプレビューを初期化し、ボタンと Canvas コンテナを divRoot に追加する。
10902
+ *
10903
+ * @param {HTMLElement} divRoot - キーコンフィグ画面のルート div
10904
+ */
10905
+ const init = divRoot => {
10906
+ calcScale();
10907
+
10908
+ // ボタン: キャンバス横幅中央に配置、小さいサイズ
10909
+ const btnW = 80;
10910
+ const btnX = Math.floor((g_btnWidth() - btnW) / 2);
10911
+
10912
+ // "↓ Preview" → 展開、"↑ Preview" → 閉じる のトグルボタン
10913
+ const btn = createCss2Button(C_BTN_ID, `↓ Preview`, () => {
10914
+ togglePreview();
10915
+ btn.textContent = _state.visible ? `↑ Preview` : `↓ Preview`;
10916
+ }, {
10917
+ x: btnX, y: BTN_Y, w: btnW, h: BTN_H,
10918
+ title: g_msgObj.kcPreview,
10919
+ }, g_cssObj.button_Setting);
10920
+ btn.style.fontSize = `${BTN_FS}px`;
10921
+ divRoot.appendChild(btn);
10922
+
10923
+ // プレビューエリア: 水平・垂直センタリング
10924
+ const areaX = Math.floor((g_btnWidth() - _state.cvsW) / 2);
10925
+ const areaY = 130;
10926
+
10927
+ const areaDiv = createEmptySprite(divRoot, C_PREVIEW_ID, {
10928
+ x: areaX, y: areaY - 60, w: _state.cvsW, h: _state.cvsH + 80,
10929
+ pointerEvents: C_DIS_AUTO, background: `#00000080`,
10930
+ });
10931
+ areaDiv.style.display = `none`;
10932
+ areaDiv.style.position = `absolute`;
10933
+ areaDiv.style.overflow = `hidden`;
10934
+
10935
+ const canvasBase = document.createElement(`canvas`);
10936
+ canvasBase.id = C_CANVAS_BASE_ID;
10937
+ canvasBase.style.cssText = `position:absolute;left:0;top:0;`;
10938
+ areaDiv.appendChild(canvasBase);
10939
+ _state.canvasBase = canvasBase;
10940
+
10941
+ const canvasMap = document.createElement(`canvas`);
10942
+ canvasMap.id = C_CANVAS_MAP_ID;
10943
+ canvasMap.style.cssText = `position:absolute;left:0;top:0;`;
10944
+ areaDiv.appendChild(canvasMap);
10945
+ _state.canvasMap = canvasMap;
10946
+
10947
+ drawBase();
10948
+ };
10949
+
10950
+ /**
10951
+ * プレビューの表示 / 非表示を切り替える。
10952
+ * 表示するたびにマッピングレイヤーを最新化する。
10953
+ */
10954
+ const togglePreview = () => {
10955
+ const area = document.getElementById(C_PREVIEW_ID);
10956
+ if (!area) return;
10957
+
10958
+ _state.visible = !_state.visible;
10959
+ area.style.display = _state.visible ? `block` : `none`;
10960
+
10961
+ if (_state.visible) refresh();
10962
+ };
10963
+
10964
+ /**
10965
+ * g_keyObj から現在のキー割り当てを取得して mappedSet / altSet を更新し、
10966
+ * プレビューが表示中なら即時再描画する。
10967
+ *
10968
+ * g_keyObj[`keyCtrl${keyCtrlPtn}`] は二次元配列:
10969
+ * [ [矢印0のメインkeyCode, 代替keyCode, ...], [矢印1のメインkeyCode, ...], ... ]
10970
+ * 各サブ配列の index 0 がメインキー、index 1 以降が代替キー。
10971
+ */
10972
+ const refresh = () => {
10973
+ const tkObj = getKeyInfo();
10974
+ const configKeyGroupList = g_headerObj.keyGroupOrder[g_stateObj.scoreId] ??
10975
+ g_keyObj[`keyGroupOrder${tkObj.keyCtrlPtn}`] ?? tkObj.keyGroupList;
10976
+ const ctrl = g_keyObj[`keyCtrl${tkObj.keyCtrlPtn}`]
10977
+ .filter((val, idx) => tkObj.keyGroupMaps[idx].includes(configKeyGroupList[g_keycons.keySwitchNum]));
10978
+
10979
+ _state.mappedSet = new Set(ctrl.map(arr => arr[0]).filter(v => v > 0));
10980
+ _state.altSet = new Set(ctrl.flatMap(arr => arr.slice(1)).filter(v => v > 0));
10981
+ // プレイ中ショートカット: keyRetry / keyTitleBack は g_headerObj から取得、PgDn(34) / PgUp(33) は固定
10982
+ _state.shortcutSet = new Set(
10983
+ [g_headerObj.keyRetry, g_headerObj.keyTitleBack, 34, 33].filter(v => v > 0)
10984
+ );
10985
+ if (_state.visible) drawMap();
10986
+ };
10987
+
10988
+ /**
10989
+ * プレビューを強制非表示にしてリセットする。
10990
+ * キーコンフィグ画面の離脱時に呼ぶ。
10991
+ */
10992
+ const dispose = () => {
10993
+ _state.visible = false;
10994
+ _state.mappedSet = new Set();
10995
+ _state.altSet = new Set();
10996
+ _state.shortcutSet = new Set();
10997
+ _state.keyRects = [];
10998
+ _state.canvasBase = null;
10999
+ _state.canvasMap = null;
11000
+ };
11001
+
11002
+ return { init, refresh, togglePreview, dispose };
11003
+
11004
+ })();
11005
+
10345
11006
  /**
10346
11007
  * 回転できないオブジェクトの場合に設定の自動絞り込みを行う
10347
11008
  */
@@ -12593,7 +13254,7 @@ const getArrowSettings = () => {
12593
13254
  if (g_workObj.stepX_df.length === 0) {
12594
13255
  g_workObj.stepX_df = structuredClone(g_workObj.stepX);
12595
13256
  }
12596
- if (g_stateObj.swapping.endsWith(`Mirror`)) {
13257
+ if (g_settings.swappingSubs.includes(g_stateObj.swapping)) {
12597
13258
 
12598
13259
  // Swappingにおけるグループ単位での入れ替えでは、上下でステップゾーンが分かれている場合は分離してシャッフルする
12599
13260
  let _style = structuredClone(Object.values(g_workObj.shuffleGroupMap));
@@ -12613,11 +13274,11 @@ const getArrowSettings = () => {
12613
13274
  });
12614
13275
  const _styleTransDf = structuredClone(Object.values(_styleTrans));
12615
13276
 
12616
- if (g_stateObj.swapping === `Mirror`) {
13277
+ if (g_stateObj.swapping === `Mirror` || g_stateObj.swapping === `OuterSwap`) {
12617
13278
  _styleTrans.map(_group => _group.reverse());
12618
-
12619
- } else if (g_stateObj.swapping === `X-Mirror`) {
12620
- // X-Mirrorの場合、グループの内側だけ入れ替える
13279
+ }
13280
+ if (g_stateObj.swapping.endsWith(`Swap`)) {
13281
+ // グループの内側だけ入れ替える
12621
13282
  _styleTrans.forEach((group, i) => {
12622
13283
  g_settings.swapPattern.forEach(val => {
12623
13284
  swapGroupNums(_styleTrans, group, i, val);
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2026/05/09 (v47.5.3)
8
+ * Revised : 2026/05/13 (v47.6.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -1396,9 +1396,11 @@ const g_settings = {
1396
1396
  camoufrageTypes: [C_FLG_HYPHEN, `FrzArrow`],
1397
1397
  camoufrageTypeNum: 0,
1398
1398
 
1399
- swappings: [C_FLG_OFF, `Mirror`, `X-Mirror`, `Mirror+`],
1399
+ swappings: [C_FLG_OFF, `InnerSwap`, `OuterSwap`, `Mirror`, `Mirror+`],
1400
1400
  swappingNum: 0,
1401
1401
 
1402
+ swappingSubs: [`InnerSwap`, `OuterSwap`, `Mirror`],
1403
+
1402
1404
  judgRanges: [`Normal`, `Narrow`, `Hard`, `ExHard`],
1403
1405
  judgRangeNum: 0,
1404
1406
 
@@ -2292,6 +2294,7 @@ for (let j = 0; j < 260; j++) {
2292
2294
  // キーボード配列の言語設定
2293
2295
  const g_lang_kCd = {
2294
2296
  Ja: {
2297
+ 13: `Enter`,
2295
2298
  48: `0`,
2296
2299
  49: `1`,
2297
2300
  50: `2`,
@@ -2317,6 +2320,7 @@ const g_lang_kCd = {
2317
2320
  229: `IME`,
2318
2321
  },
2319
2322
  En: {
2323
+ 13: `Return`,
2320
2324
  48: `0 )`,
2321
2325
  49: `1 !`,
2322
2326
  50: `2 @`,
@@ -2433,6 +2437,7 @@ g_kCd[134] = `FN`;
2433
2437
  g_kCd[144] = `NumLk`;
2434
2438
  g_kCd[145] = `SL`;
2435
2439
  g_kCd[240] = `CapsLk`;
2440
+ g_kCd[242] = `Kana`;
2436
2441
  g_kCd[256] = `R)Shift`;
2437
2442
  g_kCd[257] = `R)Ctrl`;
2438
2443
  g_kCd[258] = `R)Alt`;
@@ -2552,6 +2557,7 @@ g_kCdN[222] = `Equal`;
2552
2557
  g_kCdN[226] = `IntlRo`;
2553
2558
  g_kCdN[229] = `Backquote`;
2554
2559
  g_kCdN[240] = `CapsLock`;
2560
+ g_kCdN[242] = `KanaMode`;
2555
2561
  g_kCdN[256] = `ShiftRight`;
2556
2562
  g_kCdN[257] = `ControlRight`;
2557
2563
  g_kCdN[258] = `AltRight`;
@@ -4554,6 +4560,8 @@ const g_lblNameObj = {
4554
4560
  'u_Random+': `Random+`,
4555
4561
  'u_S-Random': `S-Random`,
4556
4562
  'u_S-Random+': `S-Random+`,
4563
+ 'u_InnerSwap': `InnerSwap`,
4564
+ 'u_OuterSwap': `OuterSwap`,
4557
4565
  'u_Mirror+': `Mirror+`,
4558
4566
  'u_(S)': `(S)`,
4559
4567
 
@@ -4732,6 +4740,11 @@ const g_lang_lblNameObj = {
4732
4740
  'u_±120deg': `±120°`,
4733
4741
  'u_±360deg': `±360°`,
4734
4742
 
4743
+ unallocated: `未割当`,
4744
+ allocated: `割当済`,
4745
+ altAllocated: `代替キー`,
4746
+ shortcutKey: `ショートカットキー`,
4747
+
4735
4748
  j_ii: "(・∀・)イイ!!",
4736
4749
  j_shakin: "(`・ω・)シャキン",
4737
4750
  j_matari: "( ´∀`)マターリ",
@@ -4783,6 +4796,11 @@ const g_lang_lblNameObj = {
4783
4796
  'u_±120deg': `±120deg`,
4784
4797
  'u_±360deg': `±360deg`,
4785
4798
 
4799
+ unallocated: `Unallocated`,
4800
+ allocated: `Allocated`,
4801
+ altAllocated: `Alternate Keys`,
4802
+ shortcutKey: `Shortcut Keys`,
4803
+
4786
4804
  j_ii: ":D Perfect!!",
4787
4805
  j_shakin: ":) Great!",
4788
4806
  j_matari: ":| Good",
@@ -4884,7 +4902,8 @@ const g_lang_msgObj = {
4884
4902
  effect: `矢印・フリーズアローにエフェクトをかけます。\n[Dizzy/Spin] 矢印が回転します\n[Wave/Storm] 矢印の軌道が左右に揺れます\n[Blinking] 矢印が点滅します\n[Squids] 矢印が伸び縮みします`,
4885
4903
  camoufrage: `ステップの見た目が配置は同じでランダムに変わります。`,
4886
4904
  camoufrageType: `[FrzArrow] フリーズアローの帯部分を初期表示のみ非表示にし、矢印のみで表示します(ヒット/失敗時は帯を再表示)`,
4887
- swapping: `ステップゾーンの位置を入れ替える設定です。\n[Mirror] ステップゾーンの位置をグループ単位で入れ替えます。\n[X-Mirror] ステップゾーンの中央部分のみグループ単位で入れ替えます。\n[Mirror+] ステップゾーンの位置をグループに関係なく全体的に反転します。`,
4905
+ swapping: `ステップゾーンの位置を入れ替える設定です。\n[InnerSwap] ステップゾーンの中央部分のみグループ単位で入れ替えます。\n[OuterSwap] InnerSwapの逆側(外側)をグループ単位で入れ替えます。\n` +
4906
+ `[Mirror] ステップゾーンの位置をグループ単位で入れ替えます。\n[Mirror+] ステップゾーンの位置をグループに関係なく全体的に反転します。`,
4888
4907
  judgRange: `判定の許容範囲を設定します。\n[Normal] 通常、[Narrow/Hard] 辛判定、[ExHard] 激辛判定`,
4889
4908
  autoRetry: `自動リトライの条件を設定します。\n[Miss] ミス時、[Matari] マターリ時、[Shakin] シャキン時、[FS] Fast/Slow発生時`,
4890
4909
 
@@ -4907,6 +4926,7 @@ const g_lang_msgObj = {
4907
4926
  shuffleGroup: `Mirror/X-Mirror/Turning/Random/S-Random選択時、シャッフルするグループを変更します。\n矢印の上にある同じ数字同士でシャッフルします。`,
4908
4927
  stepRtnGroup: `矢印などノーツの種類、回転に関するパターンを切り替えます。\nあらかじめ設定されている場合のみ変更可能です。`,
4909
4928
  kcReset: `対応するキーの割り当てを元に戻します。`,
4929
+ kcPreview: `キーボードレイアウトのプレビューを表示/非表示します。`,
4910
4930
 
4911
4931
  pickArrow: `色番号ごとの矢印色(枠、塗りつぶし)、通常時のフリーズアロー色(枠、帯)を\nカラーピッカーから選んで変更できます。`,
4912
4932
  pickColorR: `設定する矢印色の種類を切り替えます。`,
@@ -4986,7 +5006,8 @@ const g_lang_msgObj = {
4986
5006
  effect: `Applies effects to the arrows and freeze arrows.\n[Dizzy/Spin] Arrows rotate.\n[Wave/Storm] Swing from left to right.\n[Blinking] Arrows blink.\n[Squids] Arrows stretch and shrink.`,
4987
5007
  camoufrage: `The appearance of the steps changes randomly with the same placement.`,
4988
5008
  camoufrageType: `[FrzArrow] Initially hides freeze-arrow bars and displays only the arrow portion (bars reappear on hit/failure)`,
4989
- swapping: `This setting allows you to swap the positions of the step zones.\n[Mirror] Swaps the positions of step zones within each shuffle group. \n[X-Mirror] Swaps only the central portion of step zones within each shuffle group.\n[Mirror+] Flips the position of all step zones, regardless of shuffle groups. `,
5009
+ swapping: `This setting allows you to swap the positions of the step zones.\n[InnerSwap] Swaps only the inner portion of step zones within each shuffle group.\n[OuterSwap] Swaps the outer portion (inverse of InnerSwap) within each shuffle group.\n` +
5010
+ `[Mirror] Swaps the positions of step zones within each shuffle group. \n[Mirror+] Flips the position of all step zones, regardless of shuffle groups. `,
4990
5011
  judgRange: `Set the allowable range of judgment.\n[Normal] Normal judgment, [Narrow/Hard] Hard judgment, [ExHard] Very hard judgment`,
4991
5012
  autoRetry: `Set the conditions for automatic retry.\n[Miss] When missed, [Matari] When good, [Shakin] When great, [FS] When Fast/Slow occurs`,
4992
5013
 
@@ -5009,6 +5030,7 @@ const g_lang_msgObj = {
5009
5030
  shuffleGroup: `Change the shuffle group when Mirror, X-Mirror, Turning, Random or S-Random are selected.\nShuffle with the same numbers listed above.`,
5010
5031
  stepRtnGroup: `Switches the type of notes, such as arrows, and the pattern regarding rotation.\nThis can only be changed if it has been set in advance.`,
5011
5032
  kcReset: `Restores the corresponding key assignments.`,
5033
+ kcPreview: `Show/hide the preview of the keyboard layout.`,
5012
5034
 
5013
5035
  pickArrow: `Change the frame or fill of arrow color and the frame or bar of normal freeze-arrow color\nfor each color number from the color picker.`,
5014
5036
  pickColorR: `Switches the arrow color type to be set.`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "47.5.3",
3
+ "version": "47.6.1",
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",