danoniplus 47.6.0 → 47.6.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.
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/12
7
+ * Revised : 2026/05/14
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 47.6.0`;
12
- const g_revisedDate = `2026/05/12`;
11
+ const g_version = `Ver 47.6.2`;
12
+ const g_revisedDate = `2026/05/14`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -88,6 +88,7 @@ const g_remoteDomain = detectDomain(g_rootPath);
88
88
 
89
89
  const g_randTime = Date.now();
90
90
  const g_versionForUrl = g_version.slice(4); // URL用に先頭の"Ver "を削除
91
+ const g_dpr = window.devicePixelRatio || 1;
91
92
 
92
93
  const g_isFile = location.href.match(/^file/);
93
94
  const g_isLocal = location.href.match(/^file/) || location.href.indexOf(`localhost`) !== -1;
@@ -3380,7 +3381,6 @@ const storeBaseData = (_scoreId, _scoreObj, _keyCtrlPtn) => {
3380
3381
  _keyCtrlPtn,
3381
3382
  config: {
3382
3383
  scale: 1.5,
3383
- dpr: window.devicePixelRatio || 1,
3384
3384
  timeMargin: 35,
3385
3385
  mmWidthBase: (g_sWidth - 500) / 2 + 290,
3386
3386
  mmMarginY: 2,
@@ -3389,7 +3389,7 @@ const storeBaseData = (_scoreId, _scoreObj, _keyCtrlPtn) => {
3389
3389
  },
3390
3390
  get logicalWidth() {
3391
3391
  const logicalWidth = this.timeMargin + (this.laneWidth * keyNum);
3392
- return Math.ceil(logicalWidth * this.dpr) / this.dpr;
3392
+ return Math.ceil(logicalWidth * g_dpr) / g_dpr;
3393
3393
  }
3394
3394
  },
3395
3395
  };
@@ -3403,16 +3403,15 @@ const storeBaseData = (_scoreId, _scoreObj, _keyCtrlPtn) => {
3403
3403
  * 指定された高さに基づいて分割されたCanvasリストを生成する
3404
3404
  * @param {number} _width
3405
3405
  * @param {number} _totalHeight
3406
- * @param {number} _dpr
3407
3406
  * @return {object[]} 分割されたCanvasとそのコンテキスト、オフセット情報を含むリスト
3408
3407
  */
3409
- const createSplitCanvases = (_width, _totalHeight, _dpr) => {
3408
+ const createSplitCanvases = (_width, _totalHeight) => {
3410
3409
  // バックバッファ(実際のピクセル数)の最大値を 8000 に設定(iOS Safari 8192px 対策)
3411
3410
  const BACKING_STORE_LIMIT = 8000;
3412
3411
 
3413
3412
  // 論理上の最大高さ(CSSピクセル)を計算
3414
- // dpr=2なら4000px、dpr=3なら2666px が1枚の限界になる
3415
- const maxLogicalHeight = Math.max(1, Math.floor(BACKING_STORE_LIMIT / _dpr));
3413
+ // g_dpr=2なら4000px、g_dpr=3なら2666px が1枚の限界になる
3414
+ const maxLogicalHeight = Math.max(1, Math.floor(BACKING_STORE_LIMIT / g_dpr));
3416
3415
  if (_totalHeight <= 0) return [];
3417
3416
 
3418
3417
  const count = Math.ceil(_totalHeight / maxLogicalHeight);
@@ -3426,8 +3425,8 @@ const createSplitCanvases = (_width, _totalHeight, _dpr) => {
3426
3425
  : maxLogicalHeight;
3427
3426
 
3428
3427
  // 実際の描画解像度をセット
3429
- cvs.width = _width * _dpr;
3430
- cvs.height = logicalH * _dpr;
3428
+ cvs.width = _width * g_dpr;
3429
+ cvs.height = logicalH * g_dpr;
3431
3430
 
3432
3431
  // ブラウザ上の表示サイズをセット
3433
3432
  cvs.style.width = `${_width}px`;
@@ -3435,7 +3434,7 @@ const createSplitCanvases = (_width, _totalHeight, _dpr) => {
3435
3434
  cvs.style.display = 'block';
3436
3435
 
3437
3436
  const ctx = cvs.getContext('2d');
3438
- ctx.scale(_dpr, _dpr);
3437
+ ctx.scale(g_dpr, g_dpr);
3439
3438
 
3440
3439
  list.push({
3441
3440
  canvas: cvs,
@@ -3474,7 +3473,6 @@ const distributeDrawing = (_canvases, _y, _h, _dpr, _drawFunc) => {
3474
3473
  /**
3475
3474
  * 譜面ミニマップ:キー名を表示するヘッダーキャンバスを作成する
3476
3475
  * @param {object} _config ミニマップの基本設定
3477
- * @param {number} _config.dpr デバイスピクセル比
3478
3476
  * @param {number} _config.timeMargin 時間軸のマージン
3479
3477
  * @param {number} _config.laneWidth レーンの幅
3480
3478
  * @param {number} _config.logicalWidth キャンバスの論理幅
@@ -3483,20 +3481,20 @@ const distributeDrawing = (_canvases, _y, _h, _dpr, _drawFunc) => {
3483
3481
  * @return {HTMLCanvasElement} ヘッダー用のキャンバス要素
3484
3482
  */
3485
3483
  const createMinimapHeader = (_config, _keyCtrlPtn, _keyNum) => {
3486
- const { dpr, timeMargin, laneWidth, logicalWidth } = _config;
3484
+ const { timeMargin, laneWidth, logicalWidth } = _config;
3487
3485
  const headerHeight = 15; // ヘッダーの固定高
3488
3486
 
3489
3487
  const canvas = document.createElement('canvas');
3490
3488
  const ctx = canvas.getContext('2d');
3491
3489
 
3492
3490
  // 解像度と表示サイズの設定
3493
- canvas.width = logicalWidth * dpr;
3494
- canvas.height = headerHeight * dpr;
3491
+ canvas.width = logicalWidth * g_dpr;
3492
+ canvas.height = headerHeight * g_dpr;
3495
3493
  canvas.style.width = `${logicalWidth}px`;
3496
3494
  canvas.style.height = `${headerHeight}px`;
3497
3495
  canvas.style.display = 'block';
3498
3496
 
3499
- ctx.scale(dpr, dpr);
3497
+ ctx.scale(g_dpr, g_dpr);
3500
3498
 
3501
3499
  // テキストのスタイル設定
3502
3500
  ctx.fillStyle = '#999';
@@ -3526,7 +3524,6 @@ const createMinimapHeader = (_config, _keyCtrlPtn, _keyNum) => {
3526
3524
  * @param {string} _params._keyCtrlPtn キーコントロールパターン
3527
3525
  * @param {object} _params.config ミニマップの基本設定
3528
3526
  * @param {number} _params.config.scale ミニマップの時間軸のスケール
3529
- * @param {number} _params.config.dpr デバイスピクセル比
3530
3527
  * @param {number} _params.config.timeMargin 時間軸のマージン
3531
3528
  * @param {number} _params.config.laneWidth レーンの幅
3532
3529
  * @param {number} _params.config.logicalWidth キャンバスの論理幅
@@ -3536,10 +3533,10 @@ const createMinimapHeader = (_config, _keyCtrlPtn, _keyNum) => {
3536
3533
  */
3537
3534
  const generateMinimapData = (_params, _isReverse) => {
3538
3535
  const { _scoreObj, _keyNum, _playingFrame, _firstArrowFrame, _keyCtrlPtn, config } = _params;
3539
- const { scale, dpr, timeMargin, laneWidth, logicalWidth, mmMarginY } = config;
3536
+ const { scale, timeMargin, laneWidth, logicalWidth, mmMarginY } = config;
3540
3537
 
3541
3538
  const mmHeightTotal = _playingFrame * scale + mmMarginY * 2;
3542
- const canvases = createSplitCanvases(logicalWidth, mmHeightTotal, dpr);
3539
+ const canvases = createSplitCanvases(logicalWidth, mmHeightTotal);
3543
3540
 
3544
3541
  const getY = (frame) => {
3545
3542
  const relativeFrame = frame - _firstArrowFrame;
@@ -3554,7 +3551,7 @@ const generateMinimapData = (_params, _isReverse) => {
3554
3551
  const interval = g_fps;
3555
3552
  for (let f = Math.ceil(_firstArrowFrame / interval) * interval; f <= _firstArrowFrame + _playingFrame; f += interval) {
3556
3553
  const y = getY(f);
3557
- distributeDrawing(canvases, y - 5, 10, dpr, (ctx) => {
3554
+ distributeDrawing(canvases, y - 5, 10, g_dpr, (ctx) => {
3558
3555
  ctx.strokeStyle = '#444';
3559
3556
  ctx.fillStyle = '#999';
3560
3557
  ctx.font = `10px ${getBasicFont()}`;
@@ -3583,7 +3580,7 @@ const generateMinimapData = (_params, _isReverse) => {
3583
3580
  const top = Math.min(y1, y2);
3584
3581
  const h = Math.abs(y2 - y1);
3585
3582
  const x = timeMargin + j * laneWidth;
3586
- distributeDrawing(canvases, top, h, dpr, (ctx) => {
3583
+ distributeDrawing(canvases, top, h, g_dpr, (ctx) => {
3587
3584
  ctx.fillStyle = 'rgba(0, 200, 255, 0.4)';
3588
3585
  ctx.fillRect(x + 2, top, laneWidth - 3, h);
3589
3586
  ctx.strokeStyle = 'rgba(0, 200, 255, 0.8)';
@@ -3597,7 +3594,7 @@ const generateMinimapData = (_params, _isReverse) => {
3597
3594
  const color = g_dfColorObj.setColorType2[g_keyObj[`color${_keyCtrlPtn}_0`][j]] || '#ffffff';
3598
3595
  _scoreObj.arrowData[j].forEach(note => {
3599
3596
  const y = getY(parseFloat(note));
3600
- distributeDrawing(canvases, y - 1.5, 3, dpr, (ctx) => {
3597
+ distributeDrawing(canvases, y - 1.5, 3, g_dpr, (ctx) => {
3601
3598
  ctx.fillStyle = color;
3602
3599
  ctx.fillRect(timeMargin + j * laneWidth + 1, y - 1.5, laneWidth - 1, 3);
3603
3600
  });
@@ -8239,9 +8236,8 @@ const createOptionWindow = _sprite => {
8239
8236
  const bkColor = window.getComputedStyle(textBaseObj, ``).backgroundColor;
8240
8237
 
8241
8238
  graphObj.id = `graph${_name}${j > 0 ? j + 1 : ``}`;
8242
- const dpr = window.devicePixelRatio || 1;
8243
- graphObj.width = g_limitObj.graphWidth * dpr;
8244
- graphObj.height = g_limitObj.graphHeight * dpr;
8239
+ graphObj.width = g_limitObj.graphWidth * g_dpr;
8240
+ graphObj.height = g_limitObj.graphHeight * g_dpr;
8245
8241
  graphObj.style.width = wUnit(g_limitObj.graphWidth);
8246
8242
  graphObj.style.height = wUnit(g_limitObj.graphHeight);
8247
8243
  graphObj.style.left = wUnit(125);
@@ -8249,7 +8245,7 @@ const createOptionWindow = _sprite => {
8249
8245
  graphObj.style.position = `absolute`;
8250
8246
  graphObj.style.background = j === 0 ? bkColor : `#ffffff00`;
