danoniplus 48.5.2 → 49.1.0
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 +242 -64
- package/js/lib/danoni_constants.js +21 -6
- 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/
|
|
7
|
+
* Revised : 2026/07/02
|
|
8
8
|
*
|
|
9
9
|
* https://github.com/cwtickle/danoniplus
|
|
10
10
|
*/
|
|
11
|
-
const g_version = `Ver
|
|
12
|
-
const g_revisedDate = `2026/
|
|
11
|
+
const g_version = `Ver 49.1.0`;
|
|
12
|
+
const g_revisedDate = `2026/07/02`;
|
|
13
13
|
|
|
14
14
|
// カスタム用バージョン (danoni_custom.js 等で指定可)
|
|
15
15
|
let g_localVersion = ``;
|
|
@@ -1492,6 +1492,53 @@ const getEmojiForCanvas = _str => {
|
|
|
1492
1492
|
return result;
|
|
1493
1493
|
};
|
|
1494
1494
|
|
|
1495
|
+
/**
|
|
1496
|
+
* 複数行に跨る可能性のある文字列を、改行タグ付きの文字列とフォントサイズに変換
|
|
1497
|
+
* @param {string} _targetStr
|
|
1498
|
+
* @param {number} _maxWidth
|
|
1499
|
+
* @param {object} object
|
|
1500
|
+
* @param {string} [object.font=getBasicFont()]
|
|
1501
|
+
* @param {number} [object.maxSiz=14]
|
|
1502
|
+
* @param {number} [object.minSiz=5]
|
|
1503
|
+
* @param {number} [object.maxSizMulti=maxSiz]
|
|
1504
|
+
* @param {string} [object.prefix='']
|
|
1505
|
+
* @param {number} [object.len=30]
|
|
1506
|
+
* @param {string} [object.delim=' ']
|
|
1507
|
+
* @returns {[string, number]}
|
|
1508
|
+
*/
|
|
1509
|
+
const getFontSizeMulti = (_targetStr, _maxWidth, { font = getBasicFont(),
|
|
1510
|
+
maxSiz = 14, minSiz = 5, maxSizMulti = maxSiz, prefix = ``, len = 20, delim = ` ` } = {}) => {
|
|
1511
|
+
|
|
1512
|
+
// _targetStr が長い場合のみ、その中身を 2つ に分解する
|
|
1513
|
+
if (_targetStr.length > len) {
|
|
1514
|
+
let breakNum = -1;
|
|
1515
|
+
const halfIndex = Math.floor(_targetStr.length / 2);
|
|
1516
|
+
|
|
1517
|
+
// 文字列の中央から前に向かってスペースを探す
|
|
1518
|
+
for (let j = halfIndex; j > 0; j--) {
|
|
1519
|
+
if (_targetStr[j] === delim) {
|
|
1520
|
+
breakNum = j;
|
|
1521
|
+
break;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
// スペースがなければ、中央(よりやや左)で強制分割
|
|
1525
|
+
if (breakNum === -1) {
|
|
1526
|
+
breakNum = halfIndex;
|
|
1527
|
+
}
|
|
1528
|
+
const isSpace = _targetStr[breakNum] === delim;
|
|
1529
|
+
const firstPart = _targetStr.slice(0, breakNum);
|
|
1530
|
+
const secondPart = _targetStr.slice(isSpace ? breakNum + delim.length : breakNum);
|
|
1531
|
+
|
|
1532
|
+
// 難易度名の中に <br> を仕込む
|
|
1533
|
+
_targetStr = `${firstPart}<br>${secondPart}`;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// 3. 最終的な文字列を結合(prefix と難易度名の1つ目の塊が1行目になる)
|
|
1537
|
+
const fullStr = `${prefix}${_targetStr}`;
|
|
1538
|
+
|
|
1539
|
+
return [fullStr, getFontSize2(fullStr, _maxWidth, { font, maxSiz: _targetStr.includes(`<br>`) ? maxSizMulti : maxSiz, minSiz })];
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1495
1542
|
/**
|
|
1496
1543
|
* 指定した横幅に合ったフォントサイズを取得
|
|
1497
1544
|
* @param {string} _str
|
|
@@ -1502,8 +1549,16 @@ const getEmojiForCanvas = _str => {
|
|
|
1502
1549
|
* @returns {number}
|
|
1503
1550
|
*/
|
|
1504
1551
|
const getFontSize2 = (_str, _maxWidth, { font = getBasicFont(), maxSiz = 14, minSiz = 5 } = {}) => {
|
|
1552
|
+
// 文字列を改行で分割(null/undefined 対策も含む)
|
|
1553
|
+
const lines = _str ? _str.split('<br>') : [];
|
|
1554
|
+
if (lines.length === 0) return maxSiz;
|
|
1555
|
+
|
|
1556
|
+
// 大きいサイズから順に試す
|
|
1505
1557
|
for (let siz = maxSiz; siz >= minSiz; siz--) {
|
|
1506
|
-
|
|
1558
|
+
// すべての行が _maxWidth 以内に収まるかチェック
|
|
1559
|
+
const isFitAllLines = lines.every(line => _maxWidth >= getStrWidth(line, siz, font));
|
|
1560
|
+
|
|
1561
|
+
if (isFitAllLines) {
|
|
1507
1562
|
return siz;
|
|
1508
1563
|
}
|
|
1509
1564
|
}
|
|
@@ -2459,7 +2514,7 @@ const drawTitleResultMotion = _displayName =>
|
|
|
2459
2514
|
// WebAudioAPIでAudio要素風に再生するクラス
|
|
2460
2515
|
class AudioPlayer {
|
|
2461
2516
|
constructor() {
|
|
2462
|
-
this._context =
|
|
2517
|
+
this._context = getSharedAudioContext();
|
|
2463
2518
|
this._gain = this._context.createGain();
|
|
2464
2519
|
this._gain.connect(this._context.destination);
|
|
2465
2520
|
this._startTime = 0;
|
|
@@ -2507,11 +2562,8 @@ class AudioPlayer {
|
|
|
2507
2562
|
}
|
|
2508
2563
|
|
|
2509
2564
|
close() {
|
|
2510
|
-
if (this._context) {
|
|
2511
|
-
this._context.close()?.catch(() => {/* ignore double-close */ });
|
|
2512
|
-
this._buffer = null;
|
|
2513
|
-
}
|
|
2514
2565
|
if (this._source) {
|
|
2566
|
+
this._source.stop(0);
|
|
2515
2567
|
this._source.disconnect(this._gain);
|
|
2516
2568
|
this._source = null;
|
|
2517
2569
|
}
|
|
@@ -2586,10 +2638,33 @@ class AudioPlayer {
|
|
|
2586
2638
|
this._eventListeners[_type] = this._eventListeners[_type].filter(_element => _element !== _listener);
|
|
2587
2639
|
}
|
|
2588
2640
|
|
|
2641
|
+
getBuffer() {
|
|
2642
|
+
return this._buffer;
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
setBuffer(_buffer) {
|
|
2646
|
+
this._buffer = _buffer;
|
|
2647
|
+
this._duration = _buffer.duration;
|
|
2648
|
+
this._eventListeners[`canplaythrough`]?.forEach(_listener => _listener());
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2589
2651
|
load() { }
|
|
2590
2652
|
dispatchEvent() { }
|
|
2591
2653
|
}
|
|
2592
2654
|
|
|
2655
|
+
// グローバルで1つだけ保持(遅延生成)
|
|
2656
|
+
let g_sharedAudioContext = null;
|
|
2657
|
+
const getSharedAudioContext = () => {
|
|
2658
|
+
if (!g_sharedAudioContext) {
|
|
2659
|
+
g_sharedAudioContext = new AudioContext();
|
|
2660
|
+
}
|
|
2661
|
+
// タブのバックグラウンド化等でsuspendedになることがあるため念のためresume
|
|
2662
|
+
if (g_sharedAudioContext.state === `suspended`) {
|
|
2663
|
+
g_sharedAudioContext.resume();
|
|
2664
|
+
}
|
|
2665
|
+
return g_sharedAudioContext;
|
|
2666
|
+
};
|
|
2667
|
+
|
|
2593
2668
|
/**
|
|
2594
2669
|
* クリップボードコピー関数
|
|
2595
2670
|
* 入力値をクリップボードへコピーし、メッセージを表示
|
|
@@ -6315,23 +6390,22 @@ const playBGM = async (_num, _currentLoopNum = g_settings.musicLoopNum) => {
|
|
|
6315
6390
|
|
|
6316
6391
|
if (encodeFlg) {
|
|
6317
6392
|
try {
|
|
6318
|
-
|
|
6319
|
-
if (
|
|
6320
|
-
|
|
6393
|
+
closeExistingAudio();
|
|
6394
|
+
if (g_audioBufferCache.has(url)) {
|
|
6395
|
+
const tmpAudio = new AudioPlayer();
|
|
6396
|
+
tmpAudio.setBuffer(g_audioBufferCache.get(url)); // 新設メソッド、decode不要
|
|
6397
|
+
g_audioForMS = tmpAudio;
|
|
6398
|
+
} else {
|
|
6321
6399
|
await loadScript2(url);
|
|
6322
6400
|
musicInit();
|
|
6323
|
-
if (!isTitle()) {
|
|
6324
|
-
|
|
6325
|
-
return;
|
|
6326
|
-
}
|
|
6401
|
+
if (!isTitle()) { g_musicdata = ``; return; }
|
|
6402
|
+
|
|
6327
6403
|
const tmpAudio = new AudioPlayer();
|
|
6328
|
-
const array =
|
|
6404
|
+
const array = base64ToUint8Array(g_musicdata);
|
|
6329
6405
|
await tmpAudio.init(array.buffer);
|
|
6330
|
-
if (!isTitle()) {
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
return;
|
|
6334
|
-
}
|
|
6406
|
+
if (!isTitle()) { g_musicdata = ``; tmpAudio.close(); return; }
|
|
6407
|
+
|
|
6408
|
+
cacheAudioBuffer(url, tmpAudio.getBuffer());
|
|
6335
6409
|
g_audioForMS = tmpAudio;
|
|
6336
6410
|
}
|
|
6337
6411
|
g_audioForMS.volume = g_stateObj.bgmVolume / 100;
|
|
@@ -7179,12 +7253,21 @@ const makeDifList = (_difList, _targetKey = ``) => {
|
|
|
7179
7253
|
g_headerObj.viewLists.forEach(j => {
|
|
7180
7254
|
const keyLabel = g_headerObj.keyLabels[j];
|
|
7181
7255
|
if (_targetKey === `` || keyLabel === _targetKey) {
|
|
7182
|
-
|
|
7256
|
+
|
|
7257
|
+
// 譜面名の表示
|
|
7258
|
+
const prefix = `${getKeyName(keyLabel)} / `;
|
|
7259
|
+
let text = `${g_headerObj.difLabels[j]}`;
|
|
7183
7260
|
if (g_headerObj.makerView) {
|
|
7184
7261
|
text += ` (${g_headerObj.creatorNames[j]})`;
|
|
7185
7262
|
}
|
|
7186
|
-
|
|
7187
|
-
|
|
7263
|
+
// キー種と譜面名に分割し、譜面名が長すぎる場合は二段に分割して表示
|
|
7264
|
+
const [difText, difSiz] = getFontSizeMulti(text, g_limitObj.difSelectorWidth, {
|
|
7265
|
+
maxSiz: g_limitObj.difSelectorSiz, maxSizMulti: 9, prefix, len: 30,
|
|
7266
|
+
})
|
|
7267
|
+
_difList.appendChild(makeDifLblCssButton(`dif${k}`, difText, k, () => nextDifficulty(j - g_stateObj.scoreId), {
|
|
7268
|
+
btnStyle: (j === g_stateObj.scoreId ? `Setting` : `Default`), siz: difSiz,
|
|
7269
|
+
}));
|
|
7270
|
+
document.getElementById(`dif${k}`).style.lineHeight = `9px`;
|
|
7188
7271
|
if (j === g_stateObj.scoreId) {
|
|
7189
7272
|
pos = k + 6.5 * (g_sHeight - 239) / 261;
|
|
7190
7273
|
curk = k;
|
|
@@ -8136,9 +8219,14 @@ const setDifficulty = (_initFlg) => {
|
|
|
8136
8219
|
const difWidth = parseFloat(lnkDifficulty.style.width) - 20;
|
|
8137
8220
|
const transKeyName = getTransKeyName();
|
|
8138
8221
|
const keyUnitName = getStgDetailName(getKeyUnitName(g_keyObj.currentKey));
|
|
8139
|
-
const difNames = [`${getKeyName(g_keyObj.currentKey)}${transKeyName} ${keyUnitName} / ${g_headerObj.difLabels[g_stateObj.scoreId]}`];
|
|
8140
|
-
lnkDifficulty.style.fontSize = wUnit(getFontSize2(difNames[0], difWidth, { maxSiz: g_limitObj.setLblSiz }));
|
|
8141
8222
|
|
|
8223
|
+
const prefix = `${getKeyName(g_keyObj.currentKey)}${transKeyName} ${keyUnitName} / `;
|
|
8224
|
+
let difLabel = `${g_headerObj.difLabels[g_stateObj.scoreId]}`;
|
|
8225
|
+
|
|
8226
|
+
const [difName, difSiz] = getFontSizeMulti(difLabel, difWidth, { maxSiz: g_limitObj.setLblSiz, prefix });
|
|
8227
|
+
lnkDifficulty.style.fontSize = wUnit(difSiz);
|
|
8228
|
+
|
|
8229
|
+
const difNames = [difName];
|
|
8142
8230
|
if (g_headerObj.makerView) {
|
|
8143
8231
|
difNames.push(`(${g_headerObj.creatorNames[g_stateObj.scoreId]})`);
|
|
8144
8232
|
difNames.forEach((difName, j) => {
|
|
@@ -8998,6 +9086,9 @@ const setExcessive = (_btn, _val) => {
|
|
|
8998
9086
|
const getKeyCtrl = (_localStorage, _extraKeyName = ``) => {
|
|
8999
9087
|
g_keyObj.storagePtn = _localStorage[`keyCtrlPtn${_extraKeyName}`];
|
|
9000
9088
|
const basePtn = `${g_keyObj.currentKey}_${g_keyObj.storagePtn}`;
|
|
9089
|
+
if (g_keyObj[`keyCtrl${basePtn}`] === undefined || hasVal(g_keyObj[`transKey${basePtn}`])) {
|
|
9090
|
+
return;
|
|
9091
|
+
}
|
|
9001
9092
|
const baseKeyNum = g_keyObj[`${g_keyObj.defaultProp}${basePtn}`].length;
|
|
9002
9093
|
|
|
9003
9094
|
if (_localStorage[`keyCtrl${_extraKeyName}`]?.[0].length > 0) {
|
|
@@ -10098,6 +10189,11 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
|
|
|
10098
10189
|
// 譜面初期情報ロード許可フラグ
|
|
10099
10190
|
g_canLoadDifInfoFlg = false;
|
|
10100
10191
|
|
|
10192
|
+
if (_initFlg) {
|
|
10193
|
+
g_stateObj.keyLockFlg = false;
|
|
10194
|
+
g_stateObj.kbPreviewFlg = false;
|
|
10195
|
+
}
|
|
10196
|
+
|
|
10101
10197
|
multiAppend(divRoot,
|
|
10102
10198
|
|
|
10103
10199
|
// キーコンフィグ画面タイトル
|
|
@@ -10105,8 +10201,7 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
|
|
|
10105
10201
|
`<div class="settings_Title">${g_lblNameObj.key}</div><div class="settings_Title2">${g_lblNameObj.config}</div>`
|
|
10106
10202
|
.replace(/[\t\n]/g, ``), 0, 15, g_cssObj.flex_centering),
|
|
10107
10203
|
|
|
10108
|
-
createDescDiv(`kcDesc`,
|
|
10109
|
-
.split(`{1}:`).join(g_isMac ? `` : `Delete:`)),
|
|
10204
|
+
createDescDiv(`kcDesc`, getKcDescMsg()),
|
|
10110
10205
|
|
|
10111
10206
|
createDescDiv(`kcShuffleDesc`,
|
|
10112
10207
|
g_headerObj.shuffleUse && g_settings.shuffles.filter(val => val.endsWith(`+`)).length > 0
|
|
@@ -10236,11 +10331,24 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
|
|
|
10236
10331
|
* @param {number} _scrollNum
|
|
10237
10332
|
*/
|
|
10238
10333
|
const changeTmpColor = (_j, _scrollNum = 1) => {
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10334
|
+
const changeTmpOneColor = _idx => {
|
|
10335
|
+
changeTmpData(`color`, g_headerObj.setColor.length, _idx, _scrollNum);
|
|
10336
|
+
const arrowColor = getKeyConfigColor(_idx, g_keyObj[`color${keyCtrlPtn}`][_idx]);
|
|
10337
|
+
$id(`arrow${_idx}`).background = arrowColor;
|
|
10338
|
+
$id(`arrowShadow${_idx}`).background = getShadowColor(g_keyObj[`color${keyCtrlPtn}`][_idx], arrowColor);
|
|
10339
|
+
};
|
|
10243
10340
|
|
|
10341
|
+
if (g_stateObj.keyLockFlg && keyIsShift()) {
|
|
10342
|
+
const tmpList = [];
|
|
10343
|
+
g_keyObj[`color${keyCtrlPtn}`].forEach((val, idx) => {
|
|
10344
|
+
if (val === g_keyObj[`color${keyCtrlPtn}`][_j]) {
|
|
10345
|
+
tmpList.push(idx);
|
|
10346
|
+
}
|
|
10347
|
+
});
|
|
10348
|
+
tmpList.forEach(idx => changeTmpOneColor(idx));
|
|
10349
|
+
} else {
|
|
10350
|
+
changeTmpOneColor(_j);
|
|
10351
|
+
}
|
|
10244
10352
|
adjustScrollPoint(parseFloat($id(`arrow${_j}`).left));
|
|
10245
10353
|
};
|
|
10246
10354
|
|
|
@@ -10250,10 +10358,23 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
|
|
|
10250
10358
|
* @param {number} _scrollNum
|
|
10251
10359
|
*/
|
|
10252
10360
|
const changeTmpShuffleNum = (_j, _scrollNum = 1) => {
|
|
10253
|
-
const
|
|
10254
|
-
|
|
10361
|
+
const changeTmpOneShuffle = _idx => {
|
|
10362
|
+
const tmpShuffle = changeTmpData(`shuffle`, g_keyObj[`keyCtrl${keyCtrlPtn}`].length - 1, _idx, _scrollNum);
|
|
10363
|
+
document.getElementById(`sArrow${_idx}`).textContent = tmpShuffle + 1;
|
|
10364
|
+
changeShuffleConfigColor(keyCtrlPtn, g_keyObj[`shuffle${keyCtrlPtn}_${g_keycons.shuffleGroupNum}`][_idx], _idx);
|
|
10365
|
+
};
|
|
10255
10366
|
|
|
10256
|
-
|
|
10367
|
+
if (g_stateObj.keyLockFlg && keyIsShift()) {
|
|
10368
|
+
const tmpList = [];
|
|
10369
|
+
g_keyObj[`shuffle${keyCtrlPtn}`].forEach((val, idx) => {
|
|
10370
|
+
if (val === g_keyObj[`shuffle${keyCtrlPtn}`][_j]) {
|
|
10371
|
+
tmpList.push(idx);
|
|
10372
|
+
}
|
|
10373
|
+
});
|
|
10374
|
+
tmpList.forEach(idx => changeTmpOneShuffle(idx));
|
|
10375
|
+
} else {
|
|
10376
|
+
changeTmpOneShuffle(_j);
|
|
10377
|
+
}
|
|
10257
10378
|
adjustScrollPoint(parseFloat($id(`arrow${_j}`).left));
|
|
10258
10379
|
};
|
|
10259
10380
|
|
|
@@ -10941,17 +11062,30 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
|
|
|
10941
11062
|
}
|
|
10942
11063
|
}, g_lblPosObj.btnKcReset, g_cssObj.button_Reset),
|
|
10943
11064
|
|
|
11065
|
+
createCss2Button(`btnKeyLock`, getKeyLockName(), () => {
|
|
11066
|
+
g_stateObj.keyLockFlg = !g_stateObj.keyLockFlg;
|
|
11067
|
+
makeInfoWindow(g_msgInfoObj.I_0012.split(`{0}`).join(boolToSwitch(!g_stateObj.keyLockFlg)), `leftToRightFade`);
|
|
11068
|
+
toggleKcDesc();
|
|
11069
|
+
}, g_lblPosObj.btnKcKeyLock, g_cssObj.button_Mini),
|
|
11070
|
+
|
|
10944
11071
|
// プレイ開始
|
|
10945
11072
|
makePlayButton(() => loadMusic())
|
|
10946
11073
|
);
|
|
11074
|
+
toggleKcDesc();
|
|
10947
11075
|
|
|
10948
11076
|
// キーボード押下時処理
|
|
10949
11077
|
setShortcutEvent(g_currentPage, (kbCode) => {
|
|
11078
|
+
const C_KEY_ESCAPE = 27;
|
|
11079
|
+
const C_KEY_IME = 229;
|
|
10950
11080
|
const keyCdObj = document.getElementById(`keycon${g_currentj}_${g_currentk}`);
|
|
10951
11081
|
let setKey = g_kCdN.findIndex(kCd => kCd === kbCode);
|
|
10952
11082
|
|
|
10953
|
-
|
|
10954
|
-
|
|
11083
|
+
if (g_stateObj.keyLockFlg) {
|
|
11084
|
+
if (setKey === C_KEY_ESCAPE) {
|
|
11085
|
+
btnBack.click();
|
|
11086
|
+
}
|
|
11087
|
+
return;
|
|
11088
|
+
}
|
|
10955
11089
|
|
|
10956
11090
|
// 全角切替、BackSpace、Deleteキー、Escキーは割り当て禁止
|
|
10957
11091
|
// また、直前と同じキーを押した場合(BackSpaceを除く)はキー操作を無効にする
|
|
@@ -11032,11 +11166,33 @@ const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
|
|
|
11032
11166
|
})
|
|
11033
11167
|
);
|
|
11034
11168
|
|
|
11169
|
+
if (g_stateObj.kbPreviewFlg) {
|
|
11170
|
+
btnKbPreview.click();
|
|
11171
|
+
}
|
|
11172
|
+
|
|
11035
11173
|
safeExecuteCustomHooks(`g_skinJsObj.keyconfig`, g_skinJsObj.keyconfig);
|
|
11036
11174
|
document.onkeyup = evt => commonKeyUp(evt);
|
|
11037
11175
|
document.oncontextmenu = () => false;
|
|
11038
11176
|
};
|
|
11039
11177
|
|
|
11178
|
+
const toggleKcDesc = () => {
|
|
11179
|
+
if (document.getElementById(`kcDesc`) !== null) {
|
|
11180
|
+
kcDesc.textContent = getKcDescMsg();
|
|
11181
|
+
kcDesc.style.fontSize = wUnit(getFontSize2(kcDesc.textContent, g_lblPosObj.kcDesc.w, { maxSiz: g_limitObj.mainSiz }));
|
|
11182
|
+
kcDesc.classList.remove(g_cssObj.title_base, g_cssObj.keyconfig_Defaultkey);
|
|
11183
|
+
kcDesc.classList.add(g_stateObj.keyLockFlg ? g_cssObj.keyconfig_Defaultkey : g_cssObj.title_base);
|
|
11184
|
+
btnKeyLock.innerHTML = getKeyLockName();
|
|
11185
|
+
}
|
|
11186
|
+
};
|
|
11187
|
+
|
|
11188
|
+
const getKcDescMsg = () =>
|
|
11189
|
+
g_stateObj.keyLockFlg
|
|
11190
|
+
? g_lblNameObj.kcNonDesc
|
|
11191
|
+
: g_lblNameObj.kcDesc.split(`{0}`).join(g_kCd[C_KEY_RETRY]).split(`{1}:`).join(g_isMac ? `` : `Delete:`);
|
|
11192
|
+
|
|
11193
|
+
const getKeyLockName = () =>
|
|
11194
|
+
`${g_lblNameObj.b_keyLock}${g_stateObj.keyLockFlg ? g_emojiObj.locked : g_emojiObj.unlocked}`;
|
|
11195
|
+
|
|
11040
11196
|
/**
|
|
11041
11197
|
* キーボードレイアウトプレビュー(Canvas版)
|
|
11042
11198
|
*
|
|
@@ -11612,7 +11768,9 @@ const keyconfigKeyboardPreview = (() => {
|
|
|
11612
11768
|
|
|
11613
11769
|
_state.visible = !_state.visible;
|
|
11614
11770
|
area.style.display = _state.visible ? `block` : `none`;
|
|
11615
|
-
|
|
11771
|
+
g_stateObj.kbPreviewFlg = _state.visible;
|
|
11772
|
+
g_stateObj.keyLockFlg = _state.visible;
|
|
11773
|
+
toggleKcDesc();
|
|
11616
11774
|
if (_state.visible) refresh();
|
|
11617
11775
|
};
|
|
11618
11776
|
|
|
@@ -11830,7 +11988,7 @@ const loadMusic = () => {
|
|
|
11830
11988
|
const blobUrl = URL.createObjectURL(request.response);
|
|
11831
11989
|
createEmptySprite(divRoot, `loader`, g_windowObj.loader);
|
|
11832
11990
|
lblLoading.textContent = g_lblNameObj.pleaseWait;
|
|
11833
|
-
setAudio(blobUrl);
|
|
11991
|
+
setAudio(blobUrl, url);
|
|
11834
11992
|
} else {
|
|
11835
11993
|
makeWarningWindow(`${g_msgInfoObj.E_0041.split('{0}').join(getFullPath(url))}<br>(${request.status} ${request.statusText})`, { backBtnUse: true });
|
|
11836
11994
|
}
|
|
@@ -11862,8 +12020,9 @@ const loadMusic = () => {
|
|
|
11862
12020
|
* 音楽データの設定
|
|
11863
12021
|
* iOSの場合はAudioタグによる再生
|
|
11864
12022
|
* @param {string} _url
|
|
12023
|
+
* @param {string} _cacheKey
|
|
11865
12024
|
*/
|
|
11866
|
-
const setAudio = async (_url) => {
|
|
12025
|
+
const setAudio = async (_url, _cacheKey = _url) => {
|
|
11867
12026
|
|
|
11868
12027
|
const loadMp3 = () => {
|
|
11869
12028
|
if (g_isFile) {
|
|
@@ -11895,7 +12054,7 @@ const setAudio = async (_url) => {
|
|
|
11895
12054
|
await loadScript2(_url);
|
|
11896
12055
|
if (typeof musicInit === C_TYP_FUNCTION) {
|
|
11897
12056
|
musicInit();
|
|
11898
|
-
readyToStart(() => initWebAudioAPIfromBase64(g_musicdata));
|
|
12057
|
+
readyToStart(() => initWebAudioAPIfromBase64(g_musicdata, _cacheKey));
|
|
11899
12058
|
} else {
|
|
11900
12059
|
makeWarningWindow(g_msgInfoObj.E_0031);
|
|
11901
12060
|
musicAfterLoaded();
|
|
@@ -11906,11 +12065,19 @@ const setAudio = async (_url) => {
|
|
|
11906
12065
|
};
|
|
11907
12066
|
|
|
11908
12067
|
// Base64から音声データに変換してWebAudioAPIで再生する準備
|
|
11909
|
-
const initWebAudioAPIfromBase64 = async (_base64) => {
|
|
12068
|
+
const initWebAudioAPIfromBase64 = async (_base64, _cacheKey) => {
|
|
11910
12069
|
g_audio = new AudioPlayer();
|
|
11911
12070
|
musicAfterLoaded();
|
|
11912
|
-
|
|
12071
|
+
|
|
12072
|
+
if (_cacheKey && g_audioBufferCache.has(_cacheKey)) {
|
|
12073
|
+
g_audio.setBuffer(g_audioBufferCache.get(_cacheKey)); // デコード完全スキップ
|
|
12074
|
+
return;
|
|
12075
|
+
}
|
|
12076
|
+
const array = base64ToUint8Array(_base64);
|
|
11913
12077
|
await g_audio.init(array.buffer);
|
|
12078
|
+
if (_cacheKey) {
|
|
12079
|
+
cacheAudioBuffer(_cacheKey, g_audio.getBuffer());
|
|
12080
|
+
}
|
|
11914
12081
|
};
|
|
11915
12082
|
|
|
11916
12083
|
// 音声ファイルを読み込んでWebAudioAPIで再生する準備
|
|
@@ -11922,6 +12089,26 @@ const initWebAudioAPIfromURL = async (_url) => {
|
|
|
11922
12089
|
await g_audio.init(arrayBuffer);
|
|
11923
12090
|
};
|
|
11924
12091
|
|
|
12092
|
+
const g_audioBufferCache = new Map();
|
|
12093
|
+
const AUDIO_CACHE_MAX = 5;
|
|
12094
|
+
|
|
12095
|
+
const cacheAudioBuffer = (_key, _buffer) => {
|
|
12096
|
+
g_audioBufferCache.set(_key, _buffer);
|
|
12097
|
+
if (g_audioBufferCache.size > AUDIO_CACHE_MAX) {
|
|
12098
|
+
g_audioBufferCache.delete(g_audioBufferCache.keys().next().value); // 古い順に破棄
|
|
12099
|
+
}
|
|
12100
|
+
};
|
|
12101
|
+
|
|
12102
|
+
const base64ToUint8Array = (_base64Str) => {
|
|
12103
|
+
const binaryStr = atob(_base64Str);
|
|
12104
|
+
const len = binaryStr.length;
|
|
12105
|
+
const array = new Uint8Array(len);
|
|
12106
|
+
for (let i = 0; i < len; i++) {
|
|
12107
|
+
array[i] = binaryStr.charCodeAt(i);
|
|
12108
|
+
}
|
|
12109
|
+
return array;
|
|
12110
|
+
};
|
|
12111
|
+
|
|
11925
12112
|
const musicAfterLoaded = () => {
|
|
11926
12113
|
g_audio.load();
|
|
11927
12114
|
|
|
@@ -16725,7 +16912,8 @@ const resultInit = () => {
|
|
|
16725
16912
|
makeCssResultPlayData(`lblMusicData`, dataRX, g_cssObj.result_style, 0, mTitleForView[0]),
|
|
16726
16913
|
makeCssResultPlayData(`lblMusicData2`, dataRX, g_cssObj.result_style, 1, mTitleForView[1]),
|
|
16727
16914
|
makeCssResultPlayData(`lblDifficulty`, lblRX, g_cssObj.result_lbl, 2, g_lblNameObj.rt_Difficulty, C_ALIGN_LEFT),
|
|
16728
|
-
makeCssResultPlayData(`lblDifData`, dataRX, g_cssObj.result_style, 2, settingData.difData
|
|
16915
|
+
makeCssResultPlayData(`lblDifData`, dataRX, g_cssObj.result_style, 2, settingData.difData, C_ALIGN_CENTER,
|
|
16916
|
+
{ siz: getFontSize2(settingData.difData, 350) }),
|
|
16729
16917
|
makeCssResultPlayData(`lblStyle`, lblRX, g_cssObj.result_lbl, 3, g_lblNameObj.rt_Style, C_ALIGN_LEFT),
|
|
16730
16918
|
makeCssResultPlayData(`lblStyleData`, dataRX, g_cssObj.result_style, 3, settingData.playStyleData),
|
|
16731
16919
|
makeCssResultPlayData(`lblDisplay`, lblRX, g_cssObj.result_lbl, 4, g_lblNameObj.rt_Display, C_ALIGN_LEFT),
|
|
@@ -16734,21 +16922,9 @@ const resultInit = () => {
|
|
|
16734
16922
|
);
|
|
16735
16923
|
|
|
16736
16924
|
// 設定項目が多い場合に2行に分解して表示する処理
|
|
16737
|
-
|
|
16738
|
-
|
|
16739
|
-
|
|
16740
|
-
if (lblStyleData.textContent[j] === `,`) {
|
|
16741
|
-
playStyleBreakNum = j + 2;
|
|
16742
|
-
break;
|
|
16743
|
-
}
|
|
16744
|
-
}
|
|
16745
|
-
lblStyleData.style.top = `${parseFloat(lblStyleData.style.top) - 3}px`;
|
|
16746
|
-
lblStyleData.innerHTML = `${lblStyleData.textContent.slice(0, playStyleBreakNum)}<br>` +
|
|
16747
|
-
`${lblStyleData.textContent.slice(playStyleBreakNum)}`;
|
|
16748
|
-
lblStyleData.style.fontSize = `${getFontSize2(lblStyleData.textContent.slice(0, playStyleBreakNum), 350, { maxSiz: 10 })}px`;
|
|
16749
|
-
} else {
|
|
16750
|
-
lblStyleData.style.fontSize = `${getFontSize2(lblStyleData.textContent, 350)}px`;
|
|
16751
|
-
}
|
|
16925
|
+
const [styleStr, styleSiz] = getFontSizeMulti(settingData.playStyleData, 350, { maxSizMulti: 10, len: 60 });
|
|
16926
|
+
lblStyleData.innerHTML = styleStr;
|
|
16927
|
+
lblStyleData.style.fontSize = wUnit(styleSiz);
|
|
16752
16928
|
|
|
16753
16929
|
/**
|
|
16754
16930
|
* キャラクタ、スコア描画のID共通部、色CSS名、スコア変数名
|
|
@@ -17182,6 +17358,7 @@ const resultInit = () => {
|
|
|
17182
17358
|
const artistName = g_headerObj.artistNames[g_headerObj.musicNos[g_stateObj.scoreId]] || g_headerObj.artistName;
|
|
17183
17359
|
const logicalWidth = 400;
|
|
17184
17360
|
const logicalHeight = g_sHeight - 90;
|
|
17361
|
+
const flapWidth = 370;
|
|
17185
17362
|
|
|
17186
17363
|
canvas.id = `resultImage`;
|
|
17187
17364
|
canvas.width = logicalWidth * g_dpr;
|
|
@@ -17210,13 +17387,14 @@ const resultInit = () => {
|
|
|
17210
17387
|
drawText(unEscapeHtml(mTitleForView[1]), { hy: 2 });
|
|
17211
17388
|
drawText(`${getEmojiForCanvas(g_emojiObj.memo)} ${unEscapeHtml(g_headerObj.tuning)} / ${getEmojiForCanvas(g_emojiObj.musical)} ${unEscapeHtml(artistName)}`,
|
|
17212
17389
|
{ hy: mTitleForView[1] !== `` ? 3 : 2, siz: 12 });
|
|
17213
|
-
drawText(unEscapeHtml(settingData.difDataForImage), { hy: 4 });
|
|
17390
|
+
drawText(unEscapeHtml(settingData.difDataForImage), { hy: 4, siz: getFontSize2(settingData.difDataForImage, flapWidth) });
|
|
17214
17391
|
|
|
17215
17392
|
if (settingData.playStyleData.length > 60) {
|
|
17216
|
-
|
|
17217
|
-
drawText(
|
|
17393
|
+
const strs = styleStr.split(`<br>`);
|
|
17394
|
+
drawText(strs[0], { hy: 5, siz: getFontSize2(strs[0], flapWidth) });
|
|
17395
|
+
drawText(strs[1], { hy: 6, siz: getFontSize2(strs[1], flapWidth) });
|
|
17218
17396
|
} else {
|
|
17219
|
-
drawText(settingData.playStyleData, { hy: 5, siz: getFontSize2(settingData.playStyleData,
|
|
17397
|
+
drawText(settingData.playStyleData, { hy: 5, siz: getFontSize2(settingData.playStyleData, flapWidth, { maxSiz: 15 }) });
|
|
17220
17398
|
}
|
|
17221
17399
|
Object.keys(jdgScoreObj).forEach(score => {
|
|
17222
17400
|
drawText(g_lblNameObj[`j_${score}`], { hy: 7 + jdgScoreObj[score].pos, color: jdgScoreObj[score].dfColor });
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Source by tickle
|
|
7
7
|
* Created : 2019/11/19
|
|
8
|
-
* Revised : 2026/06/
|
|
8
|
+
* Revised : 2026/06/23 (v49.0.0)
|
|
9
9
|
*
|
|
10
10
|
* https://github.com/cwtickle/danoniplus
|
|
11
11
|
*/
|
|
@@ -640,6 +640,10 @@ const updateWindowSiz = () => {
|
|
|
640
640
|
x: g_btnX() + Math.floor((g_btnWidth() - 80) / 2), y: 3, w: 80, h: 18, siz: 11,
|
|
641
641
|
title: g_msgObj.displayPreview,
|
|
642
642
|
},
|
|
643
|
+
btnKcKeyLock: {
|
|
644
|
+
x: g_btnX() + Math.floor((g_btnWidth() - 80) / 2) + 90, y: 3, w: 80, h: 18, siz: 11,
|
|
645
|
+
title: g_msgObj.keyLock,
|
|
646
|
+
},
|
|
643
647
|
|
|
644
648
|
btnKcBack: {
|
|
645
649
|
x: g_btnX(1 / 3), y: g_sHeight - 75,
|
|
@@ -1062,6 +1066,8 @@ const g_emojiObj = {
|
|
|
1062
1066
|
memo: `📝`, // メモ (memo)
|
|
1063
1067
|
musical: `🎵`, // 音符 (musical note)
|
|
1064
1068
|
camera: `📷`, // カメラ (camera)
|
|
1069
|
+
locked: `🔒`, // 鍵 (locked)
|
|
1070
|
+
unlocked: `🔓`, // 鍵開 (unlocked)
|
|
1065
1071
|
};
|
|
1066
1072
|
|
|
1067
1073
|
/** 設定・オプション画面用共通 */
|
|
@@ -1284,6 +1290,9 @@ const g_stateObj = {
|
|
|
1284
1290
|
rotateEnabled: true,
|
|
1285
1291
|
flatStepHeight: C_ARW_WIDTH,
|
|
1286
1292
|
|
|
1293
|
+
keyLockFlg: false,
|
|
1294
|
+
kbPreviewFlg: false,
|
|
1295
|
+
|
|
1287
1296
|
dm_environment: C_FLG_OFF,
|
|
1288
1297
|
dm_highscores: C_FLG_OFF,
|
|
1289
1298
|
dm_customKey: C_FLG_OFF,
|
|
@@ -3597,7 +3606,7 @@ const g_keyObj = {
|
|
|
3597
3606
|
// - _0 の数字部分をカウントアップすることで実現できる。
|
|
3598
3607
|
keyCtrl5_1: [[`Space`], [`Left`], [`Down`], [`Up`], [`Right`]],
|
|
3599
3608
|
keyCtrl7_1: [[`S`], [`E`], [`F`], [`Space`, `G`, `H`], [`J`], [`I`], [`L`]],
|
|
3600
|
-
keyCtrl8_1: [[`
|
|
3609
|
+
keyCtrl8_1: [[`Tab`], [`S`], [`D`], [`F`], [`Space`], [`J`], [`K`], [`L`]],
|
|
3601
3610
|
keyCtrl9A_1: [[`S`], [`D`], [`E`, `R`], [`F`], [`Space`], [`Left`], [`Down`], [`Up`], [`Right`]],
|
|
3602
3611
|
keyCtrl9i_1: [[`A`], [`S`], [`D`], [`F`], [`Space`], [`Left`], [`Down`], [`Up`], [`Right`]],
|
|
3603
3612
|
keyCtrl11_1: [[`S`], [`D`], [`F`], [`Space`], [`J`], [`K`], [`L`], [`Left`], [`Down`], [`Up`], [`Right`]],
|
|
@@ -3658,7 +3667,7 @@ const g_keyObj = {
|
|
|
3658
3667
|
// ショートカットキーコード
|
|
3659
3668
|
keyRetry: 8, // 8: Backspace
|
|
3660
3669
|
keyRetry8_0: 9, // 9: Tab
|
|
3661
|
-
keyRetry8_1:
|
|
3670
|
+
keyRetry8_1: 8, // 8: Backspace
|
|
3662
3671
|
keyRetry11j_0: 123, // 123: F12
|
|
3663
3672
|
|
|
3664
3673
|
keyTitleBack: 46, // 46: Delete
|
|
@@ -3666,9 +3675,8 @@ const g_keyObj = {
|
|
|
3666
3675
|
|
|
3667
3676
|
// 別キー
|
|
3668
3677
|
transKey8_2: '12',
|
|
3669
|
-
transKey15A_1: '',
|
|
3670
|
-
transKey15B_0: '',
|
|
3671
|
-
transKey15B_1: '',
|
|
3678
|
+
transKey15A_1: '15B', // 15A/15Bはキーパターンをコピーして生成するため、transKeyを明示的に指定
|
|
3679
|
+
transKey15B_0: '', // 15A/15Bはキーパターンをコピーして生成するため、transKeyを明示的に指定
|
|
3672
3680
|
|
|
3673
3681
|
// キー置換用(ParaFla版との互換)
|
|
3674
3682
|
keyTransPattern: {
|
|
@@ -4461,6 +4469,7 @@ const g_lang_msgInfoObj = {
|
|
|
4461
4469
|
I_0006: `ローカルストレージ情報をクリップボードにコピーしました!`,
|
|
4462
4470
|
I_0007: `オブジェクト情報をクリップボードにコピーしました!`,
|
|
4463
4471
|
I_0011: `指定した部分キーが未定義のため、画面表示できません。設定を見直してください。`,
|
|
4472
|
+
I_0012: `キー割り当てモードを{0}に変更しました。`,
|
|
4464
4473
|
},
|
|
4465
4474
|
En: {
|
|
4466
4475
|
W_0001: `Your browser is not guaranteed to work.<br>
|
|
@@ -4511,6 +4520,7 @@ const g_lang_msgInfoObj = {
|
|
|
4511
4520
|
I_0006: `Local storage information copied to clipboard!`,
|
|
4512
4521
|
I_0007: `Object information copied to clipboard!`,
|
|
4513
4522
|
I_0011: `The specified partial key is undefined and cannot be displayed on the screen. Please review your settings.`,
|
|
4523
|
+
I_0012: `Key assignment mode changed to {0}.`,
|
|
4514
4524
|
},
|
|
4515
4525
|
};
|
|
4516
4526
|
|
|
@@ -4566,6 +4576,7 @@ const g_lblNameObj = {
|
|
|
4566
4576
|
b_close: `Close`,
|
|
4567
4577
|
b_cReset: `Reset`,
|
|
4568
4578
|
b_precond: `Precondition`,
|
|
4579
|
+
b_keyLock: `KeyLock`,
|
|
4569
4580
|
|
|
4570
4581
|
Difficulty: `Difficulty`,
|
|
4571
4582
|
Speed: `Speed`,
|
|
@@ -4818,6 +4829,7 @@ const g_lang_lblNameObj = {
|
|
|
4818
4829
|
dataDeleteONDesc: `セーフモード適用中はデータ消去は行えません。変更するにはセーフモードを解除してください`,
|
|
4819
4830
|
|
|
4820
4831
|
kcDesc: `[{0}:スキップ / {1}:(代替キーのみ)キー無効化]`,
|
|
4832
|
+
kcNonDesc: `キー割り当て無効化中です。解除するには「KeyLock」を押してください`,
|
|
4821
4833
|
kcShuffleDesc: `番号をクリックでシャッフルグループ、矢印をクリックでカラーグループを変更`,
|
|
4822
4834
|
kcNoShuffleDesc: `矢印をクリックでカラーグループを変更`,
|
|
4823
4835
|
sdDesc: `[クリックでON/OFFを切替、灰色でOFF]`,
|
|
@@ -4881,6 +4893,7 @@ const g_lang_lblNameObj = {
|
|
|
4881
4893
|
dataDeleteONDesc: `Data erasure cannot be performed while safe mode is applied. <br>Please deactivate the safe mode to change the data.`,
|
|
4882
4894
|
|
|
4883
4895
|
kcDesc: `[{0}:Skip / {1}:Key invalidation (Alternate keys only)]`,
|
|
4896
|
+
kcNonDesc: `Key assignments are currently disabled. Press "KeyLock" to disable this setting.`,
|
|
4884
4897
|
kcShuffleDesc: `Click the number to change the shuffle group, and click the arrow to change the color.`,
|
|
4885
4898
|
kcNoShuffleDesc: `Click the arrow to change the color group.`,
|
|
4886
4899
|
sdDesc: `[Click to switch, gray to OFF]`,
|
|
@@ -5052,6 +5065,7 @@ const g_lang_msgObj = {
|
|
|
5052
5065
|
stepRtnGroup: `矢印などノーツの種類、回転に関するパターンを切り替えます。\nあらかじめ設定されている場合のみ変更可能です。`,
|
|
5053
5066
|
kcReset: `対応するキーの割り当てを元に戻します。`,
|
|
5054
5067
|
kcPreview: `キーボードレイアウトのプレビューを表示/非表示します。`,
|
|
5068
|
+
keyLock: `キー割り当ての有効/無効を切り替えます。\n無効化時はシフトキー+番号/矢印クリックで同一グループの矢印群をまとめてグループ変更できます。`,
|
|
5055
5069
|
|
|
5056
5070
|
pickArrow: `色番号ごとの矢印色(枠、塗りつぶし)、通常時のフリーズアロー色(枠、帯)を\nカラーピッカーから選んで変更できます。`,
|
|
5057
5071
|
pickColorR: `設定する矢印色の種類を切り替えます。`,
|
|
@@ -5159,6 +5173,7 @@ const g_lang_msgObj = {
|
|
|
5159
5173
|
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.`,
|
|
5160
5174
|
kcReset: `Restores the corresponding key assignments.`,
|
|
5161
5175
|
kcPreview: `Show/hide the preview of the keyboard layout.`,
|
|
5176
|
+
keyLock: `Toggles key assignments on or off. \nWhen disabled, you can use the Shift key plus a number or arrow key \nto change the group of all arrows in the same group at once.`,
|
|
5162
5177
|
|
|
5163
5178
|
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.`,
|
|
5164
5179
|
pickColorR: `Switches the arrow color type to be set.`,
|