danoniplus 50.4.0 → 50.5.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 +479 -16549
- package/js/lib/danoni_constants.js +2 -1
- package/js/lib/dataLoader.js +2837 -0
- package/js/lib/dosConverter.js +3093 -0
- package/js/lib/keyconfig.js +1932 -0
- package/js/lib/mainWindow.js +2626 -0
- package/js/lib/result.js +979 -0
- package/js/lib/settings.js +3426 -0
- package/js/lib/title.js +1274 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1932 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dancing☆Onigiri (CW Edition)
|
|
3
|
+
* キーコンフィグ画面
|
|
4
|
+
* - ページ: keyConfig
|
|
5
|
+
*
|
|
6
|
+
* Source by tickle
|
|
7
|
+
* Created : 2026/09/13
|
|
8
|
+
* Revised :
|
|
9
|
+
*
|
|
10
|
+
* https://github.com/cwtickle/danoniplus
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/*-----------------------------------------------------------*/
|
|
14
|
+
/* Scene : KEYCONFIG [orange] */
|
|
15
|
+
/*-----------------------------------------------------------*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* キーコンフィグ画面初期化
|
|
19
|
+
* @param {string} _kcType
|
|
20
|
+
* @param {boolean} _initFlg 初期表示フラグ
|
|
21
|
+
*/
|
|
22
|
+
const keyConfigInit = (_kcType = g_kcType, _initFlg = false) => {
|
|
23
|
+
|
|
24
|
+
clearWindow();
|
|
25
|
+
const divRoot = document.getElementById(`divRoot`);
|
|
26
|
+
g_kcType = _kcType;
|
|
27
|
+
g_currentPage = `keyConfig`;
|
|
28
|
+
let selectedKc = `Default`;
|
|
29
|
+
|
|
30
|
+
// 譜面初期情報ロード許可フラグ
|
|
31
|
+
g_canLoadDifInfoFlg = false;
|
|
32
|
+
|
|
33
|
+
if (_initFlg) {
|
|
34
|
+
g_stateObj.keyLockFlg = false;
|
|
35
|
+
g_stateObj.kbPreviewFlg = false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
multiAppend(divRoot,
|
|
39
|
+
|
|
40
|
+
// キーコンフィグ画面タイトル
|
|
41
|
+
getTitleDivLabel(`lblTitle`,
|
|
42
|
+
`<div class="settings_Title">${g_lblNameObj.key}</div><div class="settings_Title2">${g_lblNameObj.config}</div>`
|
|
43
|
+
.replace(/[\t\n]/g, ``), 0, 15, g_cssObj.flex_centering),
|
|
44
|
+
|
|
45
|
+
createDescDiv(`kcDesc`, getKcDescMsg()),
|
|
46
|
+
|
|
47
|
+
createDescDiv(`kcShuffleDesc`,
|
|
48
|
+
g_headerObj.shuffleUse && g_settings.shuffles.filter(val => val.endsWith(`+`)).length > 0
|
|
49
|
+
? g_lblNameObj.kcShuffleDesc : g_lblNameObj.kcNoShuffleDesc),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* keyconSpriteのスクロール位置調整
|
|
54
|
+
* @param {number} _targetX
|
|
55
|
+
*/
|
|
56
|
+
const adjustScrollPoint = _targetX => {
|
|
57
|
+
if (maxLeftX !== 0) {
|
|
58
|
+
keyconSprite.scrollLeft = Math.max(0, _targetX - g_sWidth / 2);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* キーコンフィグ用の矢印色を取得
|
|
64
|
+
* @param {number} _j
|
|
65
|
+
* @param {number} _colorPos
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
const getKeyConfigColor = (_j, _colorPos) => {
|
|
69
|
+
let arrowColor = g_headerObj.setColor[_colorPos];
|
|
70
|
+
|
|
71
|
+
// 色変化データの利用条件設定(Default/Type0限定)
|
|
72
|
+
const storageObj = g_stateObj.extraKeyFlg ? g_localStorage : g_localKeyStorage;
|
|
73
|
+
const baseGroupNum = g_keycons.colorGroupNum === -1
|
|
74
|
+
? (storageObj?.[`keyCtrlPtn${g_keyObj.currentKey}`] ?? storageObj?.keyCtrlPtn ?? 0)
|
|
75
|
+
: g_keycons.colorGroupNum;
|
|
76
|
+
const currentColorGr = g_keyObj[`color${keyCtrlPtn}_${g_keycons.colorGroupNum}`];
|
|
77
|
+
const baseColorGr = g_baseColorGrs?.[`color${keyCtrlPtn}_${baseGroupNum}`];
|
|
78
|
+
if (hasVal(initColors[_j]) && g_keycons.colorDefTypes.includes(g_colorType)
|
|
79
|
+
&& currentColorGr?.[_j] === baseColorGr?.[_j]) {
|
|
80
|
+
arrowColor = initColors[_j];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// アシスト設定時はアシストの色を優先して適用
|
|
84
|
+
if (typeof g_keyObj[`assistPos${keyCtrlPtn}`] === C_TYP_OBJECT &&
|
|
85
|
+
g_keyObj[`assistPos${keyCtrlPtn}`][g_stateObj.autoPlay] !== undefined &&
|
|
86
|
+
!g_autoPlaysBase.includes(g_stateObj.autoPlay)) {
|
|
87
|
+
if (g_keyObj[`assistPos${keyCtrlPtn}`][g_stateObj.autoPlay][_j] === 1) {
|
|
88
|
+
arrowColor = g_headerObj.setDummyColor[_colorPos];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return arrowColor;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 対象割り当てキーの色変更
|
|
96
|
+
* @param {number} _j
|
|
97
|
+
* @param {number} _k
|
|
98
|
+
* @param {string} _cssName
|
|
99
|
+
*/
|
|
100
|
+
const changeKeyConfigColor = (_j, _k, _cssName) =>
|
|
101
|
+
changeConfigColor(document.getElementById(`keycon${_j}_${_k}`), _cssName);
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 一時的に矢印色・シャッフルグループを変更(共通処理)
|
|
105
|
+
* @param {string} _type
|
|
106
|
+
* @param {number} _len
|
|
107
|
+
* @param {number} _j
|
|
108
|
+
* @param {number} _scrollNum
|
|
109
|
+
* @returns {number}
|
|
110
|
+
*/
|
|
111
|
+
const changeTmpData = (_type, _len, _j, _scrollNum) => {
|
|
112
|
+
const tmpNo = nextPos(g_keyObj[`${_type}${keyCtrlPtn}_${g_keycons[`${_type}GroupNum`]}`][_j], _scrollNum, _len);
|
|
113
|
+
g_keyObj[`${_type}${keyCtrlPtn}`][_j] = tmpNo;
|
|
114
|
+
g_keyObj[`${_type}${keyCtrlPtn}_${g_keycons[`${_type}GroupNum`]}`][_j] = tmpNo;
|
|
115
|
+
|
|
116
|
+
return tmpNo;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 一時的に矢印色を変更
|
|
121
|
+
* @param {number} _j
|
|
122
|
+
* @param {number} _scrollNum
|
|
123
|
+
*/
|
|
124
|
+
const changeTmpColor = (_j, _scrollNum = 1) => {
|
|
125
|
+
const changeTmpOneColor = _idx => {
|
|
126
|
+
changeTmpData(`color`, g_headerObj.setColor.length, _idx, _scrollNum);
|
|
127
|
+
const arrowColor = getKeyConfigColor(_idx, g_keyObj[`color${keyCtrlPtn}`][_idx]);
|
|
128
|
+
$id(`arrow${_idx}`).background = arrowColor;
|
|
129
|
+
$id(`arrowShadow${_idx}`).background = getShadowColor(g_keyObj[`color${keyCtrlPtn}`][_idx], arrowColor);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
if (g_stateObj.keyLockFlg && keyIsShift()) {
|
|
133
|
+
const tmpList = [];
|
|
134
|
+
g_keyObj[`color${keyCtrlPtn}`].forEach((val, idx) => {
|
|
135
|
+
if (val === g_keyObj[`color${keyCtrlPtn}`][_j]) {
|
|
136
|
+
tmpList.push(idx);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
tmpList.forEach(idx => changeTmpOneColor(idx));
|
|
140
|
+
} else {
|
|
141
|
+
changeTmpOneColor(_j);
|
|
142
|
+
}
|
|
143
|
+
adjustScrollPoint(parseFloat($id(`keyGroup${_j}`).left));
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 一時的にシャッフルグループ番号を変更
|
|
148
|
+
* @param {number} _j
|
|
149
|
+
* @param {number} _scrollNum
|
|
150
|
+
*/
|
|
151
|
+
const changeTmpShuffleNum = (_j, _scrollNum = 1) => {
|
|
152
|
+
const changeTmpOneShuffle = _idx => {
|
|
153
|
+
const tmpShuffle = changeTmpData(`shuffle`, g_keyObj[`keyCtrl${keyCtrlPtn}`].length - 1, _idx, _scrollNum);
|
|
154
|
+
document.getElementById(`sArrow${_idx}`).textContent = tmpShuffle + 1;
|
|
155
|
+
changeShuffleConfigColor(keyCtrlPtn, g_keyObj[`shuffle${keyCtrlPtn}_${g_keycons.shuffleGroupNum}`][_idx], _idx);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (g_stateObj.keyLockFlg && keyIsShift()) {
|
|
159
|
+
const tmpList = [];
|
|
160
|
+
g_keyObj[`shuffle${keyCtrlPtn}`].forEach((val, idx) => {
|
|
161
|
+
if (val === g_keyObj[`shuffle${keyCtrlPtn}`][_j]) {
|
|
162
|
+
tmpList.push(idx);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
tmpList.forEach(idx => changeTmpOneShuffle(idx));
|
|
166
|
+
} else {
|
|
167
|
+
changeTmpOneShuffle(_j);
|
|
168
|
+
}
|
|
169
|
+
adjustScrollPoint(parseFloat($id(`keyGroup${_j}`).left));
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 指定関数群だけを抽出したtransform文字列を作成
|
|
174
|
+
* @param {string} _cssString
|
|
175
|
+
* @param {string[]} _funcNames
|
|
176
|
+
* @returns {string}
|
|
177
|
+
*/
|
|
178
|
+
const extractTransformFuncs = (_cssString, _funcNames) => {
|
|
179
|
+
const pattern = new RegExp(`\\b(${_funcNames.join(`|`)})\\([^)]*\\)`, `g`);
|
|
180
|
+
return (_cssString.match(pattern) || []).join(` `);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 対象レーンのレイヤー番号を取得
|
|
185
|
+
* @param {number} _j
|
|
186
|
+
* @param {number} _posj
|
|
187
|
+
* @returns {number}
|
|
188
|
+
*/
|
|
189
|
+
const getLayerIdx = (_j, _posj) => {
|
|
190
|
+
const baseLayer = g_keyObj[`layerGroup${keyCtrlPtn}`]?.[_j] || 0;
|
|
191
|
+
const rowFlg = Number(_posj > divideCnt); // reverse/scrollDirは考慮せず固定
|
|
192
|
+
return baseLayer * 2 + rowFlg;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 対象レイヤーの回転変形を取得
|
|
197
|
+
* @param {string} _keyCtrlPtn
|
|
198
|
+
* @returns {string[]}
|
|
199
|
+
*/
|
|
200
|
+
const getLayerRotateParts = _keyCtrlPtn => {
|
|
201
|
+
const raw = g_keyObj[`layerTrans${_keyCtrlPtn}`]?.[0] ?? [``, ``, ``, ``];
|
|
202
|
+
return raw.map(trans => trans === `` ? `` : extractTransformFuncs(trans, [`rotate`, `rotateX`, `rotateY`, `rotateZ`, `rotate3d`]));
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// キーの一覧を表示するための準備
|
|
206
|
+
const C_LAYER_Y_OFFSET = 10; // baseLayerごとの縦オフセット量
|
|
207
|
+
const keyconSprite = createEmptySprite(divRoot, `keyconSprite`, g_windowObj.keyconSprite);
|
|
208
|
+
const tkObj = getKeyInfo();
|
|
209
|
+
const [keyCtrlPtn, keyNum, posMax, divideCnt] =
|
|
210
|
+
[tkObj.keyCtrlPtn, tkObj.keyNum, tkObj.posMax, tkObj.divideCnt];
|
|
211
|
+
|
|
212
|
+
g_keyCopyLists.simpleDef.forEach(header => updateKeyInfo(header, keyCtrlPtn));
|
|
213
|
+
addTransform(`keyconSprite`, `root`, `scale(${g_keyObj.scale})`, g_transPriority.scale);
|
|
214
|
+
keyconSprite.style.height = wUnit(parseFloat(keyconSprite.style.height) / ((1 + g_keyObj.scale) / 2));
|
|
215
|
+
const kWidth = parseInt(keyconSprite.style.width);
|
|
216
|
+
changeSetColor();
|
|
217
|
+
|
|
218
|
+
const maxLeftPos = Math.max(divideCnt, posMax - divideCnt - 2) / 2;
|
|
219
|
+
const maxLeftX = Math.min(0, (kWidth - C_ARW_WIDTH) / 2 - maxLeftPos * g_keyObj.blank);
|
|
220
|
+
|
|
221
|
+
g_keycons.cursorNumList = [...Array(keyNum).keys()].map(i => i);
|
|
222
|
+
const configKeyGroupList = g_headerObj.keyGroupOrder[g_stateObj.scoreId] ??
|
|
223
|
+
g_keyObj[`keyGroupOrder${keyCtrlPtn}`] ?? tkObj.keyGroupList;
|
|
224
|
+
g_keycons.colorCursorNum = 0;
|
|
225
|
+
|
|
226
|
+
// 色変化中の初期色を取得(矢印枠のみ)
|
|
227
|
+
const arrowColorTmp = g_detailObj.miniMapParams[g_stateObj.scoreId]._scoreObj.ncolorData.Arrow;
|
|
228
|
+
const arrowColors = Array.from({ length: Math.ceil(arrowColorTmp.length / 5) }, (_, i) =>
|
|
229
|
+
arrowColorTmp.slice(i * 5, i * 5 + 5)
|
|
230
|
+
).filter(val => val[0] === 0);
|
|
231
|
+
const initColors = [];
|
|
232
|
+
arrowColors.forEach(val => {
|
|
233
|
+
const laneToken = val[1];
|
|
234
|
+
const laneStr = String(laneToken ?? ``);
|
|
235
|
+
if (laneStr.startsWith('g')) {
|
|
236
|
+
// g付きの場合は矢印グループから対象の矢印番号を検索
|
|
237
|
+
const groupVal = setIntVal(laneStr.slice(1));
|
|
238
|
+
for (let j = 0; j < tkObj.keyNum; j++) {
|
|
239
|
+
if (g_keyObj[`color${tkObj.keyCtrlPtn}`][j] === groupVal) {
|
|
240
|
+
initColors[j] = makeColorGradation(val[2]);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
const laneIdx = setIntVal(laneToken, -1);
|
|
245
|
+
if (laneIdx >= 0 && laneIdx < tkObj.keyNum) {
|
|
246
|
+
initColors[laneIdx] = makeColorGradation(val[2]);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
if (_initFlg) {
|
|
251
|
+
g_baseColorGrs = {};
|
|
252
|
+
const colorKey = Object.keys(g_keyObj).filter(val => val.startsWith(`color${g_keyObj.currentKey}`));
|
|
253
|
+
colorKey.forEach(val => g_baseColorGrs[val] = g_keyObj[val]);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const layerParts = getLayerRotateParts(keyCtrlPtn);
|
|
257
|
+
g_keycons.layerIdxList = [];
|
|
258
|
+
|
|
259
|
+
// キーコンフィグの矢印表示
|
|
260
|
+
const addLeft = (maxLeftX === 0 ? 0 : - maxLeftX + g_limitObj.kcColorPickerX);
|
|
261
|
+
for (let j = 0; j < keyNum; j++) {
|
|
262
|
+
|
|
263
|
+
const posj = g_keyObj[`pos${keyCtrlPtn}`][j];
|
|
264
|
+
const stdPos = posj - ((posj > divideCnt ? posMax : 0) + divideCnt) / 2;
|
|
265
|
+
const baseLayer = g_keyObj[`layerGroup${keyCtrlPtn}`]?.[j] || 0;
|
|
266
|
+
const layerIdx = getLayerIdx(j, posj); // baseLayer*2 + Number(posj > divideCnt)
|
|
267
|
+
const layerRotate = layerParts[layerIdx] || ``;
|
|
268
|
+
g_keycons.layerIdxList[j] = layerIdx;
|
|
269
|
+
|
|
270
|
+
const keyconX = g_keyObj.blank * stdPos + (kWidth - C_ARW_WIDTH) / 2 + addLeft;
|
|
271
|
+
const keyconY = C_KYC_HEIGHT * (Number(posj > divideCnt)) + 12 + baseLayer * C_LAYER_Y_OFFSET;
|
|
272
|
+
const colorPos = g_keyObj[`color${keyCtrlPtn}`][j];
|
|
273
|
+
const arrowColor = getKeyConfigColor(j, colorPos);
|
|
274
|
+
|
|
275
|
+
keyconSprite.appendChild(
|
|
276
|
+
createCss2Button(`color${j}`, ``, () => changeTmpColor(j), {
|
|
277
|
+
x: keyconX, y: keyconY, w: C_ARW_WIDTH, h: C_ARW_WIDTH,
|
|
278
|
+
cxtFunc: () => changeTmpColor(j, -1),
|
|
279
|
+
}, g_cssObj.button_Default_NoColor, g_cssObj.title_base)
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// キーごとの親コンテナ(矢印要素を囲う)
|
|
283
|
+
const keyGroup = createEmptySprite(keyconSprite, `keyGroup${j}`, { x: keyconX, y: keyconY, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
|
|
284
|
+
if (layerRotate !== ``) {
|
|
285
|
+
keyGroup.style.transform = layerRotate; // ここだけがlayer変形の適用箇所
|
|
286
|
+
}
|
|
287
|
+
// キーコンフィグ表示用の矢印・おにぎりを表示
|
|
288
|
+
multiAppend(keyGroup,
|
|
289
|
+
// 矢印の塗り部分
|
|
290
|
+
createColorObject2(`arrowShadow${j}`, {
|
|
291
|
+
background: hasVal(g_headerObj[`setShadowColor${g_colorType}`][colorPos]) ? getShadowColor(colorPos, arrowColor) : ``,
|
|
292
|
+
rotate: g_keyObj[`stepRtn${keyCtrlPtn}_${g_keycons.stepRtnGroupNum}`][j], styleName: `Shadow`,
|
|
293
|
+
}),
|
|
294
|
+
// 矢印本体
|
|
295
|
+
createColorObject2(`arrow${j}`, {
|
|
296
|
+
background: arrowColor, rotate: g_keyObj[`stepRtn${keyCtrlPtn}_${g_keycons.stepRtnGroupNum}`][j],
|
|
297
|
+
}),
|
|
298
|
+
);
|
|
299
|
+
if (g_headerObj.shuffleUse && g_keyObj[`shuffle${keyCtrlPtn}`] !== undefined) {
|
|
300
|
+
keyconSprite.appendChild(
|
|
301
|
+
createCss2Button(`sArrow${j}`, ``, () => changeTmpShuffleNum(j), {
|
|
302
|
+
x: keyconX, y: keyconY - 12, w: C_ARW_WIDTH, h: 15, siz: 12, fontWeight: `bold`,
|
|
303
|
+
pointerEvents: (g_settings.shuffles.filter(val => val.endsWith(`+`)).length > 0 ? C_DIS_AUTO : C_DIS_NONE),
|
|
304
|
+
cxtFunc: () => changeTmpShuffleNum(j, -1),
|
|
305
|
+
}, g_cssObj.button_Default_NoColor, g_cssObj.title_base)
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
if (g_isDebug) {
|
|
309
|
+
keyconSprite.appendChild(
|
|
310
|
+
createDivCss2Label(`arrowChara${j}`, g_keyObj[`chara${keyCtrlPtn}`][j], {
|
|
311
|
+
x: keyconX, y: keyconY + 40, w: C_ARW_WIDTH, h: 10, siz: 10, align: C_ALIGN_CENTER,
|
|
312
|
+
background: g_headerObj.baseBrightFlg ? `rgba(255,255,255,0.5)` : `rgba(0,0,0,0.5)`,
|
|
313
|
+
}, g_cssObj.title_base)
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// 割り当て先のキー名を表示
|
|
318
|
+
for (let k = 0; k < g_keyObj[`keyCtrl${keyCtrlPtn}`][j].length; k++) {
|
|
319
|
+
g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k] = setIntVal(g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k]);
|
|
320
|
+
g_keyObj[`keyCtrl${keyCtrlPtn}d`][j][k] = setIntVal(g_keyObj[`keyCtrl${keyCtrlPtn}d`][j][k]);
|
|
321
|
+
|
|
322
|
+
keyconSprite.appendChild(
|
|
323
|
+
createCss2Button(`keycon${j}_${k}`, g_kCd[g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k]], () => {
|
|
324
|
+
g_currentj = j;
|
|
325
|
+
g_currentk = k;
|
|
326
|
+
g_prevKey = -1;
|
|
327
|
+
selectedKc = `Default`;
|
|
328
|
+
g_keycons.cursorNum = g_keycons.cursorNumList.findIndex(val => val === g_currentj);
|
|
329
|
+
setKeyConfigCursor();
|
|
330
|
+
}, {
|
|
331
|
+
x: keyconX - 5, y: 50 + C_KYC_REPHEIGHT * k + keyconY,
|
|
332
|
+
w: C_ARW_WIDTH + 10, h: C_KYC_REPHEIGHT, siz: g_limitObj.keySetSiz,
|
|
333
|
+
}, g_cssObj.button_Default_NoColor, g_cssObj.title_base)
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
// キーに色付け
|
|
337
|
+
if (g_keyObj[`keyCtrl${keyCtrlPtn}d`][j][k] !== g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k]) {
|
|
338
|
+
changeKeyConfigColor(j, k, g_cssObj.keyconfig_Changekey);
|
|
339
|
+
} else if (g_keyObj.currentPtn === -1) {
|
|
340
|
+
changeKeyConfigColor(j, k, g_cssObj.keyconfig_Defaultkey);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const posj = g_keyObj[`pos${keyCtrlPtn}`][0];
|
|
345
|
+
|
|
346
|
+
// カーソルの作成
|
|
347
|
+
const cursor = keyconSprite.appendChild(createImg(`cursor`, g_imgObj.cursor,
|
|
348
|
+
(kWidth - C_ARW_WIDTH) / 2 + g_keyObj.blank * (posj - divideCnt / 2) - 10, 57, 15, 30));
|
|
349
|
+
cursor.style.transitionDuration = `0.125s`;
|
|
350
|
+
|
|
351
|
+
const viewGroupObj = {
|
|
352
|
+
shuffle: (_type = ``) => {
|
|
353
|
+
if (g_keyObj[`shuffle${keyCtrlPtn}`] !== undefined) {
|
|
354
|
+
for (let j = 0; j < keyNum; j++) {
|
|
355
|
+
document.getElementById(`sArrow${j}`).textContent = g_keyObj[`shuffle${keyCtrlPtn}${_type}`][j] + 1;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
color: (_type = ``) => {
|
|
360
|
+
for (let j = 0; j < keyNum; j++) {
|
|
361
|
+
const colorPos = g_keyObj[`color${keyCtrlPtn}${_type}`][j];
|
|
362
|
+
const arrowColor = getKeyConfigColor(j, colorPos);
|
|
363
|
+
$id(`arrow${j}`).background = arrowColor;
|
|
364
|
+
$id(`arrowShadow${j}`).background = hasVal(g_headerObj.setShadowColor[colorPos]) ?
|
|
365
|
+
getShadowColor(colorPos, arrowColor) : ``;
|
|
366
|
+
if (g_headerObj.setShadowColor[colorPos] === `Default`) {
|
|
367
|
+
$id(`arrowShadow${j}`).opacity = 0.5;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
stepRtn: (_type = ``) => { },
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* カラー・シャッフルグループ設定の表示
|
|
376
|
+
* - シャッフルグループではデフォルトからの差異表示もここで行う
|
|
377
|
+
* @param {string} _type
|
|
378
|
+
*/
|
|
379
|
+
const viewGroup = _type => {
|
|
380
|
+
if (g_headerObj[`${_type}Use`]) {
|
|
381
|
+
const num = g_keycons[`${_type}GroupNum`] === -1 ? g_keycons.groupSelf : g_keycons[`${_type}GroupNum`] + 1;
|
|
382
|
+
if (document.getElementById(`lnk${toCapitalize(_type)}Group`) !== null) {
|
|
383
|
+
document.getElementById(`lnk${toCapitalize(_type)}Group`).textContent = getStgDetailName(num);
|
|
384
|
+
}
|
|
385
|
+
viewGroupObj[_type](`_${g_keycons[`${_type}GroupNum`]}`);
|
|
386
|
+
|
|
387
|
+
if (_type === `shuffle`) {
|
|
388
|
+
changeShuffleConfigColor(keyCtrlPtn, g_keyObj[`shuffle${keyCtrlPtn}_${g_keycons.shuffleGroupNum}`]);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
/**
|
|
393
|
+
* カラー・シャッフルグループ設定
|
|
394
|
+
* @param {string} _type
|
|
395
|
+
* @param {number} [_scrollNum=1]
|
|
396
|
+
*/
|
|
397
|
+
const setGroup = (_type, _scrollNum = 1) => {
|
|
398
|
+
g_keycons[`${_type}GroupNum`] = g_keycons[`${_type}Groups`][getNextNum(_scrollNum, `${_type}Groups`, g_keycons[`${_type}GroupNum`])];
|
|
399
|
+
g_keyObj[`${_type}${keyCtrlPtn}`] = structuredClone(g_keyObj[`${_type}${keyCtrlPtn}_${g_keycons[`${_type}GroupNum`]}`]);
|
|
400
|
+
viewGroup(_type);
|
|
401
|
+
if (_type === `stepRtn`) {
|
|
402
|
+
keyConfigInit(g_kcType);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* キーコンフィグ用設定ラベル
|
|
408
|
+
* @param {string} _id
|
|
409
|
+
* @param {string} _name
|
|
410
|
+
* @param {number} [object.x=g_btnX(5 / 6)]
|
|
411
|
+
* @param {number} [object.y=0]
|
|
412
|
+
* @param {number} [object.w=g_btnWidth(1 / 6)]
|
|
413
|
+
* @param {number} [object.h=20]
|
|
414
|
+
* @param {number} [object.siz=12]
|
|
415
|
+
* @param {string} [object.align='left']
|
|
416
|
+
* @param {...any} [object.rest]
|
|
417
|
+
* @param {...any} _classes
|
|
418
|
+
* @returns {HTMLDivElement}
|
|
419
|
+
*/
|
|
420
|
+
const makeKCButtonHeader = (_id, _name, {
|
|
421
|
+
x = g_btnX(5 / 6) - 30, y = 0, w = g_btnWidth(1 / 6), h = 20, siz = 12, align = C_ALIGN_LEFT, ...rest
|
|
422
|
+
} = {}, ..._classes) => createDivCss2Label(_id, g_lblNameObj[_name], { x, y, w, h, siz, align, ...rest }, ..._classes);
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* キーコンフィグ用設定ボタン
|
|
426
|
+
* @param {string} _id
|
|
427
|
+
* @param {string} _text
|
|
428
|
+
* @param {Function} _func
|
|
429
|
+
* @param {number} [object.x=g_btnX(5 / 6) - 20]
|
|
430
|
+
* @param {number} [object.y=15]
|
|
431
|
+
* @param {number} [object.w=g_btnWidth(1 / 6)]
|
|
432
|
+
* @param {number} [object.h=18]
|
|
433
|
+
* @param {number} [object.siz=g_limitObj.jdgCntsSiz]
|
|
434
|
+
* @param {string} [object.borderStyle='solid']
|
|
435
|
+
* @param {Function} [object.cxtFunc]
|
|
436
|
+
* @param {...any} [object.rest]
|
|
437
|
+
* @param {string} [_mainClass=g_cssObj.button_RevOFF]
|
|
438
|
+
* @param {...any} _classes
|
|
439
|
+
* @returns {HTMLDivElement}
|
|
440
|
+
*/
|
|
441
|
+
const makeKCButton = (_id, _text, _func, { x = g_btnX(5 / 6) - 20, y = 15, w = g_btnWidth(1 / 6), h = 18,
|
|
442
|
+
siz = g_limitObj.jdgCntsSiz, borderStyle = C_DIS_NONE, cxtFunc, ...rest } = {}, _mainClass = g_cssObj.button_RevOFF, ..._classes) =>
|
|
443
|
+
makeSettingLblCssButton(_id, getStgDetailName(_text), 0, _func, { x, y, w, h, siz, cxtFunc, borderStyle, ...rest }, _mainClass, ..._classes);
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* キーコンフィグ用ミニボタン
|
|
447
|
+
* @param {string} _id
|
|
448
|
+
* @param {string} _directionFlg
|
|
449
|
+
* @param {Function} _func
|
|
450
|
+
* @param {number} [object.x=g_btnX(5 / 6) - 30]
|
|
451
|
+
* @param {number} [object.y=15]
|
|
452
|
+
* @param {number} [object.w=15]
|
|
453
|
+
* @param {number} [object.h=20]
|
|
454
|
+
* @param {number} [object.siz=g_limitObj.mainSiz]
|
|
455
|
+
*/
|
|
456
|
+
const makeMiniKCButton = (_id, _directionFlg, _func, { x = g_btnX(5 / 6) - 30, y = 15, w = 15, h = 20, siz = g_limitObj.mainSiz } = {}) =>
|
|
457
|
+
createCss2Button(`${_id}${_directionFlg}`, g_settingBtnObj.chara[_directionFlg], _func, { x, y, w, h, siz }, g_cssObj.button_Mini);
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* キーコンフィグ用グループ設定ラベル・ボタンの作成
|
|
461
|
+
* @param {string} _type
|
|
462
|
+
* @param {number} [object.baseX=g_btnX(5 / 6) - 20]
|
|
463
|
+
* @param {number} [object.baseY=0]
|
|
464
|
+
* @param {string} [object.cssName]
|
|
465
|
+
*/
|
|
466
|
+
const makeGroupButton = (_type, { baseX = g_btnX(5 / 6) - 20, baseY = 0, cssName } = {}) => {
|
|
467
|
+
if (g_headerObj[`${_type}Use`] && g_keycons[`${_type}Groups`].length > 1) {
|
|
468
|
+
const typeName = toCapitalize(_type);
|
|
469
|
+
multiAppend(divRoot,
|
|
470
|
+
makeKCButtonHeader(`lbl${_type}Group`, `${typeName}Group`, { x: baseX - 10, y: baseY }, cssName),
|
|
471
|
+
makeKCButton(`lnk${typeName}Group`, ``, () => setGroup(_type), {
|
|
472
|
+
x: baseX, y: baseY + 13, w: g_btnWidth(1 / 18), title: g_msgObj[`${_type}Group`], cxtFunc: () => setGroup(_type, -1),
|
|
473
|
+
}),
|
|
474
|
+
makeMiniKCButton(`lnk${typeName}Group`, `L`, () => setGroup(_type, -1), { x: baseX - 10, y: baseY + 13 }),
|
|
475
|
+
makeMiniKCButton(`lnk${typeName}Group`, `R`, () => setGroup(_type), { x: baseX + g_btnWidth(1 / 18), y: baseY + 13 }),
|
|
476
|
+
);
|
|
477
|
+
} else {
|
|
478
|
+
g_keycons[`${_type}GroupNum`] = 0;
|
|
479
|
+
}
|
|
480
|
+
viewGroup(_type);
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const kcSubX = parseFloat(keyconSprite.style.width) * ((1 - g_keyObj.scale) / 4);
|
|
484
|
+
const kcSubY = parseFloat(keyconSprite.style.height) / ((1 + g_keyObj.scale) / 2) - parseFloat(keyconSprite.style.height);
|
|
485
|
+
multiAppend(divRoot,
|
|
486
|
+
|
|
487
|
+
// ショートカットキーメッセージ
|
|
488
|
+
createDescDiv(`scMsg`, g_lblNameObj.kcShortcutDesc, { altId: `scKcMsg` }),
|
|
489
|
+
|
|
490
|
+
// タイトルバックのショートカットキー変更
|
|
491
|
+
createCss2Button(`scTitleBack`, getScMsg.TitleBack(), () => {
|
|
492
|
+
if (!g_isMac) {
|
|
493
|
+
cursor.style.left = wUnit(g_btnX(1 / 4) - kcSubX);
|
|
494
|
+
cursor.style.top = wUnit(g_sHeight - 160 + kcSubY);
|
|
495
|
+
selectedKc = `TitleBack`;
|
|
496
|
+
}
|
|
497
|
+
}, g_lblPosObj.scTitleBack, g_cssObj.button_Default_NoColor,
|
|
498
|
+
g_headerObj.keyTitleBack === g_headerObj.keyTitleBackDef2 ?
|
|
499
|
+
g_cssObj.title_base : g_cssObj.keyconfig_Changekey),
|
|
500
|
+
|
|
501
|
+
// リトライのショートカットキー変更
|
|
502
|
+
createCss2Button(`scRetry`, getScMsg.Retry(), () => {
|
|
503
|
+
cursor.style.left = wUnit(g_btnX(1 / 2) + kcSubX);
|
|
504
|
+
cursor.style.top = wUnit(g_sHeight - 160 + kcSubY);
|
|
505
|
+
selectedKc = `Retry`;
|
|
506
|
+
}, g_lblPosObj.scRetry, g_cssObj.button_Default_NoColor,
|
|
507
|
+
g_headerObj.keyRetry === g_headerObj.keyRetryDef2 ?
|
|
508
|
+
g_cssObj.title_base : g_cssObj.keyconfig_Changekey),
|
|
509
|
+
|
|
510
|
+
// ポーズのショートカットキー変更
|
|
511
|
+
createCss2Button(`scPause`, getScMsg.Pause(), () => {
|
|
512
|
+
cursor.style.left = wUnit(g_btnX(3 / 4) + kcSubX);
|
|
513
|
+
cursor.style.top = wUnit(g_sHeight - 160 + kcSubY);
|
|
514
|
+
selectedKc = `Pause`;
|
|
515
|
+
}, g_lblPosObj.scPause, g_cssObj.button_Default_NoColor,
|
|
516
|
+
g_headerObj.keyPause === g_headerObj.keyPauseDef2 ?
|
|
517
|
+
g_cssObj.title_base : g_cssObj.keyconfig_Changekey),
|
|
518
|
+
|
|
519
|
+
// 別キーモード警告メッセージ
|
|
520
|
+
createDivCss2Label(
|
|
521
|
+
`kcMsg`,
|
|
522
|
+
hasVal(g_keyObj[`transKey${keyCtrlPtn}`]) ? g_lblNameObj.transKeyDesc : ``,
|
|
523
|
+
g_lblPosObj.kcMsg, g_cssObj.keyconfig_warning
|
|
524
|
+
),
|
|
525
|
+
// ColorType警告メッセージ
|
|
526
|
+
createDivCss2Label(
|
|
527
|
+
`kcMsg2`,
|
|
528
|
+
g_keycons.colorDefTypes.includes(g_colorType) ? `` : g_lblNameObj.colorTypeDesc,
|
|
529
|
+
g_lblPosObj.kcMsg2, g_cssObj.keyconfig_Defaultkey
|
|
530
|
+
),
|
|
531
|
+
|
|
532
|
+
// キーカラータイプ切替ボタン
|
|
533
|
+
makeKCButtonHeader(`lblcolorType`, `ColorType`, { x: 10 + g_btnX() }, g_cssObj.keyconfig_ColorType),
|
|
534
|
+
makeKCButton(`lnkColorType`, g_colorType, () => setColorType(), {
|
|
535
|
+
x: 20 + g_btnX(), title: g_msgObj.colorType, cxtFunc: () => setColorType(-1),
|
|
536
|
+
}),
|
|
537
|
+
makeMiniKCButton(`lnkColorType`, `L`, () => setColorType(-1), { x: 10 + g_btnX() }),
|
|
538
|
+
makeMiniKCButton(`lnkColorType`, `R`, () => setColorType(), { x: 20 + g_btnX(1 / 6) }),
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
if (g_headerObj.imgType.length > 1) {
|
|
542
|
+
const [imgBaseX, imgBaseY] = [20 + g_btnX(), 50];
|
|
543
|
+
multiAppend(divRoot,
|
|
544
|
+
// オブジェクトタイプの切り替え(リロードあり)
|
|
545
|
+
makeKCButtonHeader(`lblImgType`, `ImgType`, { x: imgBaseX - 10, y: 37 }, g_cssObj.keyconfig_ConfigType),
|
|
546
|
+
makeKCButton(`lnkImgType`, g_imgType, () => setImgType(), {
|
|
547
|
+
x: imgBaseX, y: imgBaseY, title: g_msgObj.imgType, cxtFunc: () => setImgType(-1),
|
|
548
|
+
}),
|
|
549
|
+
makeMiniKCButton(`lnkImgType`, `L`, () => setImgType(-1), { x: imgBaseX - 10, y: imgBaseY }),
|
|
550
|
+
makeMiniKCButton(`lnkImgType`, `R`, () => setImgType(), { x: imgBaseX + g_btnWidth(1 / 6), y: imgBaseY }),
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// カラー/シャッフルグループ切替ボタン(カラー/シャッフルパターンが複数ある場合のみ)
|
|
555
|
+
makeGroupButton(`color`, { cssName: g_cssObj.keyconfig_ColorGr });
|
|
556
|
+
makeGroupButton(`shuffle`, { baseX: g_btnX(11 / 12) - 10, cssName: g_cssObj.keyconfig_ShuffleGr });
|
|
557
|
+
makeGroupButton(`stepRtn`, { baseY: 37, cssName: g_cssObj.keyconfig_StepRtnGr });
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* カーソル位置の設定
|
|
561
|
+
*/
|
|
562
|
+
const setKeyConfigCursor = () => {
|
|
563
|
+
const posj = g_keyObj[`pos${keyCtrlPtn}`][g_currentj];
|
|
564
|
+
const stdPos = posj - ((posj > divideCnt ? posMax : 0) + divideCnt) / 2;
|
|
565
|
+
const baseLayer = g_keyObj[`layerGroup${keyCtrlPtn}`]?.[g_currentj] || 0;
|
|
566
|
+
|
|
567
|
+
const nextLeft = (kWidth - C_ARW_WIDTH) / 2 + g_keyObj.blank * stdPos + addLeft - 10;
|
|
568
|
+
cursor.style.left = wUnit(nextLeft);
|
|
569
|
+
cursor.style.top = wUnit(C_KYC_HEIGHT * Number(posj > divideCnt) + 57 + C_KYC_REPHEIGHT * g_currentk + baseLayer * C_LAYER_Y_OFFSET);
|
|
570
|
+
g_kcType = (g_currentk === 0 ? `Main` : `Replaced`);
|
|
571
|
+
|
|
572
|
+
// 次の位置が見えなくなったらkeyconSpriteの位置を調整する
|
|
573
|
+
adjustScrollPoint(nextLeft);
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* カーソル位置の変更
|
|
578
|
+
* @param {number} [_nextj] 次のカーソル位置
|
|
579
|
+
*/
|
|
580
|
+
const changeConfigCursor = (_nextj = ++g_keycons.cursorNum % g_keycons.cursorNumList.length) => {
|
|
581
|
+
g_keycons.cursorNum = _nextj;
|
|
582
|
+
|
|
583
|
+
g_currentj = g_keycons.cursorNumList[_nextj];
|
|
584
|
+
g_currentk = 0;
|
|
585
|
+
if (g_kcType === `Replaced`) {
|
|
586
|
+
g_currentk = 1;
|
|
587
|
+
|
|
588
|
+
// 代替キー設定の場合は次の代替キーが見つかるまで移動
|
|
589
|
+
while (g_keyObj[`keyCtrl${keyCtrlPtn}`][g_currentj][1] === undefined) {
|
|
590
|
+
g_keycons.cursorNum = (g_keycons.cursorNum + 1) % g_keycons.cursorNumList.length;
|
|
591
|
+
g_currentj = g_keycons.cursorNumList[g_keycons.cursorNum];
|
|
592
|
+
|
|
593
|
+
// 一周して対象が無い場合は代替キーが無いため処理を抜ける(無限ループ対策)
|
|
594
|
+
if (g_keycons.cursorNum === _nextj) {
|
|
595
|
+
g_kcType = `Main`;
|
|
596
|
+
g_currentk = 0;
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
setKeyConfigCursor();
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* 次のカーソル位置の取得
|
|
606
|
+
* @param {number} _scrollNum
|
|
607
|
+
* @param {string} _groupName
|
|
608
|
+
* @param {string} _target
|
|
609
|
+
* @returns {number}
|
|
610
|
+
*/
|
|
611
|
+
const getNextNum = (_scrollNum, _groupName, _target) =>
|
|
612
|
+
nextPos(g_keycons[_groupName].findIndex(value => value === _target), _scrollNum, g_keycons[_groupName].length);
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* ConfigTypeの制御
|
|
616
|
+
* @param {number} _scrollNum
|
|
617
|
+
*/
|
|
618
|
+
const setConfigType = (_scrollNum = 1) => {
|
|
619
|
+
g_kcType = g_keycons.configTypes[getNextNum(_scrollNum, `configTypes`, g_kcType)];
|
|
620
|
+
changeConfigCursor(g_keycons.cursorNum);
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* 一部のキーコンフィグを表示する
|
|
625
|
+
* (キーグループ毎にフィルターされたもののみを表示する)
|
|
626
|
+
* @param {number} _num
|
|
627
|
+
*/
|
|
628
|
+
const appearConfigSteps = _num => {
|
|
629
|
+
|
|
630
|
+
const appearConfigView = (_j, _display) => {
|
|
631
|
+
$id(`arrow${_j}`).display = _display;
|
|
632
|
+
$id(`arrowShadow${_j}`).display = _display;
|
|
633
|
+
$id(`color${_j}`).display = _display;
|
|
634
|
+
if (document.getElementById(`sArrow${_j}`) !== null) {
|
|
635
|
+
$id(`sArrow${_j}`).display = _display;
|
|
636
|
+
}
|
|
637
|
+
if (document.getElementById(`arrowChara${_j}`) !== null) {
|
|
638
|
+
$id(`arrowChara${_j}`).display = _display;
|
|
639
|
+
}
|
|
640
|
+
const ctrlPtn = g_keyObj[`keyCtrl${g_headerObj.keyLabels[g_stateObj.scoreId]}_${g_keyObj.currentPtn}`][_j];
|
|
641
|
+
for (let k = 0; k < ctrlPtn.length; k++) {
|
|
642
|
+
$id(`keycon${_j}_${k}`).display = _display;
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
g_keycons.keySwitchNum = _num;
|
|
647
|
+
g_keycons.cursorNumList = [];
|
|
648
|
+
for (let j = 0; j < keyNum; j++) {
|
|
649
|
+
appearConfigView(j, C_DIS_NONE);
|
|
650
|
+
|
|
651
|
+
if (tkObj.keyGroupMaps[j].includes(configKeyGroupList[_num])) {
|
|
652
|
+
g_keycons.cursorNumList.push(j);
|
|
653
|
+
appearConfigView(j, C_DIS_INHERIT);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (g_keycons.cursorNumList.length === 0) {
|
|
657
|
+
makeInfoWindow(g_msgInfoObj.I_0011, ``);
|
|
658
|
+
} else {
|
|
659
|
+
changeConfigCursor(0);
|
|
660
|
+
|
|
661
|
+
// keySwitchボタンを一旦非選択にして、選択中のものを再度色付け
|
|
662
|
+
if (configKeyGroupList.length > 1) {
|
|
663
|
+
for (let j = 0; j < configKeyGroupList.length; j++) {
|
|
664
|
+
document.getElementById(`key${j}`).classList.replace(g_cssObj.button_Next, g_cssObj.button_Mini);
|
|
665
|
+
}
|
|
666
|
+
document.getElementById(`key${_num}`).classList.replace(g_cssObj.button_Mini, g_cssObj.button_Next);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
keyconfigKeyboardPreview.refresh();
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* ColorPickerの色切替
|
|
674
|
+
* @param {number} _j
|
|
675
|
+
* @param {string} _type
|
|
676
|
+
* @param {string} _color
|
|
677
|
+
*/
|
|
678
|
+
const changeColorPicker = (_j, _type, _color) => {
|
|
679
|
+
if (_color !== ``) {
|
|
680
|
+
document.getElementById(`pick${_type}${_j}`).value = _color.slice(0, 7);
|
|
681
|
+
$id(`pick${_type}${_j}`).display = C_DIS_INHERIT;
|
|
682
|
+
} else {
|
|
683
|
+
$id(`pick${_type}${_j}`).display = C_DIS_NONE;
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* ColorPickerに対応する実際の番号を取得
|
|
689
|
+
* @param {number} _j
|
|
690
|
+
*/
|
|
691
|
+
const getGroupNum = _j => _j + g_keycons.colorCursorNum * g_limitObj.kcColorPickerNum;
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* ColorPicker(一式)の切替
|
|
695
|
+
*/
|
|
696
|
+
const changeColorPickers = () => {
|
|
697
|
+
lnkColorR.textContent = `[${g_keycons.colorCursorNum + 1} /`;
|
|
698
|
+
for (let j = 0; j < g_limitObj.kcColorPickerNum; j++) {
|
|
699
|
+
const m = getGroupNum(j);
|
|
700
|
+
changeColorPicker(j, `arrow`, g_headerObj.setColor[m]);
|
|
701
|
+
changeColorPicker(j, `arrowShadow`, g_headerObj.setShadowColor[m]);
|
|
702
|
+
changeColorPicker(j, `frz`, g_headerObj.frzColor[m][0]);
|
|
703
|
+
changeColorPicker(j, `frzBar`, g_headerObj.frzColor[m][1]);
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* ColorTypeの制御
|
|
709
|
+
* @param {number} [_scrollNum=1]
|
|
710
|
+
* @param {boolean} [_reloadFlg=true]
|
|
711
|
+
*/
|
|
712
|
+
const setColorType = (_scrollNum = 1, _reloadFlg = true) => {
|
|
713
|
+
const nextNum = getNextNum(_scrollNum, `colorTypes`, g_colorType);
|
|
714
|
+
g_colorType = g_keycons.colorTypes[nextNum];
|
|
715
|
+
const isDefault = g_keycons.colorDefTypes.includes(g_colorType);
|
|
716
|
+
if (g_headerObj.colorUse) {
|
|
717
|
+
g_stateObj.d_color = boolToSwitch(g_keycons.colorDefTypes.findIndex(val => val === g_colorType) !== -1);
|
|
718
|
+
}
|
|
719
|
+
changeSetColor();
|
|
720
|
+
viewGroupObj.color(`_${g_keycons.colorGroupNum}`);
|
|
721
|
+
lnkColorType.textContent = `${getStgDetailName(g_colorType)}${g_localStorage.colorType === g_colorType ? ' *' : ''}`;
|
|
722
|
+
kcMsg2.textContent = (isDefault || !g_headerObj.colorUse) ? `` : g_lblNameObj.colorTypeDesc;
|
|
723
|
+
kcMsg2.style.top = wUnit(hasVal(g_keyObj[`transKey${keyCtrlPtn}`]) ? g_lblPosObj.kcMsg2.y : g_lblPosObj.kcMsg.y);
|
|
724
|
+
kcMsg2.style.fontSize = wUnit(getFontSize2(kcMsg2.textContent, g_btnWidth()));
|
|
725
|
+
if (_reloadFlg) {
|
|
726
|
+
colorPickSprite.style.display = isDefault ? C_DIS_NONE : C_DIS_INHERIT;
|
|
727
|
+
g_keycons.colorCursorNum = g_keycons.colorCursorNum % Math.ceil(g_dfColorObj.setColorInit.length / g_limitObj.kcColorPickerNum);
|
|
728
|
+
changeColorPickers();
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* ImgTypeの制御
|
|
734
|
+
* @param {number} [_scrollNum=1]
|
|
735
|
+
*/
|
|
736
|
+
const setImgType = (_scrollNum = 1) => {
|
|
737
|
+
const nextNum = getNextNum(_scrollNum, `imgTypes`, g_imgType);
|
|
738
|
+
g_imgType = g_keycons.imgTypes[nextNum];
|
|
739
|
+
g_stateObj.rotateEnabled = g_headerObj.imgType[nextNum].rotateEnabled;
|
|
740
|
+
g_stateObj.flatStepHeight = g_headerObj.imgType[nextNum].flatStepHeight;
|
|
741
|
+
|
|
742
|
+
changeSettingListsForImg();
|
|
743
|
+
updateImgType(g_headerObj.imgType[nextNum]);
|
|
744
|
+
keyConfigInit(g_kcType);
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
const colorPickSprite = createEmptySprite(divRoot, `colorPickSprite`, { ...g_windowObj.colorPickSprite, title: g_msgObj.pickArrow });
|
|
748
|
+
if (g_keycons.colorDefTypes.includes(g_colorType)) {
|
|
749
|
+
colorPickSprite.style.display = C_DIS_NONE;
|
|
750
|
+
}
|
|
751
|
+
multiAppend(colorPickSprite,
|
|
752
|
+
|
|
753
|
+
// ColorPickerの切替
|
|
754
|
+
createCss2Button(`lnkColorR`, `[${g_keycons.colorCursorNum + 1} /`, () => {
|
|
755
|
+
g_keycons.colorCursorNum = (g_keycons.colorCursorNum + 1) % Math.ceil(g_dfColorObj.setColorInit.length / g_limitObj.kcColorPickerNum);
|
|
756
|
+
changeColorPickers();
|
|
757
|
+
}, g_lblPosObj.lnkColorR, g_cssObj.button_Start),
|
|
758
|
+
|
|
759
|
+
// 矢印の配色をフリーズアローへ反映
|
|
760
|
+
createCss2Button(`lnkColorCopy`, `↓]`, () => {
|
|
761
|
+
if (window.confirm(g_msgObj.colorCopyConfirm)) {
|
|
762
|
+
for (let j = 0; j < g_dfColorObj.setColorInit.length; j++) {
|
|
763
|
+
g_headerObj.frzColor[j] = g_headerObj[`frzColor${g_colorType}`][j] =
|
|
764
|
+
fillArray(g_headerObj[`frzColor${g_colorType}`][j].length, g_headerObj[`setColor${g_colorType}`][j]);
|
|
765
|
+
}
|
|
766
|
+
for (let j = 0; j < g_limitObj.kcColorPickerNum; j++) {
|
|
767
|
+
const m = getGroupNum(j);
|
|
768
|
+
[``, `Bar`].forEach((val, k) =>
|
|
769
|
+
document.getElementById(`pickfrz${val}${j}`).value = g_headerObj[`frzColor${g_colorType}`][m][k]);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}, g_lblPosObj.lnkColorCopy, g_cssObj.button_Start),
|
|
773
|
+
|
|
774
|
+
createDivCss2Label(`lblPickArrow`, g_lblNameObj.s_arrow, { ...g_lblPosObj.pickPos, y: 0 }),
|
|
775
|
+
createDivCss2Label(`lblPickFrz`, g_lblNameObj.s_frz, { ...g_lblPosObj.pickPos, y: 140 }),
|
|
776
|
+
|
|
777
|
+
// ColorPickerの色を元に戻す
|
|
778
|
+
createCss2Button(`lnkColorReset`, g_lblNameObj.b_cReset, () => {
|
|
779
|
+
if (window.confirm(g_msgObj.colorResetConfirm)) {
|
|
780
|
+
resetColorType({ _from: g_colorType, _to: ``, _fromObj: g_dfColorObj });
|
|
781
|
+
resetColorType({ _from: g_colorType, _to: g_colorType, _fromObj: g_dfColorObj });
|
|
782
|
+
|
|
783
|
+
// 影矢印が未指定の場合はType1, Type2の影矢印指定を無くす
|
|
784
|
+
const _idHeader = setScoreIdHeader(g_stateObj.scoreId, false, true);
|
|
785
|
+
const _shadowDefault = g_headerObj[`setShadowColor${_idHeader}Default`];
|
|
786
|
+
if ((!Array.isArray(_shadowDefault) || !hasVal(_shadowDefault[0])) &&
|
|
787
|
+
[`Type1`, `Type2`].includes(g_colorType)) {
|
|
788
|
+
|
|
789
|
+
g_headerObj.setShadowColor = fillArray(g_headerObj.setColorInit.length, ``);
|
|
790
|
+
g_headerObj[`setShadowColor${g_colorType}`] = fillArray(g_headerObj.setColorInit.length, ``);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
changeColorPickers();
|
|
794
|
+
viewGroupObj.color(`_${g_keycons.colorGroupNum}`);
|
|
795
|
+
}
|
|
796
|
+
}, g_lblPosObj.lnkColorReset, g_cssObj.button_Reset),
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* ColorPicker部分の作成
|
|
801
|
+
* @param {number} _j
|
|
802
|
+
* @param {string} _type
|
|
803
|
+
* @param {Function} _func
|
|
804
|
+
* @param {number} [object.x=0]
|
|
805
|
+
* @param {number} [object.y=15]
|
|
806
|
+
*/
|
|
807
|
+
const createColorPickWindow = (_j, _type, _func, { x = 0, y = 15 } = {}) =>
|
|
808
|
+
createColorPicker(colorPickSprite, `pick${_type}${_j}`, _func, { x, y: y + 25 * _j });
|
|
809
|
+
|
|
810
|
+
for (let j = 0; j < g_limitObj.kcColorPickerNum; j++) {
|
|
811
|
+
createColorPickWindow(j, `arrow`, () => {
|
|
812
|
+
g_headerObj[`setColor${g_colorType}`][getGroupNum(j)] = document.getElementById(`pickarrow${j}`).value;
|
|
813
|
+
setColorType(0, false);
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
createColorPickWindow(j, `arrowShadow`, () => {
|
|
817
|
+
g_headerObj[`setShadowColor${g_colorType}`][getGroupNum(j)] = `${document.getElementById(`pickarrowShadow${j}`).value}80`;
|
|
818
|
+
setColorType(0, false);
|
|
819
|
+
}, { x: 25 });
|
|
820
|
+
|
|
821
|
+
[``, `Bar`].forEach((val, k) =>
|
|
822
|
+
createColorPickWindow(j, `frz${val}`, () => {
|
|
823
|
+
g_headerObj[`frzColor${g_colorType}`][getGroupNum(j)][k] = document.getElementById(`pickfrz${val}${j}`).value;
|
|
824
|
+
}, { x: 25 * k, y: 155 }));
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// ConfigType, ColorTypeの初期設定
|
|
828
|
+
setConfigType(0);
|
|
829
|
+
setColorType(0);
|
|
830
|
+
keyconSprite.scrollLeft = - maxLeftX;
|
|
831
|
+
|
|
832
|
+
// キーパターン表示
|
|
833
|
+
const lblTransKey = hasVal(g_keyObj[`transKey${keyCtrlPtn}`]) ? `(${g_keyObj[`transKey${keyCtrlPtn}`] ?? ''})` : ``;
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* キーパターン検索
|
|
837
|
+
* @param {number} _tempPtn
|
|
838
|
+
* @param {number} _sign
|
|
839
|
+
* @param {boolean} [_transKeyUse=false]
|
|
840
|
+
* @param {boolean} [_skipFlg=false]
|
|
841
|
+
*/
|
|
842
|
+
const searchPattern = (_tempPtn, _sign, _transKeyUse = false, _skipFlg = false) => {
|
|
843
|
+
let nextPtn = _tempPtn + _sign;
|
|
844
|
+
const initialPtn = hasVal(g_keyObj[`keyCtrl${g_keyObj.currentKey}_-1`]) ? -1 : 0;
|
|
845
|
+
|
|
846
|
+
const searchStart = () => {
|
|
847
|
+
if (!hasVal(g_keyObj[`keyCtrl${g_keyObj.currentKey}_${nextPtn}`])) {
|
|
848
|
+
nextPtn = 0;
|
|
849
|
+
while (hasVal(g_keyObj[`keyCtrl${g_keyObj.currentKey}_${nextPtn}`])) {
|
|
850
|
+
nextPtn -= _sign;
|
|
851
|
+
}
|
|
852
|
+
nextPtn += _sign;
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
const searchNextGroup = () => {
|
|
857
|
+
while (nextPtn !== initialPtn &&
|
|
858
|
+
g_keyObj[`transKey${g_keyObj.currentKey}_${_tempPtn}`] === g_keyObj[`transKey${g_keyObj.currentKey}_${nextPtn}`] &&
|
|
859
|
+
hasVal(g_keyObj[`keyCtrl${g_keyObj.currentKey}_${nextPtn}`])) {
|
|
860
|
+
nextPtn += _sign;
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
searchStart();
|
|
865
|
+
if (_skipFlg) {
|
|
866
|
+
searchNextGroup();
|
|
867
|
+
searchStart();
|
|
868
|
+
}
|
|
869
|
+
if (!_transKeyUse) {
|
|
870
|
+
while (hasVal(g_keyObj[`transKey${g_keyObj.currentKey}_${nextPtn}`])) {
|
|
871
|
+
nextPtn += _sign;
|
|
872
|
+
}
|
|
873
|
+
searchStart();
|
|
874
|
+
}
|
|
875
|
+
return nextPtn;
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* キーパターン変更時処理
|
|
880
|
+
* @param {number} [_sign=1]
|
|
881
|
+
* @param {boolean} [_skipFlg=false]
|
|
882
|
+
*/
|
|
883
|
+
const changePattern = (_sign = 1, _skipFlg = false) => {
|
|
884
|
+
|
|
885
|
+
// キーパターンの変更
|
|
886
|
+
g_keyObj.currentPtn = searchPattern(g_keyObj.currentPtn, _sign, g_headerObj.transKeyUse, _skipFlg);
|
|
887
|
+
|
|
888
|
+
// カラーグループ、シャッフルグループの再設定
|
|
889
|
+
g_keycons.groups.forEach(type => resetGroupList(type, `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`));
|
|
890
|
+
|
|
891
|
+
// 曲中ショートカットキーの切り替え
|
|
892
|
+
setPlayingShortcut();
|
|
893
|
+
|
|
894
|
+
// キーコンフィグ画面を再呼び出し
|
|
895
|
+
keyConfigInit();
|
|
896
|
+
|
|
897
|
+
// シャッフルグループのデフォルト値からの差異表示(色付け)
|
|
898
|
+
// 再描画後で無いと色付けできないため、keyConfigInit() 実行後に処理
|
|
899
|
+
if (g_headerObj.shuffleUse) {
|
|
900
|
+
changeShuffleConfigColor(`${g_keyObj.currentKey}_${g_keyObj.currentPtn}`, g_keyObj[`shuffle${g_keyObj.currentKey}_${g_keyObj.currentPtn}_${g_keycons.shuffleGroupNum}`]);
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
// ユーザカスタムイベント(初期)
|
|
905
|
+
safeExecuteCustomHooks(`g_customJsObj.keyconfig`, g_customJsObj.keyconfig);
|
|
906
|
+
|
|
907
|
+
// 部分キー表示用ボタン描画
|
|
908
|
+
if (configKeyGroupList.length > 1) {
|
|
909
|
+
multiAppend(divRoot,
|
|
910
|
+
createDivCss2Label(`lblkey`, `KeySwitch`, g_lblPosObj.lblkey));
|
|
911
|
+
configKeyGroupList.forEach((val, j) =>
|
|
912
|
+
divRoot.appendChild(
|
|
913
|
+
createCss2Button(`key${j}`, `${j + 1}`, () => appearConfigSteps(j),
|
|
914
|
+
{ ...g_lblPosObj.lnkKeySwitch, y: 110 + j * 20 }, g_cssObj.button_Mini),
|
|
915
|
+
));
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// カーソル位置の初期化
|
|
919
|
+
appearConfigSteps(g_keycons.keySwitchNum);
|
|
920
|
+
|
|
921
|
+
keyconfigKeyboardPreview.dispose();
|
|
922
|
+
keyconfigKeyboardPreview.init(divRoot);
|
|
923
|
+
|
|
924
|
+
// ラベル・ボタン描画
|
|
925
|
+
multiAppend(divRoot,
|
|
926
|
+
|
|
927
|
+
// 設定画面へ戻る
|
|
928
|
+
createCss2Button(`btnBack`, g_lblNameObj.b_settings, () => {
|
|
929
|
+
g_currentj = 0;
|
|
930
|
+
g_currentk = 0;
|
|
931
|
+
g_prevKey = 0;
|
|
932
|
+
}, {
|
|
933
|
+
...g_lblPosObj.btnKcBack, resetFunc: () => {
|
|
934
|
+
keyconfigKeyboardPreview.dispose();
|
|
935
|
+
g_moveSettingWindow(false);
|
|
936
|
+
}
|
|
937
|
+
}, g_cssObj.button_Back),
|
|
938
|
+
|
|
939
|
+
createDivCss2Label(`lblPattern`, `${g_lblNameObj.KeyPattern}: ${g_keyObj.currentPtn === -1 ?
|
|
940
|
+
'Self' : g_keyObj.currentPtn + 1}${lblTransKey}`, g_lblPosObj.lblPattern),
|
|
941
|
+
|
|
942
|
+
// パターン変更ボタン描画(右回り)
|
|
943
|
+
createCss2Button(`btnPtnChangeR`, `>`, () => true, {
|
|
944
|
+
...g_lblPosObj.btnPtnChangeR, resetFunc: () => changePattern(),
|
|
945
|
+
}, g_cssObj.button_Mini),
|
|
946
|
+
|
|
947
|
+
// パターン変更ボタン描画(左回り)
|
|
948
|
+
createCss2Button(`btnPtnChangeL`, `<`, () => true, {
|
|
949
|
+
...g_lblPosObj.btnPtnChangeL, resetFunc: () => changePattern(-1),
|
|
950
|
+
}, g_cssObj.button_Mini),
|
|
951
|
+
|
|
952
|
+
// パターン変更ボタン描画(右回り/別キーモード間スキップ)
|
|
953
|
+
createCss2Button(`btnPtnChangeRR`, `|>`, () => true, {
|
|
954
|
+
...g_lblPosObj.btnPtnChangeRR, resetFunc: () => changePattern(1, true),
|
|
955
|
+
}, g_cssObj.button_Setting),
|
|
956
|
+
|
|
957
|
+
// パターン変更ボタン描画(左回り/別キーモード間スキップ)
|
|
958
|
+
createCss2Button(`btnPtnChangeLL`, `<|`, () => true, {
|
|
959
|
+
...g_lblPosObj.btnPtnChangeLL, resetFunc: () => changePattern(-1, true),
|
|
960
|
+
}, g_cssObj.button_Setting),
|
|
961
|
+
|
|
962
|
+
// キーコンフィグリセットボタン描画
|
|
963
|
+
createCss2Button(`btnReset`, g_lblNameObj.b_reset, () => {
|
|
964
|
+
if (window.confirm(g_msgObj.keyResetConfirm)) {
|
|
965
|
+
const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
|
|
966
|
+
|
|
967
|
+
for (let m = 0; m < g_keycons.cursorNumList.length; m++) {
|
|
968
|
+
const j = g_keycons.cursorNumList[m];
|
|
969
|
+
for (let k = 0; k < g_keyObj[`keyCtrl${keyCtrlPtn}`][j].length; k++) {
|
|
970
|
+
g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k] = setIntVal(g_keyObj[`keyCtrl${keyCtrlPtn}d`][j][k]);
|
|
971
|
+
document.getElementById(`keycon${j}_${k}`).textContent = g_kCd[g_keyObj[`keyCtrl${keyCtrlPtn}`][j][k]];
|
|
972
|
+
changeKeyConfigColor(j, k, g_keyObj.currentPtn === -1 ? g_cssObj.keyconfig_Defaultkey : g_cssObj.title_base);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
changeConfigCursor(0);
|
|
976
|
+
}
|
|
977
|
+
}, g_lblPosObj.btnKcReset, g_cssObj.button_Reset),
|
|
978
|
+
|
|
979
|
+
createCss2Button(`btnKeyLock`, getKeyLockName(), () => {
|
|
980
|
+
g_stateObj.keyLockFlg = !g_stateObj.keyLockFlg;
|
|
981
|
+
makeInfoWindow(g_msgInfoObj.I_0012.split(`{0}`).join(boolToSwitch(!g_stateObj.keyLockFlg)), `leftToRightFade`);
|
|
982
|
+
toggleKcDesc();
|
|
983
|
+
}, g_lblPosObj.btnKcKeyLock, g_cssObj.button_Mini),
|
|
984
|
+
|
|
985
|
+
// プレイ開始
|
|
986
|
+
makePlayButton(() => loadMusic())
|
|
987
|
+
);
|
|
988
|
+
toggleKcDesc();
|
|
989
|
+
|
|
990
|
+
// Selfパターン取込ボタン(条件成立時のみ表示)
|
|
991
|
+
const keyCtrlPtnForSelf = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
|
|
992
|
+
if (getTransKeySelfCtrl(keyCtrlPtnForSelf) !== undefined) {
|
|
993
|
+
divRoot.appendChild(
|
|
994
|
+
createCss2Button(`btnPtnSelf`, `Self`, () => applyTransKeySelfPattern(), {
|
|
995
|
+
x: g_lblPosObj.lblPattern.x + g_lblPosObj.lblPattern.w - 50,
|
|
996
|
+
y: g_lblPosObj.lblPattern.y - 14,
|
|
997
|
+
w: 50, h: 14, siz: 10, title: g_msgObj.ptnSelfImport,
|
|
998
|
+
}, g_cssObj.button_Mini)
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// キーボード押下時処理
|
|
1003
|
+
setShortcutEvent(g_currentPage, (kbCode) => {
|
|
1004
|
+
const C_KEY_ESCAPE = 27;
|
|
1005
|
+
const C_KEY_IME = 229;
|
|
1006
|
+
const keyCdObj = document.getElementById(`keycon${g_currentj}_${g_currentk}`);
|
|
1007
|
+
let setKey = g_kCdN.findIndex(kCd => kCd === kbCode);
|
|
1008
|
+
|
|
1009
|
+
if (g_stateObj.keyLockFlg) {
|
|
1010
|
+
if (setKey === C_KEY_ESCAPE) {
|
|
1011
|
+
btnBack.click();
|
|
1012
|
+
}
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// 全角切替、BackSpace、Deleteキー、Escキーは割り当て禁止
|
|
1017
|
+
// また、直前と同じキーを押した場合(BackSpaceを除く)はキー操作を無効にする
|
|
1018
|
+
const disabledKeys = [240, 242, 243, 244, 91, 29, 28, 259, g_prevKey];
|
|
1019
|
+
|
|
1020
|
+
if (g_localeObj.val === `Ja`) {
|
|
1021
|
+
disabledKeys.unshift(C_KEY_IME);
|
|
1022
|
+
}
|
|
1023
|
+
if (disabledKeys.includes(setKey) || g_kCdN[setKey] === undefined) {
|
|
1024
|
+
makeInfoWindow(g_msgInfoObj.I_0002, `fadeOut0`);
|
|
1025
|
+
return;
|
|
1026
|
+
} else if ((keyIsDown(g_kCdNameObj.metaLKey) || keyIsDown(g_kCdNameObj.metaRKey)) && keyIsShift()) {
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (selectedKc === `TitleBack` || selectedKc === `Retry` || selectedKc === `Pause`) {
|
|
1030
|
+
// タイトルバックキー、リトライキー、ポーズキーはプレイ中の操作キーと重複しないようにする(簡易的)
|
|
1031
|
+
if (g_keyObj[`keyCtrl${keyCtrlPtn}`].flat().includes(setKey)) {
|
|
1032
|
+
makeInfoWindow(g_msgInfoObj.I_0002, `fadeOut0`);
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
// プレイ中ショートカットキー変更
|
|
1036
|
+
g_headerObj[`key${selectedKc}`] = setKey;
|
|
1037
|
+
g_headerObj[`key${selectedKc}Def`] = setKey;
|
|
1038
|
+
document.getElementById(`sc${selectedKc}`).textContent = getScMsg[selectedKc]();
|
|
1039
|
+
document.getElementById(`sc${selectedKc}`).style.fontSize =
|
|
1040
|
+
wUnit(getFontSize2(getScMsg[selectedKc](), g_btnWidth(1 / 4) - 40, { maxSiz: g_limitObj.mainSiz }));
|
|
1041
|
+
if (g_isMac) {
|
|
1042
|
+
scTitleBack.textContent = getScMsg.TitleBack();
|
|
1043
|
+
scTitleBack.style.fontSize = wUnit(getFontSize2(getScMsg.TitleBack(), g_btnWidth(1 / 4) - 40, { maxSiz: g_limitObj.mainSiz }));
|
|
1044
|
+
}
|
|
1045
|
+
changeConfigColor(document.getElementById(`sc${selectedKc}`),
|
|
1046
|
+
g_headerObj[`key${selectedKc}`] === g_headerObj[`key${selectedKc}Def2`] ?
|
|
1047
|
+
g_cssObj.title_base : g_cssObj.keyconfig_Changekey);
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
if (setKey === C_KEY_ESCAPE) {
|
|
1052
|
+
// リトライキー、タイトルバックキーにEscキーを割り当て可能にするため、
|
|
1053
|
+
// 例外的にEscキーで戻る対応をここで処理
|
|
1054
|
+
btnBack.click();
|
|
1055
|
+
return;
|
|
1056
|
+
} else if (setKey === C_KEY_TITLEBACK && g_currentk === 0) {
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (setKey === C_KEY_RETRY && (!g_isMac || g_currentk === 0)) {
|
|
1061
|
+
// スキップ
|
|
1062
|
+
} else {
|
|
1063
|
+
// キー割り当て処理
|
|
1064
|
+
if (setKey === C_KEY_TITLEBACK || setKey === C_KEY_RETRY) {
|
|
1065
|
+
// キー無効化(代替キーのみ)
|
|
1066
|
+
setKey = 0;
|
|
1067
|
+
}
|
|
1068
|
+
if (g_keyObj[`keyCtrl${keyCtrlPtn}d`][g_currentj][g_currentk] !== setKey) {
|
|
1069
|
+
// 既定キーと異なる場合は色付け
|
|
1070
|
+
changeKeyConfigColor(g_currentj, g_currentk, g_cssObj.keyconfig_Changekey);
|
|
1071
|
+
}
|
|
1072
|
+
keyCdObj.textContent = g_kCd[setKey];
|
|
1073
|
+
g_keyObj[`keyCtrl${keyCtrlPtn}`][g_currentj][g_currentk] = setKey;
|
|
1074
|
+
g_prevKey = setKey;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// カーソル移動
|
|
1078
|
+
if (g_currentk < g_keyObj[`keyCtrl${keyCtrlPtn}`][g_currentj].length - 1 && g_kcType !== `Main`) {
|
|
1079
|
+
// 後続に代替キーが存在する場合
|
|
1080
|
+
g_currentk++;
|
|
1081
|
+
cursor.style.top = wUnit(parseInt(cursor.style.top) + C_KYC_REPHEIGHT);
|
|
1082
|
+
|
|
1083
|
+
} else {
|
|
1084
|
+
changeConfigCursor();
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
// 戻るボタンのショートカットキー表示
|
|
1089
|
+
multiAppend(btnBack,
|
|
1090
|
+
createDivCss2Label(`scKeyConfigBack`, `${g_lblNameObj.sc_keyConfigBack})`, {
|
|
1091
|
+
x: 0, siz: 12, fontWeight: `bold`, opacity: 0.75, align: C_ALIGN_LEFT,
|
|
1092
|
+
})
|
|
1093
|
+
);
|
|
1094
|
+
|
|
1095
|
+
if (g_stateObj.kbPreviewFlg) {
|
|
1096
|
+
btnKbPreview.click();
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
safeExecuteCustomHooks(`g_skinJsObj.keyconfig`, g_skinJsObj.keyconfig);
|
|
1100
|
+
document.onkeyup = evt => commonKeyUp(evt);
|
|
1101
|
+
document.oncontextmenu = () => false;
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* transKeyPtnの自動補完処理
|
|
1106
|
+
* - 明示指定(transKeyPtn)が無いパターンについて、
|
|
1107
|
+
* キー内で同一のtransKey対象へ向かうパターンを出現順(パターン番号昇順)に
|
|
1108
|
+
* 0から連番で補完する
|
|
1109
|
+
* @param {string[]} _keyList 対象とするキー名一覧
|
|
1110
|
+
*/
|
|
1111
|
+
const completeTransKeyPtn = (_keyList) => {
|
|
1112
|
+
_keyList.forEach(keyName => {
|
|
1113
|
+
const counterMap = {};
|
|
1114
|
+
let ptnNum = 0;
|
|
1115
|
+
while (g_keyObj[`keyCtrl${keyName}_${ptnNum}`] !== undefined) {
|
|
1116
|
+
const keyPtn = `${keyName}_${ptnNum}`;
|
|
1117
|
+
const targetKey = g_keyObj[`transKey${keyPtn}`];
|
|
1118
|
+
if (hasVal(targetKey)) {
|
|
1119
|
+
if (g_keyObj[`transKeyPtn${keyPtn}`] === undefined) {
|
|
1120
|
+
counterMap[targetKey] = counterMap[targetKey] ?? 0;
|
|
1121
|
+
g_keyObj[`transKeyPtn${keyPtn}`] = counterMap[targetKey];
|
|
1122
|
+
counterMap[targetKey]++;
|
|
1123
|
+
} else {
|
|
1124
|
+
// 明示指定がある場合は以降の自動採番と重複しないよう位置を合わせる
|
|
1125
|
+
counterMap[targetKey] = Math.max(counterMap[targetKey] ?? 0, g_keyObj[`transKeyPtn${keyPtn}`] + 1);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
ptnNum++;
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
// KeyLockボタンを押したときの表示切替
|
|
1134
|
+
const toggleKcDesc = () => {
|
|
1135
|
+
if (document.getElementById(`kcDesc`) !== null) {
|
|
1136
|
+
kcDesc.textContent = getKcDescMsg();
|
|
1137
|
+
kcDesc.style.fontSize = wUnit(getFontSize2(kcDesc.textContent, g_lblPosObj.kcDesc.w, { maxSiz: g_limitObj.mainSiz }));
|
|
1138
|
+
kcDesc.classList.remove(g_cssObj.title_base, g_cssObj.keyconfig_Defaultkey);
|
|
1139
|
+
kcDesc.classList.add(g_stateObj.keyLockFlg ? g_cssObj.keyconfig_Defaultkey : g_cssObj.title_base);
|
|
1140
|
+
btnKeyLock.innerHTML = getKeyLockName();
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
|
|
1144
|
+
// KeyLockボタンの表示文字列を取得
|
|
1145
|
+
const getKcDescMsg = () =>
|
|
1146
|
+
g_stateObj.keyLockFlg
|
|
1147
|
+
? g_lblNameObj.kcNonDesc
|
|
1148
|
+
: g_lblNameObj.kcDesc.split(`{0}`).join(g_kCd[C_KEY_RETRY]).split(`{1}:`).join(g_isMac ? `` : `Delete:`);
|
|
1149
|
+
|
|
1150
|
+
// KeyLockボタンで使用する絵文字の取得
|
|
1151
|
+
const getKeyLockName = () =>
|
|
1152
|
+
`${g_lblNameObj.b_keyLock}${g_stateObj.keyLockFlg ? g_emojiObj.locked : g_emojiObj.unlocked}`;
|
|
1153
|
+
|
|
1154
|
+
/**
|
|
1155
|
+
* キーボードレイアウトプレビュー(Canvas版)
|
|
1156
|
+
*
|
|
1157
|
+
* キーコンフィグ画面(divRoot)配下に以下の要素を追加する:
|
|
1158
|
+
* - [Preview] ボタン (createCss2Button)
|
|
1159
|
+
* - プレビュー用コンテナ div (createEmptySprite)
|
|
1160
|
+
* ├ キーボード背景 canvas (_state.canvasBase) ← 起動時のみ描画
|
|
1161
|
+
* └ マッピング強調 canvas (_state.canvasMap) ← キー変更・表示時に再描画
|
|
1162
|
+
*
|
|
1163
|
+
* 前提:
|
|
1164
|
+
* - g_kCd : グローバル定義済み。ロケール切替後は g_lang_kCd がマージ済み。
|
|
1165
|
+
* 未設定キーは空文字列 `""` で初期化。
|
|
1166
|
+
* 右Shift/Ctrl/Alt は 256/257/258 の独自コードで定義。
|
|
1167
|
+
* - g_btnWidth() : 画面の横幅(px)を返すグローバル関数。
|
|
1168
|
+
* - g_sHeight : 画面の縦幅(px)を保持するグローバル変数。
|
|
1169
|
+
* - createCss2Button, createEmptySprite : danoniplus 本体のグローバル関数。
|
|
1170
|
+
*
|
|
1171
|
+
* 使い方:
|
|
1172
|
+
* 【初期化時】
|
|
1173
|
+
* keyconfigKeyboardPreview.init(divRoot);
|
|
1174
|
+
*
|
|
1175
|
+
* 【キー割り当てが変わった時】
|
|
1176
|
+
* keyconfigKeyboardPreview.refresh();
|
|
1177
|
+
* ※ g_keyObj.currentKey / currentPtn から自動取得する
|
|
1178
|
+
*
|
|
1179
|
+
* 【キーコンフィグ画面を離脱する時】
|
|
1180
|
+
* keyconfigKeyboardPreview.dispose();
|
|
1181
|
+
*/
|
|
1182
|
+
|
|
1183
|
+
const keyconfigKeyboardPreview = (() => {
|
|
1184
|
+
|
|
1185
|
+
// -------------------------------------------------------------------------
|
|
1186
|
+
// 定数
|
|
1187
|
+
// -------------------------------------------------------------------------
|
|
1188
|
+
const C_PREVIEW_ID = `kbPreviewArea`;
|
|
1189
|
+
const C_CANVAS_BASE_ID = `kbCanvasBase`;
|
|
1190
|
+
const C_CANVAS_MAP_ID = `kbCanvasMap`;
|
|
1191
|
+
|
|
1192
|
+
// 色定義(既存ゲームの配色に合わせたダーク系)
|
|
1193
|
+
const C_COLOR = {
|
|
1194
|
+
normal: {
|
|
1195
|
+
fill: `#1a1a2e`, // 通常キー背景
|
|
1196
|
+
stroke: `#555577`, // 通常キー枠
|
|
1197
|
+
text: `#ccccdd`, // 通常キー文字
|
|
1198
|
+
subText: `#888899`, // サブラベル(Shift面)
|
|
1199
|
+
},
|
|
1200
|
+
mapped: {
|
|
1201
|
+
fill: `#003366`, // メインキー背景
|
|
1202
|
+
stroke: `#4488ff`, // メインキー枠
|
|
1203
|
+
text: `#aaddff`, // メインキー文字
|
|
1204
|
+
},
|
|
1205
|
+
alt: {
|
|
1206
|
+
fill: `#3e3e1a`, // 代替キー背景
|
|
1207
|
+
stroke: `#777755`, // 代替キー枠
|
|
1208
|
+
text: `#eeeecc`, // 代替キー文字
|
|
1209
|
+
},
|
|
1210
|
+
shortcut: {
|
|
1211
|
+
fill: `#330011`, // ショートカットキー背景
|
|
1212
|
+
stroke: `#ff4466`, // ショートカットキー枠
|
|
1213
|
+
text: `#ffaacc`, // ショートカットキー文字
|
|
1214
|
+
},
|
|
1215
|
+
bgFill: `#0d0d1a`, // Canvas 背景
|
|
1216
|
+
legendText: `#cccccc`, // 凡例テキスト
|
|
1217
|
+
};
|
|
1218
|
+
|
|
1219
|
+
// 凡例エリアの高さ
|
|
1220
|
+
const LEGEND_H = 25;
|
|
1221
|
+
|
|
1222
|
+
// -------------------------------------------------------------------------
|
|
1223
|
+
// キーレイアウト定義
|
|
1224
|
+
//
|
|
1225
|
+
// 各行: { offsetX, keys }
|
|
1226
|
+
// offsetX : 行左端の水平オフセット(単位: BASE_KEY_W)。未指定時は0
|
|
1227
|
+
// keys : キー定義の配列
|
|
1228
|
+
//
|
|
1229
|
+
// 各キー: { code, w?, h?, label? }
|
|
1230
|
+
// code : KeyboardEvent.code(文字列)。空文字 "" はスペーサー(描画・キャッシュなし)。
|
|
1231
|
+
// w : 幅倍率(BASE_KEY_W 基準。省略時 1)
|
|
1232
|
+
// h : 高さ倍率(BASE_KEY_H 基準。省略時 1)
|
|
1233
|
+
// label : 省略時は g_kCd[keyCode] を参照。g_kCd が空文字のキーや
|
|
1234
|
+
// 左右を区別したいキーに指定する。
|
|
1235
|
+
// -------------------------------------------------------------------------
|
|
1236
|
+
/**
|
|
1237
|
+
* g_localeObj.val に応じた MAIN_ROWS を生成して返す。
|
|
1238
|
+
* drawBase / calcScale の都度呼び出し、locale 変化を反映する。
|
|
1239
|
+
*
|
|
1240
|
+
* @returns {Array} MAIN_ROWS 相当の配列
|
|
1241
|
+
*/
|
|
1242
|
+
const buildMainRows = () => {
|
|
1243
|
+
const isJa = g_localeObj.val === `Ja`;
|
|
1244
|
+
return [
|
|
1245
|
+
// Row0: Fn キー行(JIS/US 共通)
|
|
1246
|
+
{
|
|
1247
|
+
keys: [
|
|
1248
|
+
{ code: `Escape` },
|
|
1249
|
+
{ code: ``, w: 0.5 }, // スペーサー
|
|
1250
|
+
{ code: `F1` }, { code: `F2` }, { code: `F3` }, { code: `F4` },
|
|
1251
|
+
{ code: ``, w: 0.25 }, // スペーサー
|
|
1252
|
+
{ code: `F5` }, { code: `F6` }, { code: `F7` }, { code: `F8` },
|
|
1253
|
+
{ code: ``, w: 0.25 }, // スペーサー
|
|
1254
|
+
{ code: `F9` }, { code: `F10` }, { code: `F11` }, { code: `F12` },
|
|
1255
|
+
],
|
|
1256
|
+
},
|
|
1257
|
+
// Row1: 数字行
|
|
1258
|
+
// JIS: ..., Minus, Equal, IntlYen, BS
|
|
1259
|
+
// US : ..., Minus, Equal, BS
|
|
1260
|
+
{
|
|
1261
|
+
keys: [
|
|
1262
|
+
{ code: `Backquote` },
|
|
1263
|
+
{ code: `Digit1` }, { code: `Digit2` }, { code: `Digit3` }, { code: `Digit4` }, { code: `Digit5` }, { code: `Digit6` },
|
|
1264
|
+
{ code: `Digit7` }, { code: `Digit8` }, { code: `Digit9` }, { code: `Digit0` }, { code: `Minus` }, { code: `Equal` },
|
|
1265
|
+
...(isJa
|
|
1266
|
+
? [{ code: `IntlYen`, w: 0.75 }, { code: `Backspace`, label: `Back\nSpace` }] // JIS: IntlYen + BS
|
|
1267
|
+
: [{ code: `Backspace`, w: 1.7 }] // US : BS のみ(広い)
|
|
1268
|
+
),
|
|
1269
|
+
],
|
|
1270
|
+
},
|
|
1271
|
+
// Row2: QWERTY
|
|
1272
|
+
// JIS: ..., BracketLeft, BracketRight, Enter(縦長)
|
|
1273
|
+
// US : ..., BracketLeft, BracketRight, Backslash
|
|
1274
|
+
{
|
|
1275
|
+
keys: [
|
|
1276
|
+
{ code: `Tab`, w: 1.5 },
|
|
1277
|
+
{ code: `KeyQ` }, { code: `KeyW` }, { code: `KeyE` }, { code: `KeyR` }, { code: `KeyT` }, { code: `KeyY` },
|
|
1278
|
+
{ code: `KeyU` }, { code: `KeyI` }, { code: `KeyO` }, { code: `KeyP` }, { code: `BracketLeft` },
|
|
1279
|
+
...(isJa
|
|
1280
|
+
? [{ code: `BracketRight` }, { code: `Enter`, w: 1.25, h: 2 }] // JIS: BracketRight + Enter縦長
|
|
1281
|
+
: [{ code: `BracketRight` }, { code: `Backslash`, w: 1.2 }] // US : BracketRight + Backslash
|
|
1282
|
+
),
|
|
1283
|
+
],
|
|
1284
|
+
},
|
|
1285
|
+
// Row3: ASDF
|
|
1286
|
+
// JIS: ..., KeyL, Semicolon, Quote, Backslash
|
|
1287
|
+
// US : ..., KeyL, Semicolon, Quote, Enter(横長)
|
|
1288
|
+
{
|
|
1289
|
+
keys: [
|
|
1290
|
+
{ code: `CapsLock`, w: 1.75, label: `Caps\nLock` },
|
|
1291
|
+
{ code: `KeyA` }, { code: `KeyS` }, { code: `KeyD` }, { code: `KeyF` }, { code: `KeyG` }, { code: `KeyH` },
|
|
1292
|
+
{ code: `KeyJ` }, { code: `KeyK` }, { code: `KeyL` }, { code: `Semicolon` }, { code: `Quote` },
|
|
1293
|
+
...(isJa
|
|
1294
|
+
? [{ code: `Backslash` }] // JIS: Backslash(¥)
|
|
1295
|
+
: [{ code: `Enter`, w: 1.9 }] // US : Enter横長
|
|
1296
|
+
),
|
|
1297
|
+
],
|
|
1298
|
+
},
|
|
1299
|
+
// Row4: ZXCV
|
|
1300
|
+
// L)Shift の幅で行頭位置を揃える
|
|
1301
|
+
// JIS: L)Shift, ..., IntlRo, R)Shift
|
|
1302
|
+
// US : L)Shift, ..., R)Shift
|
|
1303
|
+
{
|
|
1304
|
+
keys: [
|
|
1305
|
+
{ code: `ShiftLeft`, w: 2.25 },
|
|
1306
|
+
{ code: `KeyZ` }, { code: `KeyX` }, { code: `KeyC` }, { code: `KeyV` }, { code: `KeyB` }, { code: `KeyN` },
|
|
1307
|
+
{ code: `KeyM` }, { code: `Comma` }, { code: `Period` }, { code: `Slash` },
|
|
1308
|
+
...(isJa
|
|
1309
|
+
? [{ code: `IntlRo` }, { code: `ShiftRight`, w: 1.5 }] // JIS: IntlRo + R)Shift
|
|
1310
|
+
: [{ code: `ShiftRight`, w: 2.4 }] // US : R)Shift のみ(広い)
|
|
1311
|
+
),
|
|
1312
|
+
],
|
|
1313
|
+
},
|
|
1314
|
+
// Row5: スペースバー行
|
|
1315
|
+
// JIS: ..., NonConvert, Space, Convert, KanaMode, ...
|
|
1316
|
+
// US : ..., Space, ...
|
|
1317
|
+
{
|
|
1318
|
+
keys: [
|
|
1319
|
+
{ code: `ControlLeft`, w: 1.25 }, { code: `MetaLeft` }, { code: `AltLeft` },
|
|
1320
|
+
...(isJa
|
|
1321
|
+
// JIS: NonConvert + Space + Convert + KanaMode
|
|
1322
|
+
? [{ code: `NonConvert` }, { code: `Space`, w: 5.25 }, { code: `Convert` }, { code: `KanaMode` }]
|
|
1323
|
+
// US : Space のみ(広い)
|
|
1324
|
+
: [{ code: `Space`, w: 8.25 }]
|
|
1325
|
+
),
|
|
1326
|
+
{ code: `AltRight` }, { code: `ContextMenu` },
|
|
1327
|
+
...(isJa
|
|
1328
|
+
? [{ code: `ControlRight`, w: 1.2 }]
|
|
1329
|
+
: [{ code: `ControlRight`, w: 1.05 }]
|
|
1330
|
+
),
|
|
1331
|
+
],
|
|
1332
|
+
},
|
|
1333
|
+
];
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
// 編集キークラスター(PrintSc/ScrollLk/Pause/Insert/Delete/Home/End/PgUp/PgDn + 矢印キー)
|
|
1337
|
+
// MAIN_ROWS と行インデックスを揃えて配置する。空行はスキップされる。
|
|
1338
|
+
const NAV_ROWS = [
|
|
1339
|
+
{ keys: [{ code: `PrintScreen`, label: `Print\nScreen` }, { code: `ScrollLock`, label: `Scroll\nLock` }, { code: `Pause` }] },
|
|
1340
|
+
{ keys: [{ code: `Insert` }, { code: `Home` }, { code: `PageUp`, label: `Page\nUp` }] }, // Insert Home PgUp
|
|
1341
|
+
{ keys: [{ code: `Delete` }, { code: `End` }, { code: `PageDown`, label: `Page\nDown` }] }, // Delete End PgDn
|
|
1342
|
+
{ keys: [] }, // ASDF行:空
|
|
1343
|
+
{ keys: [{ code: `` }, { code: `ArrowUp` }, { code: `` }] }, // ↑
|
|
1344
|
+
{ keys: [{ code: `ArrowLeft` }, { code: `ArrowDown` }, { code: `ArrowRight` }] }, // ← ↓ →
|
|
1345
|
+
];
|
|
1346
|
+
|
|
1347
|
+
// テンキー(MAIN_ROWS と行インデックスを揃えて配置。1行目は空行で Fn行に揃える)
|
|
1348
|
+
// 標準テンキーレイアウト(2行目から):
|
|
1349
|
+
// [NumLk] [T/] [T*] [T-]
|
|
1350
|
+
// [T7][T8][T9] [T+]
|
|
1351
|
+
// [T4][T5][T6] [T+] ← T+ は縦2u
|
|
1352
|
+
// [T1][T2][T3] [TEnter]
|
|
1353
|
+
// [ T0 ][T.] [TEnter] ← T0 は横2u、TEnter は縦2u
|
|
1354
|
+
const NUM_ROWS = [
|
|
1355
|
+
{ keys: [] },
|
|
1356
|
+
{ keys: [{ code: `NumLock`, label: `Num\nLock` }, { code: `NumpadDivide` }, { code: `NumpadMultiply` }, { code: `NumpadSubtract` }] }, // NumLk T/ T* T-
|
|
1357
|
+
{ keys: [{ code: `Numpad7` }, { code: `Numpad8` }, { code: `Numpad9` }, { code: `NumpadAdd`, h: 2 }] }, // T7 T8 T9 T+(縦2u)
|
|
1358
|
+
{ keys: [{ code: `Numpad4` }, { code: `Numpad5` }, { code: `Numpad6` }] }, // T4 T5 T6
|
|
1359
|
+
{ keys: [{ code: `Numpad1` }, { code: `Numpad2` }, { code: `Numpad3` }, { code: `NumpadEnter`, h: 2 }] }, // T1 T2 T3 TEnter(縦2u)
|
|
1360
|
+
{ keys: [{ code: `Numpad0`, w: 2 }, { code: `NumpadDecimal` }] }, // T0(横2u) T.
|
|
1361
|
+
];
|
|
1362
|
+
|
|
1363
|
+
// -------------------------------------------------------------------------
|
|
1364
|
+
// 内部状態
|
|
1365
|
+
// -------------------------------------------------------------------------
|
|
1366
|
+
const _state = {
|
|
1367
|
+
visible: false,
|
|
1368
|
+
mappedSet: new Set(), // メインキー(code文字列)
|
|
1369
|
+
altSet: new Set(), // 代替キー(code文字列)
|
|
1370
|
+
shortcutSet: new Set(), // ショートカットキー(code文字列)
|
|
1371
|
+
canvasBase: null,
|
|
1372
|
+
canvasMap: null,
|
|
1373
|
+
keyDataList: [], // { code, x, y, w, h, label } — drawMap で照合するキャッシュ
|
|
1374
|
+
scale: 1, // BASE_KEY_W/H に掛けるスケール係数
|
|
1375
|
+
cvsX: 0, // Canvas の左上 X 座標(divRoot 内の相対座標)
|
|
1376
|
+
cvsW: 500, // 実際の Canvas 幅(スケール計算後)
|
|
1377
|
+
cvsH: 240, // 実際の Canvas 高さ(スケール計算後)
|
|
1378
|
+
};
|
|
1379
|
+
|
|
1380
|
+
// -------------------------------------------------------------------------
|
|
1381
|
+
// スケール計算
|
|
1382
|
+
// -------------------------------------------------------------------------
|
|
1383
|
+
|
|
1384
|
+
/**
|
|
1385
|
+
* g_btnWidth() / g_sHeight を元にスケール係数と Canvas サイズを算出して
|
|
1386
|
+
* _state に書き込む。init 時に呼ぶ。
|
|
1387
|
+
*
|
|
1388
|
+
* 基準サイズ(フルキーボード = メイン + ナビクラスター):
|
|
1389
|
+
* 横: MAIN最大行幅 + ナビ幅(3キー) + 余白
|
|
1390
|
+
* 縦: 6行 × (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP
|
|
1391
|
+
* BASE_KEY_W = BASE_KEY_H = 28px、BASE_KEY_GAP = 3px を基準とする。
|
|
1392
|
+
*/
|
|
1393
|
+
const BASE_KEY_W = 28;
|
|
1394
|
+
const BASE_KEY_H = 28;
|
|
1395
|
+
const BASE_KEY_GAP = 3;
|
|
1396
|
+
const MAIN_ROWS_LEN = 6; // MAIN_ROWS の行数(Fn行を含む)
|
|
1397
|
+
|
|
1398
|
+
// 行幅計算(スペーサー含む)
|
|
1399
|
+
const calcRowBaseW = row =>
|
|
1400
|
+
row.keys.reduce((acc, k) => acc + (k.w || 1) * BASE_KEY_W + BASE_KEY_GAP, -BASE_KEY_GAP);
|
|
1401
|
+
|
|
1402
|
+
const BASE_NAV_W = 3 * BASE_KEY_W + 2 * BASE_KEY_GAP; // NAV は 3列固定
|
|
1403
|
+
const BASE_ROW_H = MAIN_ROWS_LEN * (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP; // MAIN+NAV 分の高さ
|
|
1404
|
+
const NUM_ROWS_LEN = 6; // テンキーの行数(1行目は空行、2行目からテンキー配置)
|
|
1405
|
+
const NUM_GAP_H = BASE_KEY_H * 0.4; // テンキー上部の余白(基準キー高の40%)
|
|
1406
|
+
const BASE_NUM_ROW_H = NUM_ROWS_LEN * (BASE_KEY_H + BASE_KEY_GAP) - BASE_KEY_GAP; // テンキー部の高さ
|
|
1407
|
+
const BASE_NUM_W = 4 * BASE_KEY_W + 3 * BASE_KEY_GAP; // テンキー横幅(4列固定)
|
|
1408
|
+
|
|
1409
|
+
const calcScale = () => {
|
|
1410
|
+
// locale に依存した行幅を毎回計算する
|
|
1411
|
+
const rows = buildMainRows();
|
|
1412
|
+
const baseMainW = Math.max(...rows.map(calcRowBaseW));
|
|
1413
|
+
// 横幅: メイン + NAV + テンキー + 余白
|
|
1414
|
+
const totalW = baseMainW + BASE_KEY_GAP * 2 + BASE_NAV_W + BASE_KEY_GAP * 2
|
|
1415
|
+
+ BASE_KEY_GAP * 3 + BASE_NUM_W;
|
|
1416
|
+
|
|
1417
|
+
const tkObj = getKeyInfo();
|
|
1418
|
+
const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
|
|
1419
|
+
const configKeyGroupList = g_headerObj.keyGroupOrder[g_stateObj.scoreId] ??
|
|
1420
|
+
g_keyObj[`keyGroupOrder${keyCtrlPtn}`] ?? tkObj.keyGroupList;
|
|
1421
|
+
|
|
1422
|
+
const availW = g_btnWidth() + (configKeyGroupList.length > 1 ? -g_lblPosObj.lnkKeySwitch.w - 10 : 0);
|
|
1423
|
+
const availH = g_sHeight - 200 - LEGEND_H; // 下部 UI ぶんを除いた高さ
|
|
1424
|
+
|
|
1425
|
+
// 縦幅基準: MAIN/NAV 高さ と テンキー高さ(余白込み)の大きい方
|
|
1426
|
+
const totalH = Math.max(BASE_ROW_H, BASE_NUM_ROW_H + Math.ceil(NUM_GAP_H));
|
|
1427
|
+
|
|
1428
|
+
const scaleW = availW / totalW;
|
|
1429
|
+
const scaleH = availH / totalH;
|
|
1430
|
+
_state.scale = Math.min(scaleW, scaleH, 1.5); // 最大 1.5 倍まで拡大可
|
|
1431
|
+
|
|
1432
|
+
_state.cvsX = configKeyGroupList.length > 1 ? (-g_lblPosObj.lnkKeySwitch.w - 10) / 2 : 0;
|
|
1433
|
+
_state.cvsW = Math.floor(totalW * _state.scale);
|
|
1434
|
+
_state.cvsH = Math.floor(totalH * _state.scale) + LEGEND_H;
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
// -------------------------------------------------------------------------
|
|
1438
|
+
// ラベル取得
|
|
1439
|
+
// -------------------------------------------------------------------------
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* code に対応する [primaryLabel, subLabel] を返す。
|
|
1443
|
+
*
|
|
1444
|
+
* @param {string} code
|
|
1445
|
+
* @param {string|undefined} forcedLabel - ROWS の label 指定がある場合に優先
|
|
1446
|
+
* @returns {string[]} [primary, sub]
|
|
1447
|
+
*/
|
|
1448
|
+
const getKeyLabels = (code, forcedLabel) => {
|
|
1449
|
+
if (!code) return [``, ``];
|
|
1450
|
+
if (forcedLabel !== undefined) return [forcedLabel, ``];
|
|
1451
|
+
|
|
1452
|
+
// code 文字列から従来の keyCode を逆引きして g_kCd から取得
|
|
1453
|
+
const kc = g_kCdN.indexOf(code);
|
|
1454
|
+
if (kc >= 0) {
|
|
1455
|
+
const raw = g_kCd[kc];
|
|
1456
|
+
if (raw && raw !== g_kCd[0] && raw !== g_kCd[1]) {
|
|
1457
|
+
const parts = raw.split(` `);
|
|
1458
|
+
return [parts[0] || ``, parts[1] || ``];
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return [`?`, ``];
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1464
|
+
// -------------------------------------------------------------------------
|
|
1465
|
+
// Canvas ヘルパー
|
|
1466
|
+
// -------------------------------------------------------------------------
|
|
1467
|
+
|
|
1468
|
+
// スケール済みの各寸法を返すヘルパー
|
|
1469
|
+
const kw = w => Math.floor(w * BASE_KEY_W * _state.scale + (w - 1) * BASE_KEY_GAP * _state.scale);
|
|
1470
|
+
const kh = h => Math.floor(h * BASE_KEY_H * _state.scale + (h - 1) * BASE_KEY_GAP * _state.scale);
|
|
1471
|
+
const kg = () => Math.max(1, Math.round(BASE_KEY_GAP * _state.scale));
|
|
1472
|
+
const kr = () => Math.max(2, Math.round(4 * _state.scale));
|
|
1473
|
+
|
|
1474
|
+
/**
|
|
1475
|
+
* Canvasの共通初期化処理
|
|
1476
|
+
* @param {HTMLCanvasElement} canvas
|
|
1477
|
+
* @returns {CanvasRenderingContext2D|null}
|
|
1478
|
+
*/
|
|
1479
|
+
const setupCanvasContext = (canvas) => {
|
|
1480
|
+
if (!canvas) return null;
|
|
1481
|
+
canvas.style.top = wUnit(40);
|
|
1482
|
+
canvas.width = _state.cvsW * g_dpr;
|
|
1483
|
+
canvas.height = _state.cvsH * g_dpr;
|
|
1484
|
+
canvas.style.width = wUnit(_state.cvsW);
|
|
1485
|
+
canvas.style.height = wUnit(_state.cvsH);
|
|
1486
|
+
|
|
1487
|
+
const ctx = canvas.getContext(`2d`);
|
|
1488
|
+
ctx.scale(g_dpr, g_dpr);
|
|
1489
|
+
return ctx;
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
/**
|
|
1493
|
+
* 円角矩形を描画する
|
|
1494
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
1495
|
+
* @param {number} x
|
|
1496
|
+
* @param {number} y
|
|
1497
|
+
* @param {number} w
|
|
1498
|
+
* @param {number} h
|
|
1499
|
+
* @param {number} r
|
|
1500
|
+
*/
|
|
1501
|
+
const roundRect = (ctx, x, y, w, h, r) => {
|
|
1502
|
+
ctx.beginPath();
|
|
1503
|
+
ctx.moveTo(x + r, y);
|
|
1504
|
+
ctx.lineTo(x + w - r, y);
|
|
1505
|
+
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
|
|
1506
|
+
ctx.lineTo(x + w, y + h - r);
|
|
1507
|
+
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
|
|
1508
|
+
ctx.lineTo(x + r, y + h);
|
|
1509
|
+
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
|
|
1510
|
+
ctx.lineTo(x, y + r);
|
|
1511
|
+
ctx.quadraticCurveTo(x, y, x + r, y);
|
|
1512
|
+
ctx.closePath();
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
/**
|
|
1516
|
+
* 単一キーを描画する(枠の描画と内部テキストの書き込みを一括化)
|
|
1517
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
1518
|
+
* @param {Object} keyData - 位置・サイズ・キーコードを含むキー情報
|
|
1519
|
+
* @param {Object} style - fill, stroke, text 等の色セット
|
|
1520
|
+
* @param {number} lw - 枠線の太さ(lineWidth)
|
|
1521
|
+
*/
|
|
1522
|
+
const drawOneKey = (ctx, { keyData, style, lw = 1 }) => {
|
|
1523
|
+
const { x, y, w: keyW, h: keyH, code, label } = keyData;
|
|
1524
|
+
|
|
1525
|
+
// 1. キーの枠線・背景を描画
|
|
1526
|
+
roundRect(ctx, x + 0.5, y + 0.5, keyW - 1, keyH - 1, kr());
|
|
1527
|
+
ctx.fillStyle = style.fill;
|
|
1528
|
+
ctx.strokeStyle = style.stroke;
|
|
1529
|
+
ctx.lineWidth = lw;
|
|
1530
|
+
ctx.fill();
|
|
1531
|
+
ctx.stroke();
|
|
1532
|
+
|
|
1533
|
+
// 2. キー内部のテキスト(メイン・サブ)を描画
|
|
1534
|
+
const [primary, sub] = getKeyLabels(code, label);
|
|
1535
|
+
|
|
1536
|
+
const fs = (_textLen) => _textLen >= 5 * keyW / BASE_KEY_W
|
|
1537
|
+
? Math.max(6, Math.floor(9 * _state.scale))
|
|
1538
|
+
: Math.max(7, Math.floor(11 * _state.scale));
|
|
1539
|
+
|
|
1540
|
+
// サブラベル(Shift面などの表記)がある場合
|
|
1541
|
+
if (sub) {
|
|
1542
|
+
ctx.fillStyle = style.subText || style.text;
|
|
1543
|
+
ctx.font = `bold ${Math.max(6, Math.floor(9 * _state.scale))}px monospace`;
|
|
1544
|
+
ctx.textAlign = `right`;
|
|
1545
|
+
ctx.textBaseline = `top`;
|
|
1546
|
+
ctx.fillText(sub, x + keyW - 2, y + 2);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// メインラベルの描画(改行表記に対応)
|
|
1550
|
+
const [primary1, primary2] = primary.split(`\n`);
|
|
1551
|
+
ctx.fillStyle = style.text;
|
|
1552
|
+
ctx.textAlign = `center`;
|
|
1553
|
+
ctx.textBaseline = `middle`;
|
|
1554
|
+
const subDiff = sub ? 2 : 0;
|
|
1555
|
+
|
|
1556
|
+
if (primary2) {
|
|
1557
|
+
const siz = fs(Math.max(primary1.length, primary2.length));
|
|
1558
|
+
ctx.font = `bold ${siz}px monospace`;
|
|
1559
|
+
ctx.fillText(primary1, x + keyW / 2, y + keyH / 2 - siz / 2 + subDiff);
|
|
1560
|
+
ctx.fillText(primary2, x + keyW / 2, y + keyH / 2 + siz / 2 + subDiff);
|
|
1561
|
+
} else {
|
|
1562
|
+
ctx.font = `bold ${fs(primary.length)}px monospace`;
|
|
1563
|
+
ctx.fillText(primary, x + keyW / 2, y + keyH / 2 + subDiff);
|
|
1564
|
+
}
|
|
1565
|
+
};
|
|
1566
|
+
|
|
1567
|
+
// -------------------------------------------------------------------------
|
|
1568
|
+
// レイアウト計算・描画
|
|
1569
|
+
// -------------------------------------------------------------------------
|
|
1570
|
+
|
|
1571
|
+
/**
|
|
1572
|
+
* rows 配列から各キーの矩形座標を計算し、
|
|
1573
|
+
* canvas に描画しながら keyDataList へキャッシュする。
|
|
1574
|
+
*
|
|
1575
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
1576
|
+
* @param {Array} rows - MAIN_ROWS または NAV_ROWS({offsetX, keys} 形式)
|
|
1577
|
+
* @param {number} originX - セクション左端の X 座標(canvas 座標)
|
|
1578
|
+
* @param {number} originY - セクション上端の Y 座標(canvas 座標)
|
|
1579
|
+
*/
|
|
1580
|
+
const layoutSection = (ctx, rows, originX, originY) => {
|
|
1581
|
+
const gap = kg();
|
|
1582
|
+
const baseKeyH = kh(1);
|
|
1583
|
+
|
|
1584
|
+
rows.forEach((rowDef, rowIdx) => {
|
|
1585
|
+
if (rowDef.keys.length === 0) return;
|
|
1586
|
+
|
|
1587
|
+
const rowY = originY + rowIdx * (baseKeyH + gap);
|
|
1588
|
+
const startX = originX + Math.floor((rowDef.offsetX || 0) * BASE_KEY_W * _state.scale);
|
|
1589
|
+
let curX = startX;
|
|
1590
|
+
|
|
1591
|
+
rowDef.keys.forEach(keyDef => {
|
|
1592
|
+
const keyW = kw(keyDef.w || 1);
|
|
1593
|
+
const keyH = kh(keyDef.h || 1);
|
|
1594
|
+
|
|
1595
|
+
if (keyDef.code !== ``) {
|
|
1596
|
+
const keyData = {
|
|
1597
|
+
code: keyDef.code,
|
|
1598
|
+
x: curX,
|
|
1599
|
+
y: rowY,
|
|
1600
|
+
w: keyW,
|
|
1601
|
+
h: keyH,
|
|
1602
|
+
label: keyDef.label,
|
|
1603
|
+
};
|
|
1604
|
+
_state.keyDataList.push(keyData);
|
|
1605
|
+
drawOneKey(ctx, { keyData, style: C_COLOR.normal, lw: 1 });
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
curX += keyW + gap;
|
|
1609
|
+
});
|
|
1610
|
+
});
|
|
1611
|
+
};
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* キーボード背景レイヤーを描画し keyDataList をキャッシュする。
|
|
1615
|
+
* init 時に呼ぶ。
|
|
1616
|
+
*/
|
|
1617
|
+
const drawBase = () => {
|
|
1618
|
+
const ctx = setupCanvasContext(_state.canvasBase);
|
|
1619
|
+
if (!ctx) return;
|
|
1620
|
+
|
|
1621
|
+
ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
|
|
1622
|
+
ctx.fillStyle = C_COLOR.bgFill;
|
|
1623
|
+
ctx.fillRect(0, 0, _state.cvsW, _state.cvsH);
|
|
1624
|
+
|
|
1625
|
+
_state.keyDataList = [];
|
|
1626
|
+
|
|
1627
|
+
const mainRows = buildMainRows();
|
|
1628
|
+
const gap = kg();
|
|
1629
|
+
const baseMainW = Math.max(...mainRows.map(calcRowBaseW));
|
|
1630
|
+
const mainW = Math.floor(baseMainW * _state.scale);
|
|
1631
|
+
const originY = gap;
|
|
1632
|
+
const navOriginX = mainW + gap * 3;
|
|
1633
|
+
|
|
1634
|
+
// テンキー: NAV クラスターの右に gap*3 の余白を空けて配置
|
|
1635
|
+
const numOriginX = navOriginX + Math.floor(BASE_NAV_W * _state.scale) + gap * 3;
|
|
1636
|
+
// テンキーは MAIN 全体に対して縦方向センタリング
|
|
1637
|
+
const numH = Math.floor(BASE_NUM_ROW_H * _state.scale);
|
|
1638
|
+
const mainH = Math.floor(BASE_ROW_H * _state.scale);
|
|
1639
|
+
const numOriginY = originY + Math.floor((mainH - numH) / 2);
|
|
1640
|
+
|
|
1641
|
+
layoutSection(ctx, mainRows, 0, originY);
|
|
1642
|
+
layoutSection(ctx, NAV_ROWS, navOriginX, originY);
|
|
1643
|
+
layoutSection(ctx, NUM_ROWS, numOriginX, numOriginY);
|
|
1644
|
+
|
|
1645
|
+
// 凡例
|
|
1646
|
+
const ly = _state.cvsH - 10;
|
|
1647
|
+
ctx.font = `${Math.max(9, Math.floor(12 * _state.scale))}px ${getBasicFont()}`;
|
|
1648
|
+
ctx.textAlign = `left`;
|
|
1649
|
+
ctx.textBaseline = `middle`;
|
|
1650
|
+
|
|
1651
|
+
const legends = [
|
|
1652
|
+
{ style: C_COLOR.normal, label: g_lblNameObj.unallocated },
|
|
1653
|
+
{ style: C_COLOR.mapped, label: g_lblNameObj.allocated },
|
|
1654
|
+
{ style: C_COLOR.alt, label: g_lblNameObj.altAllocated },
|
|
1655
|
+
{ style: C_COLOR.shortcut, label: g_lblNameObj.shortcutKey }
|
|
1656
|
+
];
|
|
1657
|
+
|
|
1658
|
+
let lx = 8;
|
|
1659
|
+
legends.forEach(item => {
|
|
1660
|
+
roundRect(ctx, lx, ly - 5, 10, 10, 2);
|
|
1661
|
+
ctx.fillStyle = item.style.fill; ctx.fill();
|
|
1662
|
+
ctx.strokeStyle = item.style.stroke; ctx.lineWidth = 1; ctx.stroke();
|
|
1663
|
+
ctx.fillStyle = C_COLOR.legendText;
|
|
1664
|
+
ctx.fillText(item.label, lx + 14, ly);
|
|
1665
|
+
lx += ctx.measureText(item.label).width + 28;
|
|
1666
|
+
});
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1669
|
+
/**
|
|
1670
|
+
* マッピング強調レイヤーを再描画する。
|
|
1671
|
+
* メインキー(mappedSet)を青系、代替キー(altSet)を黄系で色分けする。
|
|
1672
|
+
* 同一キーにメインと代替が重なる場合はメインを優先する。
|
|
1673
|
+
*/
|
|
1674
|
+
const drawMap = () => {
|
|
1675
|
+
const ctx = setupCanvasContext(_state.canvasMap);
|
|
1676
|
+
if (!ctx) return;
|
|
1677
|
+
|
|
1678
|
+
ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
|
|
1679
|
+
|
|
1680
|
+
// キー状態に応じた色取得ロジック(優先度: ショートカット > メイン > 代替)
|
|
1681
|
+
const getKeyStyle = (code) => {
|
|
1682
|
+
if (_state.shortcutSet.has(code)) return C_COLOR.shortcut;
|
|
1683
|
+
if (_state.mappedSet.has(code)) return C_COLOR.mapped;
|
|
1684
|
+
if (_state.altSet.has(code)) return C_COLOR.alt;
|
|
1685
|
+
return null;
|
|
1686
|
+
};
|
|
1687
|
+
|
|
1688
|
+
_state.keyDataList.forEach(keyData => {
|
|
1689
|
+
const style = getKeyStyle(keyData.code);
|
|
1690
|
+
if (style) {
|
|
1691
|
+
drawOneKey(ctx, { keyData, style, lw: 1.5 });
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
};
|
|
1695
|
+
|
|
1696
|
+
// -------------------------------------------------------------------------
|
|
1697
|
+
// 公開 API
|
|
1698
|
+
// -------------------------------------------------------------------------
|
|
1699
|
+
|
|
1700
|
+
/**
|
|
1701
|
+
* キーボードプレビューを初期化し、ボタンと Canvas コンテナを divRoot に追加する。
|
|
1702
|
+
*
|
|
1703
|
+
* @param {HTMLElement} divRoot - キーコンフィグ画面のルート div
|
|
1704
|
+
*/
|
|
1705
|
+
const init = divRoot => {
|
|
1706
|
+
calcScale();
|
|
1707
|
+
|
|
1708
|
+
// "↓ Preview" → 展開、"↑ Preview" → 閉じる のトグルボタン
|
|
1709
|
+
const btn = createCss2Button(`btnKbPreview`, `↓ Preview`, () => {
|
|
1710
|
+
togglePreview();
|
|
1711
|
+
btn.textContent = _state.visible ? `↑ Preview` : `↓ Preview`;
|
|
1712
|
+
}, g_lblPosObj.btnKbPreview, g_cssObj.button_Setting);
|
|
1713
|
+
divRoot.appendChild(btn);
|
|
1714
|
+
|
|
1715
|
+
// プレビューエリア: 水平・垂直センタリング
|
|
1716
|
+
const areaX = g_btnX() + Math.floor((g_btnWidth() - _state.cvsW) / 2) + _state.cvsX;
|
|
1717
|
+
const areaY = 130;
|
|
1718
|
+
|
|
1719
|
+
const areaDiv = createEmptySprite(divRoot, C_PREVIEW_ID, {
|
|
1720
|
+
x: areaX, y: areaY - 60, w: _state.cvsW, h: _state.cvsH + 80,
|
|
1721
|
+
pointerEvents: C_DIS_AUTO, background: `#00000080`, display: C_DIS_NONE, overflow: `hidden`,
|
|
1722
|
+
});
|
|
1723
|
+
|
|
1724
|
+
const canvasBase = document.createElement(`canvas`);
|
|
1725
|
+
canvasBase.id = C_CANVAS_BASE_ID;
|
|
1726
|
+
areaDiv.appendChild(canvasBase);
|
|
1727
|
+
_state.canvasBase = canvasBase;
|
|
1728
|
+
|
|
1729
|
+
const canvasMap = document.createElement(`canvas`);
|
|
1730
|
+
canvasMap.id = C_CANVAS_MAP_ID;
|
|
1731
|
+
areaDiv.appendChild(canvasMap);
|
|
1732
|
+
_state.canvasMap = canvasMap;
|
|
1733
|
+
|
|
1734
|
+
drawBase();
|
|
1735
|
+
};
|
|
1736
|
+
|
|
1737
|
+
/**
|
|
1738
|
+
* プレビューの表示 / 非表示を切り替える。
|
|
1739
|
+
* 表示するたびにマッピングレイヤーを最新化する。
|
|
1740
|
+
*/
|
|
1741
|
+
const togglePreview = () => {
|
|
1742
|
+
const area = document.getElementById(C_PREVIEW_ID);
|
|
1743
|
+
if (!area) return;
|
|
1744
|
+
|
|
1745
|
+
_state.visible = !_state.visible;
|
|
1746
|
+
area.style.display = _state.visible ? `block` : `none`;
|
|
1747
|
+
g_stateObj.kbPreviewFlg = _state.visible;
|
|
1748
|
+
g_stateObj.keyLockFlg = _state.visible;
|
|
1749
|
+
toggleKcDesc();
|
|
1750
|
+
if (_state.visible) refresh();
|
|
1751
|
+
};
|
|
1752
|
+
|
|
1753
|
+
/**
|
|
1754
|
+
* g_keyObj から現在のキー割り当てを取得して mappedSet / altSet を更新し、
|
|
1755
|
+
* プレビューが表示中なら即時再描画する。
|
|
1756
|
+
*
|
|
1757
|
+
* g_keyObj[`keyCtrl${keyCtrlPtn}`] は二次元配列:
|
|
1758
|
+
* [ [矢印0のメインkeyCode, 代替keyCode, ...], [矢印1のメインkeyCode, ...], ... ]
|
|
1759
|
+
* 各サブ配列の index 0 がメインキー、index 1 以降が代替キー。
|
|
1760
|
+
*/
|
|
1761
|
+
const refresh = () => {
|
|
1762
|
+
const tkObj = getKeyInfo();
|
|
1763
|
+
const configKeyGroupList = g_headerObj.keyGroupOrder[g_stateObj.scoreId] ??
|
|
1764
|
+
g_keyObj[`keyGroupOrder${tkObj.keyCtrlPtn}`] ?? tkObj.keyGroupList;
|
|
1765
|
+
const ctrl = g_keyObj[`keyCtrl${tkObj.keyCtrlPtn}`]
|
|
1766
|
+
.filter((val, idx) => tkObj.keyGroupMaps[idx].includes(configKeyGroupList[g_keycons.keySwitchNum]));
|
|
1767
|
+
|
|
1768
|
+
// 数値から code 文字列へ安全に変換するヘルパー
|
|
1769
|
+
const toCodeStr = (num) => g_kCdN[num] || ``;
|
|
1770
|
+
|
|
1771
|
+
_state.mappedSet = new Set(ctrl.map(arr => toCodeStr(arr[0])).filter(v => v !== ``));
|
|
1772
|
+
_state.altSet = new Set(ctrl.flatMap(arr => arr.slice(1)).map(toCodeStr).filter(v => v !== ``));
|
|
1773
|
+
|
|
1774
|
+
// プレイ中ショートカット: keyRetry / keyTitleBack / keyPause は g_headerObj から取得、PgDn(34) / PgUp(33) は固定
|
|
1775
|
+
_state.shortcutSet = new Set(
|
|
1776
|
+
[g_headerObj.keyRetry, g_headerObj.keyTitleBack, g_headerObj.keyPause, 34, 33].map(toCodeStr).filter(v => v !== ``)
|
|
1777
|
+
);
|
|
1778
|
+
|
|
1779
|
+
if (_state.visible) drawMap();
|
|
1780
|
+
};
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* プレビューを強制非表示にしてリセットする。
|
|
1784
|
+
* キーコンフィグ画面の離脱時に呼ぶ。
|
|
1785
|
+
*/
|
|
1786
|
+
const dispose = () => {
|
|
1787
|
+
_state.visible = false;
|
|
1788
|
+
_state.mappedSet = new Set();
|
|
1789
|
+
_state.altSet = new Set();
|
|
1790
|
+
_state.shortcutSet = new Set();
|
|
1791
|
+
_state.keyDataList = [];
|
|
1792
|
+
_state.canvasBase = null;
|
|
1793
|
+
_state.canvasMap = null;
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
return { init, refresh, togglePreview, dispose };
|
|
1797
|
+
|
|
1798
|
+
})();
|
|
1799
|
+
|
|
1800
|
+
/**
|
|
1801
|
+
* 回転できないオブジェクトの場合に設定の自動絞り込みを行う
|
|
1802
|
+
*/
|
|
1803
|
+
const changeSettingListsForImg = () => {
|
|
1804
|
+
if (g_stateObj.rotateEnabled) {
|
|
1805
|
+
g_settings.camoufrages = g_settings.camoufrageRotates.concat();
|
|
1806
|
+
} else {
|
|
1807
|
+
g_settings.camoufrages = g_settings.camoufrageNoRotates.concat();
|
|
1808
|
+
if (g_stateObj.camoufrage.startsWith(`Color`)) {
|
|
1809
|
+
g_stateObj.camoufrage = `Color`;
|
|
1810
|
+
} else {
|
|
1811
|
+
g_stateObj.camoufrage = C_FLG_OFF;
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
g_settings.camoufrageNum = g_settings.camoufrages.findIndex(val => val === g_stateObj.camoufrage);
|
|
1815
|
+
};
|
|
1816
|
+
|
|
1817
|
+
/**
|
|
1818
|
+
* 影矢印色の取得
|
|
1819
|
+
* @param {number} _colorPos
|
|
1820
|
+
* @param {string} _arrowColor
|
|
1821
|
+
* @returns {string}
|
|
1822
|
+
*/
|
|
1823
|
+
const getShadowColor = (_colorPos, _arrowColor) => g_headerObj.setShadowColor[_colorPos] === `Default` ?
|
|
1824
|
+
_arrowColor : g_headerObj.setShadowColor[_colorPos];
|
|
1825
|
+
|
|
1826
|
+
/**
|
|
1827
|
+
* デフォルトの曲中ショートカットをキー数・キーパターンにより切り替え
|
|
1828
|
+
* - キーコンフィグ画面で個別に変えていた場合は変更しない
|
|
1829
|
+
*/
|
|
1830
|
+
const setPlayingShortcut = () => {
|
|
1831
|
+
const keyCtrlPtn = `${g_keyObj.currentKey}_${g_keyObj.currentPtn}`;
|
|
1832
|
+
if (g_headerObj.keyRetryDef === C_KEY_RETRY) {
|
|
1833
|
+
g_headerObj.keyRetry = setIntVal(getKeyCtrlVal(g_keyObj[`keyRetry${keyCtrlPtn}`]), g_headerObj.keyRetryDef);
|
|
1834
|
+
}
|
|
1835
|
+
if (g_headerObj.keyTitleBackDef === C_KEY_TITLEBACK) {
|
|
1836
|
+
g_headerObj.keyTitleBack = setIntVal(getKeyCtrlVal(g_keyObj[`keyTitleBack${keyCtrlPtn}`]), g_headerObj.keyTitleBackDef);
|
|
1837
|
+
}
|
|
1838
|
+
if (g_headerObj.keyPauseDef === C_KEY_PAUSE) {
|
|
1839
|
+
g_headerObj.keyPause = setIntVal(getKeyCtrlVal(g_keyObj[`keyPause${keyCtrlPtn}`]), g_headerObj.keyPauseDef);
|
|
1840
|
+
}
|
|
1841
|
+
};
|
|
1842
|
+
|
|
1843
|
+
/**
|
|
1844
|
+
* ステップゾーン間隔、大きさの更新
|
|
1845
|
+
* @param {string} _header
|
|
1846
|
+
* @param {string} _keyCtrlPtn
|
|
1847
|
+
*/
|
|
1848
|
+
const updateKeyInfo = (_header, _keyCtrlPtn) => {
|
|
1849
|
+
const kcPtn = hasVal(g_keyObj[`${_header}${_keyCtrlPtn}`]) ? _keyCtrlPtn : `_def`;
|
|
1850
|
+
g_keyObj[_header] = g_keyObj[`${_header}${kcPtn}`];
|
|
1851
|
+
};
|
|
1852
|
+
|
|
1853
|
+
/**
|
|
1854
|
+
* 初期矢印色・フリーズアロー色の変更
|
|
1855
|
+
* - ここでのID管理は1譜面目も区別して設定する (setScoreIdHeaderの第三引数を使用)
|
|
1856
|
+
*/
|
|
1857
|
+
const changeSetColor = () => {
|
|
1858
|
+
const isDefault = g_keycons.colorDefTypes.includes(g_colorType);
|
|
1859
|
+
const idHeader = setScoreIdHeader(g_stateObj.scoreId, false, true);
|
|
1860
|
+
const defaultType = idHeader + g_colorType;
|
|
1861
|
+
const currentTypes = {
|
|
1862
|
+
'': (isDefault ? defaultType : g_colorType),
|
|
1863
|
+
'Shadow': (isDefault ? defaultType : `${idHeader}Default`),
|
|
1864
|
+
};
|
|
1865
|
+
Object.keys(currentTypes).forEach(pattern => {
|
|
1866
|
+
g_headerObj[`set${pattern}Color`] = structuredClone(g_headerObj[`set${pattern}Color${currentTypes[pattern]}`]);
|
|
1867
|
+
if (g_headerObj[`frz${pattern}Color`] === undefined) {
|
|
1868
|
+
g_headerObj[`frz${pattern}Color`] = fillArray(g_headerObj.setColorInit.length, ``);
|
|
1869
|
+
}
|
|
1870
|
+
for (let j = 0; j < g_headerObj.setColorInit.length; j++) {
|
|
1871
|
+
g_headerObj[`frz${pattern}Color`][j] = structuredClone(g_headerObj[`frz${pattern}Color${currentTypes[pattern]}`][j]);
|
|
1872
|
+
}
|
|
1873
|
+
if (!isDefault) {
|
|
1874
|
+
g_headerObj[`set${pattern}Color`] = structuredClone(g_headerObj[`set${pattern}Color${g_colorType}`]);
|
|
1875
|
+
}
|
|
1876
|
+
});
|
|
1877
|
+
|
|
1878
|
+
// 影矢印が未指定の場合はType1, Type2の影矢印指定を無くす
|
|
1879
|
+
if (!hasVal(g_headerObj[`setShadowColor${idHeader}Default`][0]) && [`Type1`, `Type2`].includes(g_colorType)) {
|
|
1880
|
+
g_headerObj.setShadowColor = fillArray(g_headerObj.setColorInit.length, ``);
|
|
1881
|
+
}
|
|
1882
|
+
};
|
|
1883
|
+
|
|
1884
|
+
/**
|
|
1885
|
+
* コンフィグの色変更
|
|
1886
|
+
* @param {HTMLDivElement} _obj
|
|
1887
|
+
* @param {string} _cssName
|
|
1888
|
+
*/
|
|
1889
|
+
const changeConfigColor = (_obj, _cssName) => {
|
|
1890
|
+
_obj.classList.remove(g_cssObj.keyconfig_Changekey, g_cssObj.keyconfig_Defaultkey, g_cssObj.title_base);
|
|
1891
|
+
_obj.classList.add(_cssName);
|
|
1892
|
+
};
|
|
1893
|
+
|
|
1894
|
+
/**
|
|
1895
|
+
* シャッフルグループの色変更
|
|
1896
|
+
* - デフォルト値と違う番号になった場合、色付けする
|
|
1897
|
+
* @param {string} _keyCtrlPtn キーコンフィグパターン
|
|
1898
|
+
* @param {number[]} _vals シャッフルグループ番号(群)
|
|
1899
|
+
* @param {number} _j (-1: 全体に対して色付け, それ以外: 指定箇所のみ色付け)
|
|
1900
|
+
*/
|
|
1901
|
+
const changeShuffleConfigColor = (_keyCtrlPtn, _vals, _j = -1) => {
|
|
1902
|
+
const changeTargetColor = (_val, _k) => {
|
|
1903
|
+
const isEqualShuffleGr = (_val === g_keyObj[`shuffle${_keyCtrlPtn}_0d`][_k]);
|
|
1904
|
+
changeConfigColor(document.getElementById(`sArrow${_k}`), isEqualShuffleGr ? g_cssObj.title_base : g_cssObj.keyconfig_Changekey);
|
|
1905
|
+
};
|
|
1906
|
+
|
|
1907
|
+
if (_j === -1) {
|
|
1908
|
+
_vals.forEach((val, m) => changeTargetColor(val, m));
|
|
1909
|
+
} else {
|
|
1910
|
+
changeTargetColor(_vals, _j);
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
|
|
1914
|
+
/**
|
|
1915
|
+
* カラーグループ、シャッフルグループの再設定
|
|
1916
|
+
* @param {string} _type
|
|
1917
|
+
* @param {string} _keyCtrlPtn
|
|
1918
|
+
*/
|
|
1919
|
+
const resetGroupList = (_type, _keyCtrlPtn) => {
|
|
1920
|
+
let k = 1;
|
|
1921
|
+
g_keycons[`${_type}Groups`] = [0];
|
|
1922
|
+
|
|
1923
|
+
while (g_keyObj[`${_type}${_keyCtrlPtn}_${k}`] !== undefined) {
|
|
1924
|
+
g_keycons[`${_type}Groups`].push(k);
|
|
1925
|
+
k++;
|
|
1926
|
+
}
|
|
1927
|
+
if (g_keyObj.currentPtn === -1
|
|
1928
|
+
&& (_type !== `stepRtn` || (_type === `stepRtn` && g_keycons[`${_type}Groups`].length > 1))) {
|
|
1929
|
+
g_keycons[`${_type}Groups`] = addValtoArray(g_keycons[`${_type}Groups`], -1);
|
|
1930
|
+
}
|
|
1931
|
+
g_keycons[`${_type}GroupNum`] = Math.min(g_keyObj.currentPtn, 0);
|
|
1932
|
+
};
|