8251
8247
  const ctx = graphObj.getContext(`2d`);
8252
- ctx.scale(dpr, dpr);
8248
+ ctx.scale(g_dpr, g_dpr);
8253
8249
 
8254
8250
  detailObj.appendChild(graphObj);
8255
8251
  }
@@ -10396,8 +10392,11 @@ const keyconfigKeyboardPreview = (() => {
10396
10392
  altFill: `#3e3e1a`, // 代替キー背景
10397
10393
  altStroke: `#777755`, // 代替キー枠
10398
10394
  altText: `#eeeecc`, // 代替キー文字
10395
+ shortcutFill: `#330011`, // ショートカットキー背景
10396
+ shortcutStroke: `#ff4466`, // ショートカットキー枠
10397
+ shortcutText: `#ffaacc`, // ショートカットキー文字
10399
10398
  bgFill: `#0d0d1a`, // Canvas 背景
10400
- legendText: `#888899`, // 凡例テキスト
10399
+ legendText: `#cccccc`, // 凡例テキスト
10401
10400
  };
10402
10401
 
10403
10402
  // ボタン配置
@@ -10418,35 +10417,20 @@ const keyconfigKeyboardPreview = (() => {
10418
10417
  // キーレイアウト定義
10419
10418
  //
10420
10419
  // 各行: { offsetX, keys }
10421
- // offsetX : 行左端の水平オフセット(単位: BASE_KEY_W)。正の値 = 右にずらす。
10420
+ // offsetX : 行左端の水平オフセット(単位: BASE_KEY_W)。全行 0 で統一し、
10421
+ // L)Shift の幅で行頭位置を調整する。
10422
10422
  // keys : キー定義の配列
10423
10423
  //
10424
- // 各キー: { kc, w, h?, label? }
10424
+ // 各キー: { kc, w?, h?, label? }
10425
10425
  // kc : keyCode(数値)。-1 はスペーサー(描画・キャッシュなし)。
10426
10426
  // w : 幅倍率(BASE_KEY_W 基準。省略時 1)
10427
- // h : 高さ倍率(省略時 1)
10427
+ // h : 高さ倍率(BASE_KEY_H 基準。省略時 1)
10428
10428
  // label : 省略時は g_kCd[kc] を参照。g_kCd が空文字のキーや
10429
10429
  // 左右を区別したいキーに指定する。
10430
10430
  //
10431
10431
  // 右Shift/Ctrl/Alt は danoniplus 独自コード 256〜258 を使用。
10432
+ // Appli キーは 93 を使用(g_kCd[93] = `Appli`)。
10432
10433
  // -------------------------------------------------------------------------
10433
-
10434
- // メインキーボード部(Fn行 + 数字行 + QWERTY + ASDF + ZXCV + スペース行)
10435
- //
10436
- // 各行の offsetX 設計(1u = BASE_KEY_W):
10437
- // Fn行 0u Esc が左端
10438
- // 数字行 0u 229(IME/`) が左端
10439
- // QWERTY 0u Tab(1.5u) が左端、左端位置は数字行と揃う
10440
- // ASDF 0u CapsLk を 2.25u にして L)Shift 左端と揃える
10441
- // ZXCV 0.25u 標準キーボードの行オフセットを offsetX + L)Shift 拡大で再現
10442
- // スペース行 0u
10443
- //
10444
- // JIS と US の主な違い:
10445
- // 数字行: JIS は intlYen(220) あり、US はなし(BackSpace が広い)
10446
- // QWERTY: JIS は [ の右にスペーサー、US はなし(Enter が横長)
10447
- // ASDF : JIS は ¥(221) あり、US はなし(Enter が横長)
10448
- // ZXCV : JIS は intlRo(226) あり、US はなし(R)Shift が広い)
10449
- // Enter : JIS は縦長(h=2)、US は横長(h=1, w=2.25)
10450
10434
  /**
10451
10435
  * g_localeObj.val に応じた MAIN_ROWS を生成して返す。
10452
10436
  * drawBase / calcScale の都度呼び出し、locale 変化を反映する。
@@ -10460,18 +10444,18 @@ const keyconfigKeyboardPreview = (() => {
10460
10444
  {
10461
10445
  offsetX: 0,
10462
10446
  keys: [
10463
- { kc: 27 }, // Esc
10464
- { kc: -1, w: 0.5 }, // スペーサー
10447
+ { kc: 27 }, // Esc
10448
+ { kc: -1, w: 0.5 }, // スペーサー
10465
10449
  { kc: 112 }, { kc: 113 }, { kc: 114 }, { kc: 115 },
10466
- { kc: -1, w: 0.25 }, // スペーサー
10450
+ { kc: -1, w: 0.25 }, // スペーサー
10467
10451
  { kc: 116 }, { kc: 117 }, { kc: 118 }, { kc: 119 },
10468
- { kc: -1, w: 0.25 }, // スペーサー
10452
+ { kc: -1, w: 0.25 }, // スペーサー
10469
10453
  { kc: 120 }, { kc: 121 }, { kc: 122 }, { kc: 123 },
10470
10454
  ],
10471
10455
  },
10472
10456
  // Row1: 数字行
10473
- // JIS: ..., 222, 220(intlYen, 0.75u), BS(1.5u)
10474
- // US : ..., 222, BS(2.25u)
10457
+ // JIS: ..., 220(intlYen), BS
10458
+ // US : ..., BS
10475
10459
  {
10476
10460
  offsetX: 0,
10477
10461
  keys: [
@@ -10481,13 +10465,13 @@ const keyconfigKeyboardPreview = (() => {
10481
10465
  { kc: 55 }, { kc: 56 }, { kc: 57 },
10482
10466
  { kc: 48 }, { kc: 189 }, { kc: 222 },
10483
10467
  ...(isJa
10484
- ? [{ kc: 220, w: 0.75 }, { kc: 8, w: 1.5 }] // JIS: intlYen + BS
10485
- : [{ kc: 8, w: 2.25 }] // US : BS のみ(広い)
10468
+ ? [{ kc: 220, w: 0.75 }, { kc: 8, label: `Back\nSpace` }] // JIS: intlYen + BS
10469
+ : [{ kc: 8, w: 1.7 }] // US : BS のみ(広い)
10486
10470
  ),
10487
10471
  ],
10488
10472
  },
10489
10473
  // Row2: QWERTY
10490
- // JIS: ..., [, スペーサー(0.5u), Enter(縦長 h=2, w=1.25)
10474
+ // JIS: ..., [, Enter(13)
10491
10475
  // US : ..., [, ]
10492
10476
  {
10493
10477
  offsetX: 0,
@@ -10498,46 +10482,49 @@ const keyconfigKeyboardPreview = (() => {
10498
10482
  { kc: 85 }, { kc: 73 }, { kc: 79 },
10499
10483
  { kc: 80 }, { kc: 192 },
10500
10484
  ...(isJa
10501
- ? [{ kc: 219 }, { kc: -1, w: 0.5 }, { kc: 13, w: 1.25, h: 2 }] // JIS: [, スペーサー, Enter縦長
10502
- : [{ kc: 219 }, { kc: 221 }] // US : [, ]
10485
+ ? [{ kc: 219 }, { kc: 13, w: 1.25, h: 2 }] // JIS: [, Enter縦長
10486
+ : [{ kc: 219 }, { kc: 221, w: 1.2 }] // US : [, ]
10503
10487
  ),
10504
10488
  ],
10505
10489
  },
10506
10490
  // Row3: ASDF
10507
10491
  // JIS: ..., L, ;, ', ¥(221)
10508
- // US : ..., L, ;, ' ¥なし(Enter が下まで伸びる縦長分を吸収)
10492
+ // US : ..., L, ;, ', Enter(13)
10509
10493
  {
10510
10494
  offsetX: 0,
10511
10495
  keys: [
10512
- { kc: 20, w: 2.25, label: `CapsLk` },
10496
+ { kc: 20, w: 1.75, label: `CapsLk` },
10513
10497
  { kc: 65 }, { kc: 83 }, { kc: 68 },
10514
10498
  { kc: 70 }, { kc: 71 }, { kc: 72 },
10515
10499
  { kc: 74 }, { kc: 75 }, { kc: 76 },
10516
10500
  { kc: 187 }, { kc: 186 },
10517
10501
  ...(isJa
10518
- ? [{ kc: 221 }] // JIS: ¥
10519
- : [{ kc: 13, w: 2.25 }] // US : Enter横長
10502
+ ? [{ kc: 221 }] // JIS: ¥
10503
+ : [{ kc: 13, w: 1.9 }] // US : Enter横長
10520
10504
  ),
10521
10505
  ],
10522
10506
  },
10523
- // Row4: ZXCV(標準配列は ASDF より約 0.25u 右にオフセット)
10524
- // JIS: ..., /, intlRo(226), R)Shift(1.25u)
10525
- // US : ..., /, R)Shift(2.5u)
10507
+ // Row4: ZXCV
10508
+ // L)Shift の幅で行頭位置を揃える
10509
+ // JIS: L)Shift, ..., intlRo(226), R)Shift
10510
+ // US : L)Shift, ..., R)Shift
10526
10511
  {
10527
- offsetX: 0.25,
10512
+ offsetX: 0,
10528
10513
  keys: [
10529
- { kc: 16, w: 2.5 },
10514
+ { kc: 16, w: 2.25 },
10530
10515
  { kc: 90 }, { kc: 88 }, { kc: 67 },
10531
10516
  { kc: 86 }, { kc: 66 }, { kc: 78 },
10532
10517
  { kc: 77 }, { kc: 188 }, { kc: 190 },
10533
10518
  { kc: 191 },
10534
10519
  ...(isJa
10535
- ? [{ kc: 226 }, { kc: 256, w: 1.25 }] // JIS: intlRo + R)Shift
10536
- : [{ kc: 256, w: 2.5 }] // US : R)Shift のみ(広い)
10520
+ ? [{ kc: 226 }, { kc: 256, w: 1.5 }] // JIS: intlRo + R)Shift
10521
+ : [{ kc: 256, w: 2.4 }] // US : R)Shift のみ(広い)
10537
10522
  ),
10538
10523
  ],
10539
10524
  },
10540
- // Row5: スペースバー行(JIS/US 共通)
10525
+ // Row5: スペースバー行
10526
+ // JIS: ..., NoConv(29), Space, Conv(28), カタカナひらがな(242), ...
10527
+ // US : ..., Space, ...
10541
10528
  {
10542
10529
  offsetX: 0,
10543
10530
  keys: [
@@ -10556,38 +10543,41 @@ const keyconfigKeyboardPreview = (() => {
10556
10543
  ]
10557
10544
  ),
10558
10545
  { kc: 258 },
10559
- { kc: 91 },
10560
- { kc: 257, w: 1.25 },
10546
+ { kc: 93 },
10547
+ ...(isJa
10548
+ ? [{ kc: 257, w: 1.2 }]
10549
+ : [{ kc: 257, w: 1.05 }]
10550
+ ),
10561
10551
  ],
10562
10552
  },
10563
10553
  ];
10564
10554
  };
10565
- // 編集キークラスター(Insert/Delete/Home/End/PgUp/PgDn + 矢印キー)
10555
+ // 編集キークラスター(PrintSc/ScrollLk/Pause/Insert/Delete/Home/End/PgUp/PgDn + 矢印キー)
10566
10556
  // MAIN_ROWS と行インデックスを揃えて配置する。空行はスキップされる。
10567
10557
  const NAV_ROWS = [
10568
10558
  { offsetX: 0, keys: [{ kc: 44, label: `PrintSc` }, { kc: 145, label: `ScrollLk` }, { kc: 19 }] }, // PrintSc ScrollLk Pause
10569
10559
  { offsetX: 0, keys: [{ kc: 45 }, { kc: 36 }, { kc: 33 }] }, // Insert Home PgUp
10570
10560
  { offsetX: 0, keys: [{ kc: 46 }, { kc: 35 }, { kc: 34 }] }, // Delete End PgDn
10571
- { offsetX: 0, keys: [] }, // ASDF行:空
10561
+ { offsetX: 0, keys: [] }, // ASDF行:空
10572
10562
  { offsetX: 0, keys: [{ kc: -1 }, { kc: 38 }, { kc: -1 }] }, // ↑
10573
10563
  { offsetX: 0, keys: [{ kc: 37 }, { kc: 40 }, { kc: 39 }] }, // ← ↓ →
10574
10564
  ];
10575
10565
 
10576
- // テンキー(Space行の下に余白を空けて横に羅列)
10566
+ // テンキー(MAIN_ROWS と行インデックスを揃えて配置。1行目は空行で Fn行に揃える)
10577
10567
  // kc は g_kCd 定義に従う: 96〜111=テンキー各種, 144=NumLk
10578
- // 標準テンキーレイアウト:
10568
+ // 標準テンキーレイアウト(2行目から):
10579
10569
  // [NumLk] [T/] [T*] [T-]
10580
10570
  // [T7][T8][T9] [T+]
10581
10571
  // [T4][T5][T6] [T+] ← T+ は縦2u
10582
10572
  // [T1][T2][T3] [TEnter]
10583
- // [ T0 ][T_] [TEnter] ← T0 は横2u、TEnter は縦2u
10573
+ // [ T0 ][T.] [TEnter] ← T0 は横2u、TEnter は縦2u
10584
10574
  const NUM_ROWS = [
10585
10575
  { offsetX: 0, keys: [] },
10586
- { offsetX: 0, keys: [{ kc: 144 }, { kc: 111 }, { kc: 106 }, { kc: 109 }] }, // NumLk T/ T* T-
10576
+ { offsetX: 0, keys: [{ kc: 144 }, { kc: 111 }, { kc: 106 }, { kc: 109 }] }, // NumLk T/ T* T-
10587
10577
  { offsetX: 0, keys: [{ kc: 103 }, { kc: 104 }, { kc: 105 }, { kc: 107, h: 2 }] }, // T7 T8 T9 T+(縦2u)
10588
- { offsetX: 0, keys: [{ kc: 100 }, { kc: 101 }, { kc: 102 }] }, // T4 T5 T6
10589
- { offsetX: 0, keys: [{ kc: 97 }, { kc: 98 }, { kc: 99 }, { kc: 108, h: 2 }] }, // T1 T2 T3 TEnter(縦2u)
10590
- { offsetX: 0, keys: [{ kc: 96, w: 2 }, { kc: 110 }] }, // T0(横2u) T.
10578
+ { offsetX: 0, keys: [{ kc: 100 }, { kc: 101 }, { kc: 102 }] }, // T4 T5 T6
10579
+ { offsetX: 0, keys: [{ kc: 97 }, { kc: 98 }, { kc: 99 }, { kc: 108, h: 2 }] }, // T1 T2 T3 TEnter(縦2u)
10580
+ { offsetX: 0, keys: [{ kc: 96, w: 2 }, { kc: 110 }] }, // T0(横2u) T.
10591
10581
  ];
10592
10582
 
10593
10583
  // -------------------------------------------------------------------------
@@ -10595,14 +10585,15 @@ const keyconfigKeyboardPreview = (() => {
10595
10585
  // -------------------------------------------------------------------------
10596
10586
  const _state = {
10597
10587
  visible: false,
10598
- mappedSet: new Set(), // メインキー(各矢印の index 0)
10599
- altSet: new Set(), // 代替キー(各矢印の index 1 以降)
10588
+ mappedSet: new Set(), // メインキー(各矢印の index 0)
10589
+ altSet: new Set(), // 代替キー(各矢印の index 1 以降)
10590
+ shortcutSet: new Set(), // プレイ中ショートカット(keyRetry / keyTitleBack / PgDn / PgUp)
10600
10591
  canvasBase: null,
10601
10592
  canvasMap: null,
10602
- keyRects: [], // { kc, x, y, w, h, label } — drawMap で照合するキャッシュ
10603
- scale: 1, // BASE_KEY_W/H に掛けるスケール係数
10604
- cvsW: 500, // 実際の Canvas 幅(スケール計算後)
10605
- cvsH: 240, // 実際の Canvas 高さ(スケール計算後)
10593
+ keyRects: [], // { kc, x, y, w, h, label } — drawMap で照合するキャッシュ
10594
+ scale: 1, // BASE_KEY_W/H に掛けるスケール係数
10595
+ cvsW: 500, // 実際の Canvas 幅(スケール計算後)
10596
+ cvsH: 240, // 実際の Canvas 高さ(スケール計算後)
10606
10597
  };
10607
10598
 
10608
10599
  // -------------------------------------------------------------------------
@@ -10629,7 +10620,7 @@ const keyconfigKeyboardPreview = (() => {
10629
10620
 
10630
10621
  const BASE_NAV_W = 3 * BASE_KEY_W + 2 * BASE_KEY_GAP; // NAV は 3列固定
10631
10622
  const BASE_ROW_H = MAIN_ROWS_LEN * (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP; // MAIN+NAV 分の高さ
10632
- const NUM_ROWS_LEN = 6; // テンキーの行数
10623
+ const NUM_ROWS_LEN = 6; // テンキーの行数(1行目は空行、2行目からテンキー配置)
10633
10624
  const NUM_GAP_H = BASE_KEY_H * 0.4; // テンキー上部の余白(基準キー高の40%)
10634
10625
  const BASE_NUM_ROW_H = NUM_ROWS_LEN * (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP; // テンキー部の高さ
10635
10626
  const BASE_NUM_W = 4 * BASE_KEY_W + 3 * BASE_KEY_GAP; // テンキー横幅(4列固定)
@@ -10674,7 +10665,7 @@ const keyconfigKeyboardPreview = (() => {
10674
10665
  if (forcedLabel !== undefined) return [forcedLabel, ``];
10675
10666
 
10676
10667
  const raw = g_kCd[kc];
10677
- if (raw && raw !== `- - -` && raw !== `Unknown`) {
10668
+ if (raw && raw !== g_kCd[0] && raw !== g_kCd[1]) {
10678
10669
  const parts = raw.split(` `);
10679
10670
  return [parts[0] || ``, parts[1] || ``];
10680
10671
  }
@@ -10706,22 +10697,31 @@ const keyconfigKeyboardPreview = (() => {
10706
10697
  };
10707
10698
 
10708
10699
  const drawKeyLabel = (ctx, x, y, keyW, keyH, primary, sub, textColor, subColor) => {
10709
- const fs = primary.length >= 5
10710
- ? Math.max(6, Math.floor(8 * _state.scale))
10700
+ const fs = (_textLen) => _textLen >= 5 * keyW / BASE_KEY_W
10701
+ ? Math.max(6, Math.floor(9 * _state.scale))
10711
10702
  : Math.max(7, Math.floor(11 * _state.scale));
10712
10703
 
10713
10704
  if (sub) {
10714
10705
  ctx.fillStyle = subColor;
10715
- ctx.font = `bold ${Math.max(6, Math.floor(8 * _state.scale))}px monospace`;
10706
+ ctx.font = `bold ${Math.max(6, Math.floor(9 * _state.scale))}px monospace`;
10716
10707
  ctx.textAlign = `right`;
10717
10708
  ctx.textBaseline = `top`;
10718
10709
  ctx.fillText(sub, x + keyW - 2, y + 2);
10719
10710
  }
10711
+ const [primary1, primary2] = primary.split(`\n`);
10720
10712
  ctx.fillStyle = textColor;
10721
- ctx.font = `bold ${fs}px monospace`;
10722
10713
  ctx.textAlign = `center`;
10723
10714
  ctx.textBaseline = `middle`;
10724
- ctx.fillText(primary, x + keyW / 2, y + keyH / 2 + (sub ? 2 : 0));
10715
+ const subDiff = sub ? 2 : 0;
10716
+ if (primary2) {
10717
+ const siz = fs(Math.max(primary1.length, primary2.length));
10718
+ ctx.font = `bold ${siz}px monospace`;
10719
+ ctx.fillText(primary1, x + keyW / 2, y + keyH / 2 - siz / 2 + subDiff);
10720
+ ctx.fillText(primary2, x + keyW / 2, y + keyH / 2 + siz / 2 + subDiff);
10721
+ } else {
10722
+ ctx.font = `bold ${fs(primary.length)}px monospace`;
10723
+ ctx.fillText(primary, x + keyW / 2, y + keyH / 2 + subDiff);
10724
+ }
10725
10725
  };
10726
10726
 
10727
10727
  const drawOneKey = (ctx, x, y, keyW, keyH, fill, stroke, lw, primary, sub, textColor, subColor) => {
@@ -10792,15 +10792,14 @@ const keyconfigKeyboardPreview = (() => {
10792
10792
  const canvas = _state.canvasBase;
10793
10793
  if (!canvas) return;
10794
10794
 
10795
- const dpr = window.devicePixelRatio || 1;
10796
10795
  canvas.style.top = wUnit(40);
10797
- canvas.width = _state.cvsW * dpr;
10798
- canvas.height = _state.cvsH * dpr;
10796
+ canvas.width = _state.cvsW * g_dpr;
10797
+ canvas.height = _state.cvsH * g_dpr;
10799
10798
  canvas.style.width = wUnit(_state.cvsW);
10800
10799
  canvas.style.height = wUnit(_state.cvsH);
10801
10800
 
10802
10801
  const ctx = canvas.getContext(`2d`);
10803
- ctx.scale(dpr, dpr);
10802
+ ctx.scale(g_dpr, g_dpr);
10804
10803
  ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
10805
10804
  ctx.fillStyle = C_COLOR.bgFill;
10806
10805
  ctx.fillRect(0, 0, _state.cvsW, _state.cvsH);
@@ -10827,22 +10826,25 @@ const keyconfigKeyboardPreview = (() => {
10827
10826
 
10828
10827
  // 凡例
10829
10828
  const ly = _state.cvsH - 10;
10830
- const fnt = `${Math.max(9, Math.floor(10 * _state.scale))}px ${getBasicFont()}`;
10829
+ const fnt = `${Math.max(9, Math.floor(12 * _state.scale))}px ${getBasicFont()}`;
10831
10830
  ctx.font = fnt;
10832
10831
  ctx.textAlign = `left`;
10833
10832
  ctx.textBaseline = `middle`;
10834
10833
 
10835
10834
  const drawLegend = (x, fill, stroke, label) => {
10836
- roundRect(ctx, x, ly, 10, 10, 2);
10835
+ roundRect(ctx, x, ly - 5, 10, 10, 2);
10837
10836
  ctx.fillStyle = fill; ctx.fill();
10838
10837
  ctx.strokeStyle = stroke; ctx.lineWidth = 1; ctx.stroke();
10839
10838
  ctx.fillStyle = C_COLOR.legendText;
10840
- ctx.fillText(label, x + 14, ly + 5);
10841
- };
10839
+ ctx.fillText(label, x + 14, ly);
10842
10840
 
10843
- drawLegend(8, C_COLOR.keyFill, C_COLOR.keyStroke, g_lblNameObj.unallocated);
10844
- drawLegend(95, C_COLOR.mappedFill, C_COLOR.mappedStroke, g_lblNameObj.allocated);
10845
- drawLegend(182, C_COLOR.altFill, C_COLOR.altStroke, g_lblNameObj.altAllocated);
10841
+ return 14 + ctx.measureText(label).width + 14;
10842
+ };
10843
+ let lx = 8;
10844
+ lx += drawLegend(lx, C_COLOR.keyFill, C_COLOR.keyStroke, g_lblNameObj.unallocated);
10845
+ lx += drawLegend(lx, C_COLOR.mappedFill, C_COLOR.mappedStroke, g_lblNameObj.allocated);
10846
+ lx += drawLegend(lx, C_COLOR.altFill, C_COLOR.altStroke, g_lblNameObj.altAllocated);
10847
+ lx += drawLegend(lx, C_COLOR.shortcutFill, C_COLOR.shortcutStroke, g_lblNameObj.shortcutKey);
10846
10848
  };
10847
10849
 
10848
10850
  /**
@@ -10854,18 +10856,17 @@ const keyconfigKeyboardPreview = (() => {
10854
10856
  const canvas = _state.canvasMap;
10855
10857
  if (!canvas) return;
10856
10858
 
10857
- const dpr = window.devicePixelRatio || 1;
10858
10859
  canvas.style.top = wUnit(40);
10859
- canvas.width = _state.cvsW * dpr;
10860
- canvas.height = _state.cvsH * dpr;
10860
+ canvas.width = _state.cvsW * g_dpr;
10861
+ canvas.height = _state.cvsH * g_dpr;
10861
10862
  canvas.style.width = wUnit(_state.cvsW);
10862
10863
  canvas.style.height = wUnit(_state.cvsH);
10863
10864
 
10864
10865
  const ctx = canvas.getContext(`2d`);
10865
- ctx.scale(dpr, dpr);
10866
+ ctx.scale(g_dpr, g_dpr);
10866
10867
  ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
10867
10868
 
10868
- // 代替キーを先に描画し、メインキーで上書きすることで優先度を表現
10869
+ // 優先度: ショートカット > メイン > 代替(後から描くほど優先)
10869
10870
  const drawKey = (fill, stroke, text) => rect => {
10870
10871
  const [primary, sub] = getKeyLabels(rect.kc, rect.label);
10871
10872
  roundRect(ctx, rect.x + 0.5, rect.y + 0.5, rect.w - 1, rect.h - 1, kr());
@@ -10877,13 +10878,22 @@ const keyconfigKeyboardPreview = (() => {
10877
10878
  drawKeyLabel(ctx, rect.x, rect.y, rect.w, rect.h, primary, sub, text, text);
10878
10879
  };
10879
10880
 
10881
+ // 1. 代替キー(メイン・ショートカットと重複しない場合のみ)
10880
10882
  _state.keyRects
10881
- .filter(rect => _state.altSet.has(rect.kc) && !_state.mappedSet.has(rect.kc))
10883
+ .filter(rect => _state.altSet.has(rect.kc)
10884
+ && !_state.mappedSet.has(rect.kc)
10885
+ && !_state.shortcutSet.has(rect.kc))
10882
10886
  .forEach(drawKey(C_COLOR.altFill, C_COLOR.altStroke, C_COLOR.altText));
10883
10887
 
10888
+ // 2. メインキー(ショートカットと重複しない場合のみ)
10884
10889
  _state.keyRects
10885
- .filter(rect => _state.mappedSet.has(rect.kc))
10890
+ .filter(rect => _state.mappedSet.has(rect.kc) && !_state.shortcutSet.has(rect.kc))
10886
10891
  .forEach(drawKey(C_COLOR.mappedFill, C_COLOR.mappedStroke, C_COLOR.mappedText));
10892
+
10893
+ // 3. ショートカット(常に最前面)
10894
+ _state.keyRects
10895
+ .filter(rect => _state.shortcutSet.has(rect.kc))
10896
+ .forEach(drawKey(C_COLOR.shortcutFill, C_COLOR.shortcutStroke, C_COLOR.shortcutText));
10887
10897
  };
10888
10898
 
10889
10899
  // -------------------------------------------------------------------------
@@ -10971,6 +10981,10 @@ const keyconfigKeyboardPreview = (() => {
10971
10981
 
10972
10982
  _state.mappedSet = new Set(ctrl.map(arr => arr[0]).filter(v => v > 0));
10973
10983
  _state.altSet = new Set(ctrl.flatMap(arr => arr.slice(1)).filter(v => v > 0));
10984
+ // プレイ中ショートカット: keyRetry / keyTitleBack は g_headerObj から取得、PgDn(34) / PgUp(33) は固定
10985
+ _state.shortcutSet = new Set(
10986
+ [g_headerObj.keyRetry, g_headerObj.keyTitleBack, 34, 33].filter(v => v > 0)
10987
+ );
10974
10988
  if (_state.visible) drawMap();
10975
10989
  };
10976
10990
 
@@ -10982,6 +10996,7 @@ const keyconfigKeyboardPreview = (() => {
10982
10996
  _state.visible = false;
10983
10997
  _state.mappedSet = new Set();
10984
10998
  _state.altSet = new Set();
10999
+ _state.shortcutSet = new Set();
10985
11000
  _state.keyRects = [];
10986
11001
  _state.canvasBase = null;
10987
11002
  _state.canvasMap = null;
@@ -16135,12 +16150,11 @@ const resultInit = () => {
16135
16150
  for (let j = 0; j < 2; j++) {
16136
16151
  const canvas = document.createElement(`canvas`);
16137
16152
  canvas.id = `graphGaugeTransition${j > 0 ? j + 1 : ``}`;
16138
- const dpr = window.devicePixelRatio || 1;
16139
- canvas.width = g_limitObj.gaugeTransitionWidth * dpr;
16140
- canvas.height = g_limitObj.gaugeTransitionHeight * dpr;
16153
+ canvas.width = g_limitObj.gaugeTransitionWidth * g_dpr;
16154
+ canvas.height = g_limitObj.gaugeTransitionHeight * g_dpr;
16141
16155
  canvas.style.width = wUnit(g_limitObj.gaugeTransitionWidth);
16142
16156
  canvas.style.height = wUnit(g_limitObj.gaugeTransitionHeight);
16143
- canvas.getContext(`2d`).scale(dpr, dpr);
16157
+ canvas.getContext(`2d`).scale(g_dpr, g_dpr);
16144
16158
  canvas.style.left = wUnit(0);
16145
16159
  canvas.style.top = wUnit(0);
16146
16160
  canvas.style.position = `absolute`;
@@ -16451,13 +16465,12 @@ const resultInit = () => {
16451
16465
  tmpDiv.style.background = `#000000cc`;
16452
16466
  const canvas = document.createElement(`canvas`);
16453
16467
  const artistName = g_headerObj.artistNames[g_headerObj.musicNos[g_stateObj.scoreId]] || g_headerObj.artistName;
16454
- const dpr = window.devicePixelRatio || 1;
16455
16468
  const logicalWidth = 400;
16456
16469
  const logicalHeight = g_sHeight - 90;
16457
16470
 
16458
16471
  canvas.id = `resultImage`;
16459
- canvas.width = logicalWidth * dpr;
16460
- canvas.height = logicalHeight * dpr;
16472
+ canvas.width = logicalWidth * g_dpr;
16473
+ canvas.height = logicalHeight * g_dpr;
16461
16474
  canvas.style.width = wUnit(logicalWidth);
16462
16475
  canvas.style.height = wUnit(logicalHeight);
16463
16476
  canvas.style.left = wUnit((g_sWidth - parseFloat(canvas.style.width)) / 2);
@@ -16465,7 +16478,7 @@ const resultInit = () => {
16465
16478
  canvas.style.position = `absolute`;
16466
16479
 
16467
16480
  const context = canvas.getContext(`2d`);
16468
- context.scale(dpr, dpr);
16481
+ context.scale(g_dpr, g_dpr);
16469
16482
  const drawText = (_text, { x = 30, dy = 0, hy, siz = 15, color = `#cccccc`, align = C_ALIGN_LEFT, font } = {}) => {
16470
16483
  context.font = `${wUnit(siz)} ${getBasicFont(font)}`;
16471
16484
  context.fillStyle = color;
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2026/05/12 (v47.6.0)
8
+ * Revised : 2026/05/13 (v47.6.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -4743,6 +4743,7 @@ const g_lang_lblNameObj = {
4743
4743
  unallocated: `未割当`,
4744
4744
  allocated: `割当済`,
4745
4745
  altAllocated: `代替キー`,
4746
+ shortcutKey: `ショートカットキー`,
4746
4747
 
4747
4748
  j_ii: "(・∀・)イイ!!",
4748
4749
  j_shakin: "(`・ω・)シャキン",
@@ -4798,6 +4799,7 @@ const g_lang_lblNameObj = {
4798
4799
  unallocated: `Unallocated`,
4799
4800
  allocated: `Allocated`,
4800
4801
  altAllocated: `Alternate Keys`,
4802
+ shortcutKey: `Shortcut Keys`,
4801
4803
 
4802
4804
  j_ii: ":D Perfect!!",
4803
4805
  j_shakin: ":) Great!",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "47.6.0",
3
+ "version": "47.6.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",