js_lis 1.0.25 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VirtualKeyboard.js +186 -312
- package/layouts.js +12 -27
- package/package.json +1 -1
package/VirtualKeyboard.js
CHANGED
|
@@ -12,10 +12,7 @@ export class VirtualKeyboard {
|
|
|
12
12
|
this.offsetY = 0;
|
|
13
13
|
this.shiftActive = false;
|
|
14
14
|
this.capsLockActive = false;
|
|
15
|
-
|
|
16
|
-
// กำหนดคีย์และ IV สำหรับการเข้ารหัส
|
|
17
|
-
this.secretKey = "1234567890abcdef1234567890abcdef"; // คีย์ความยาว 32 bytes
|
|
18
|
-
this.iv = CryptoJS.lib.WordArray.random(16); // สร้าง IV ความยาว 16 bytes
|
|
15
|
+
this.isScrambled = false;
|
|
19
16
|
|
|
20
17
|
this.initialize();
|
|
21
18
|
}
|
|
@@ -30,64 +27,18 @@ export class VirtualKeyboard {
|
|
|
30
27
|
}
|
|
31
28
|
}
|
|
32
29
|
|
|
33
|
-
encodeText(text) {
|
|
34
|
-
const encrypted = CryptoJS.AES.encrypt(
|
|
35
|
-
text,
|
|
36
|
-
CryptoJS.enc.Hex.parse(this.secretKey),
|
|
37
|
-
{
|
|
38
|
-
iv: this.iv,
|
|
39
|
-
mode: CryptoJS.mode.CBC,
|
|
40
|
-
padding: CryptoJS.pad.Pkcs7,
|
|
41
|
-
}
|
|
42
|
-
);
|
|
43
|
-
return {
|
|
44
|
-
encrypted: encrypted.ciphertext.toString(CryptoJS.enc.Base64),
|
|
45
|
-
iv: this.iv.toString(CryptoJS.enc.Base64),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
decodeText(encryptedData) {
|
|
50
|
-
if (!encryptedData || !encryptedData.encrypted || !encryptedData.iv) {
|
|
51
|
-
if (encryptedData === "\t") {
|
|
52
|
-
return "\t";
|
|
53
|
-
} else {
|
|
54
|
-
return " ";
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
const decrypted = CryptoJS.AES.decrypt(
|
|
60
|
-
{ ciphertext: CryptoJS.enc.Base64.parse(encryptedData.encrypted) },
|
|
61
|
-
CryptoJS.enc.Hex.parse(this.secretKey),
|
|
62
|
-
{
|
|
63
|
-
iv: CryptoJS.enc.Base64.parse(encryptedData.iv),
|
|
64
|
-
mode: CryptoJS.mode.CBC,
|
|
65
|
-
padding: CryptoJS.pad.Pkcs7,
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
|
-
return decrypted.toString(CryptoJS.enc.Utf8);
|
|
69
|
-
} catch (error) {
|
|
70
|
-
console.error("Error decoding text:", error);
|
|
71
|
-
return " ";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
30
|
getLayoutName(layout) {
|
|
76
31
|
switch (layout) {
|
|
77
32
|
case "full":
|
|
78
33
|
return "Full Keyboard";
|
|
79
34
|
case "en":
|
|
80
35
|
return "English Keyboard";
|
|
81
|
-
case "enSc":
|
|
82
|
-
return "English scrambled";
|
|
83
36
|
case "th":
|
|
84
37
|
return "Thai keyboard";
|
|
85
|
-
case "thSc":
|
|
86
|
-
return "Thai scrambled";
|
|
87
38
|
case "numpad":
|
|
88
39
|
return "Numpad Keyboard";
|
|
89
|
-
case "
|
|
90
|
-
return "
|
|
40
|
+
case "symbols":
|
|
41
|
+
return "Symbols Keyboard";
|
|
91
42
|
default:
|
|
92
43
|
return "Unknown Layout";
|
|
93
44
|
}
|
|
@@ -127,6 +78,7 @@ export class VirtualKeyboard {
|
|
|
127
78
|
this.currentInput.classList.add("keyboard-active");
|
|
128
79
|
}
|
|
129
80
|
|
|
81
|
+
// [1]
|
|
130
82
|
render() {
|
|
131
83
|
const keyboard = document.createElement("div");
|
|
132
84
|
keyboard.className = `virtual-keyboard ${this.currentLayout}`;
|
|
@@ -144,7 +96,7 @@ export class VirtualKeyboard {
|
|
|
144
96
|
layoutSelector.id = "layout-selector";
|
|
145
97
|
layoutSelector.onchange = (e) => this.changeLayout(e.target.value);
|
|
146
98
|
|
|
147
|
-
const layouts = ["full", "en", "
|
|
99
|
+
const layouts = ["full", "en", "th", "numpad", "symbols"];
|
|
148
100
|
layouts.forEach((layout) => {
|
|
149
101
|
const option = document.createElement("option");
|
|
150
102
|
option.value = layout;
|
|
@@ -202,24 +154,12 @@ export class VirtualKeyboard {
|
|
|
202
154
|
this.container.innerHTML = "";
|
|
203
155
|
this.container.appendChild(keyboard);
|
|
204
156
|
|
|
205
|
-
if (this.currentLayout === "scNum") {
|
|
206
|
-
this.scrambleKeyboard();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (this.currentLayout === "enSc") {
|
|
210
|
-
this.scrambleEnglishKeys();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (this.currentLayout === "thSc") {
|
|
214
|
-
this.scrambleThaiKeys();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
157
|
keyboard.addEventListener("mousedown", (event) => this.startDrag(event));
|
|
218
158
|
}
|
|
219
159
|
|
|
160
|
+
// [2]
|
|
220
161
|
async handleKeyPress(keyPressed) {
|
|
221
162
|
if (!this.currentInput) return;
|
|
222
|
-
|
|
223
163
|
const start = this.currentInput.selectionStart;
|
|
224
164
|
const end = this.currentInput.selectionEnd;
|
|
225
165
|
const value = this.currentInput.value;
|
|
@@ -234,21 +174,72 @@ export class VirtualKeyboard {
|
|
|
234
174
|
return char.toLowerCase();
|
|
235
175
|
};
|
|
236
176
|
|
|
237
|
-
if (!keyPressed)
|
|
238
|
-
|
|
177
|
+
if (!keyPressed) return console.error("Invalid key pressed.");
|
|
178
|
+
|
|
179
|
+
if (keyPressed === "scr" || keyPressed === "scrambled") {
|
|
180
|
+
if (this.currentLayout === "en") {
|
|
181
|
+
if (this.isScrambled) {
|
|
182
|
+
this.unscrambleKeys();
|
|
183
|
+
} else {
|
|
184
|
+
this.scrambleEnglishKeys();
|
|
185
|
+
}
|
|
186
|
+
this.isScrambled = !this.isScrambled;
|
|
187
|
+
document
|
|
188
|
+
.querySelectorAll('.key[data-key="scrambled"]')
|
|
189
|
+
.forEach((key) => {
|
|
190
|
+
key.classList.toggle("active", this.isScrambled);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (this.currentLayout === "th") {
|
|
195
|
+
if (this.isScrambled) {
|
|
196
|
+
this.unscrambleKeys();
|
|
197
|
+
} else {
|
|
198
|
+
this.scrambleThaiKeys();
|
|
199
|
+
}
|
|
200
|
+
this.isScrambled = !this.isScrambled;
|
|
201
|
+
document
|
|
202
|
+
.querySelectorAll('.key[data-key="scrambled"]')
|
|
203
|
+
.forEach((key) => {
|
|
204
|
+
key.classList.toggle("active", this.isScrambled);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (this.currentLayout === "numpad") {
|
|
209
|
+
if (this.isScrambled) {
|
|
210
|
+
this.unscrambleKeys();
|
|
211
|
+
} else {
|
|
212
|
+
this.scrambleKeyboard();
|
|
213
|
+
}
|
|
214
|
+
this.isScrambled = !this.isScrambled;
|
|
215
|
+
document.querySelectorAll('.key[data-key="scr"]').forEach((key) => {
|
|
216
|
+
key.classList.toggle("active", this.isScrambled);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (this.currentLayout === "symbols") {
|
|
221
|
+
if (this.isScrambled) {
|
|
222
|
+
this.unscrambleKeys();
|
|
223
|
+
} else {
|
|
224
|
+
this.scrambleSymbols();
|
|
225
|
+
}
|
|
226
|
+
this.isScrambled = !this.isScrambled;
|
|
227
|
+
document.querySelectorAll('.key[data-key="scr"]').forEach((key) => {
|
|
228
|
+
key.classList.toggle("active", this.isScrambled);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
239
231
|
return;
|
|
240
232
|
}
|
|
241
233
|
|
|
242
234
|
switch (keyPressed) {
|
|
243
235
|
case "Esc":
|
|
244
|
-
// ปิดหน้าต่างป๊อปอัพหรือยกเลิกการทำงานปัจจุบัน
|
|
245
236
|
const modals = document.querySelectorAll(".modal");
|
|
246
237
|
if (modals.length === 0) {
|
|
247
238
|
document.exitFullscreen();
|
|
248
239
|
console.warn("No modals found to close.");
|
|
249
240
|
}
|
|
250
241
|
modals.forEach((modal) => {
|
|
251
|
-
modal.classList.add("hidden");
|
|
242
|
+
modal.classList.add("hidden");
|
|
252
243
|
});
|
|
253
244
|
break;
|
|
254
245
|
|
|
@@ -332,27 +323,21 @@ export class VirtualKeyboard {
|
|
|
332
323
|
case "Backspace":
|
|
333
324
|
case "backspace":
|
|
334
325
|
if (start === end && start > 0) {
|
|
335
|
-
this.currentInput.value =
|
|
336
|
-
|
|
337
|
-
this.currentInput.selectionStart = this.currentInput.selectionEnd =
|
|
338
|
-
start - 1;
|
|
326
|
+
this.currentInput.value = value.slice(0, start - 1) + value.slice(end);
|
|
327
|
+
this.currentInput.selectionStart = this.currentInput.selectionEnd = start - 1;
|
|
339
328
|
} else {
|
|
340
329
|
this.currentInput.value = value.slice(0, start) + value.slice(end);
|
|
341
|
-
this.currentInput.selectionStart = this.currentInput.selectionEnd =
|
|
342
|
-
start;
|
|
330
|
+
this.currentInput.selectionStart = this.currentInput.selectionEnd = start;
|
|
343
331
|
}
|
|
344
332
|
break;
|
|
345
333
|
|
|
346
334
|
case "DEL⌦":
|
|
347
335
|
if (start === end && start < value.length) {
|
|
348
|
-
this.currentInput.value =
|
|
349
|
-
|
|
350
|
-
this.currentInput.selectionStart = this.currentInput.selectionEnd =
|
|
351
|
-
start;
|
|
336
|
+
this.currentInput.value = value.slice(0, start) + value.slice(end + 1);
|
|
337
|
+
this.currentInput.selectionStart = this.currentInput.selectionEnd = start;
|
|
352
338
|
} else {
|
|
353
339
|
this.currentInput.value = value.slice(0, start) + value.slice(end);
|
|
354
|
-
this.currentInput.selectionStart = this.currentInput.selectionEnd =
|
|
355
|
-
start;
|
|
340
|
+
this.currentInput.selectionStart = this.currentInput.selectionEnd = start;
|
|
356
341
|
}
|
|
357
342
|
break;
|
|
358
343
|
|
|
@@ -366,23 +351,14 @@ export class VirtualKeyboard {
|
|
|
366
351
|
|
|
367
352
|
case "Enter":
|
|
368
353
|
if (this.currentInput.tagName === "TEXTAREA") {
|
|
369
|
-
this.currentInput.value =
|
|
370
|
-
value.slice(0, start) + "\n" + value.slice(end);
|
|
354
|
+
this.currentInput.value = value.slice(0, start) + "\n" + value.slice(end);
|
|
371
355
|
this.currentInput.setSelectionRange(start + 1, start + 1);
|
|
372
|
-
} else if (
|
|
373
|
-
this.currentInput.tagName === "INPUT" ||
|
|
374
|
-
this.currentInput.type === "password" ||
|
|
375
|
-
this.currentInput.type === "text"
|
|
376
|
-
) {
|
|
356
|
+
} else if (this.currentInput.tagName === "INPUT" || this.currentInput.type === "password" || this.currentInput.type === "text" ) {
|
|
377
357
|
if (this.currentInput.form) {
|
|
378
358
|
const submitButton = this.currentInput.form.querySelector(
|
|
379
359
|
'input[type="submit"], button[type="submit"], button[type="button"], button[onclick]'
|
|
380
360
|
);
|
|
381
|
-
if (submitButton)
|
|
382
|
-
submitButton.click();
|
|
383
|
-
} else {
|
|
384
|
-
this.currentInput.form.submit();
|
|
385
|
-
}
|
|
361
|
+
if (submitButton) submitButton.click(); else this.currentInput.form.submit();
|
|
386
362
|
} else {
|
|
387
363
|
this.currentInput.value += "\n";
|
|
388
364
|
}
|
|
@@ -418,267 +394,154 @@ export class VirtualKeyboard {
|
|
|
418
394
|
|
|
419
395
|
if (keyPressed === "↑" && currentLineIndex > 0) {
|
|
420
396
|
const prevLineLength = lines[currentLineIndex - 1].length;
|
|
421
|
-
const newPos =
|
|
422
|
-
start -
|
|
423
|
-
currentLine.length -
|
|
424
|
-
1 -
|
|
425
|
-
Math.min(columnIndex, prevLineLength);
|
|
397
|
+
const newPos = start - currentLine.length - 1 - Math.min(columnIndex, prevLineLength);
|
|
426
398
|
this.currentInput.setSelectionRange(newPos, newPos);
|
|
427
399
|
} else if (keyPressed === "↓" && currentLineIndex < lines.length - 1) {
|
|
428
400
|
const nextLine = lines[currentLineIndex + 1];
|
|
429
|
-
const newPos =
|
|
430
|
-
start +
|
|
431
|
-
currentLine.length +
|
|
432
|
-
1 +
|
|
433
|
-
Math.min(columnIndex, nextLine.length);
|
|
401
|
+
const newPos = start + currentLine.length + 1 + Math.min(columnIndex, nextLine.length);
|
|
434
402
|
this.currentInput.setSelectionRange(newPos, newPos);
|
|
435
403
|
}
|
|
436
404
|
break;
|
|
437
405
|
|
|
438
406
|
default:
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
);
|
|
442
|
-
await this.insertText(encryptedText);
|
|
407
|
+
const textvalue = await convertToCorrectCase(keyPressed);
|
|
408
|
+
await this.insertText(textvalue);
|
|
443
409
|
}
|
|
444
410
|
|
|
445
|
-
if (isShiftActive && !isCapsActive)
|
|
446
|
-
this.toggleShift();
|
|
447
|
-
}
|
|
411
|
+
if (isShiftActive && !isCapsActive) this.toggleShift();
|
|
448
412
|
|
|
449
413
|
this.currentInput.focus();
|
|
450
414
|
const event = new Event("input", { bubbles: true });
|
|
451
415
|
this.currentInput.dispatchEvent(event);
|
|
452
416
|
}
|
|
453
417
|
|
|
418
|
+
// [3]
|
|
454
419
|
async insertText(text) {
|
|
455
420
|
const start = this.currentInput.selectionStart;
|
|
456
421
|
const end = this.currentInput.selectionEnd;
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
this.currentInput.value =
|
|
460
|
-
|
|
461
|
-
decodedText +
|
|
462
|
-
this.currentInput.value.slice(end);
|
|
463
|
-
this.currentInput.selectionStart = this.currentInput.selectionEnd =
|
|
464
|
-
start + decodedText.length;
|
|
422
|
+
const textvalue = text;
|
|
423
|
+
|
|
424
|
+
this.currentInput.value = this.currentInput.value.slice(0, start) + textvalue + this.currentInput.value.slice(end);
|
|
425
|
+
this.currentInput.selectionStart = this.currentInput.selectionEnd = start + textvalue.length;
|
|
465
426
|
}
|
|
466
427
|
|
|
428
|
+
// [4]
|
|
429
|
+
unscrambleKeys() {
|
|
430
|
+
this.keys = this.originalKeys;
|
|
431
|
+
this.render();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// [5]
|
|
467
435
|
toggleCapsLock() {
|
|
468
436
|
this.capsLockActive = !this.capsLockActive;
|
|
437
|
+
|
|
469
438
|
document.querySelectorAll('.key[data-key="Caps 🄰"]').forEach((key) => {
|
|
470
439
|
key.classList.toggle("active", this.capsLockActive);
|
|
471
440
|
key.classList.toggle("bg-gray-400", this.capsLockActive);
|
|
472
441
|
});
|
|
473
442
|
|
|
474
443
|
document.querySelectorAll(".key").forEach((key) => {
|
|
475
|
-
|
|
444
|
+
const isLetter = key.dataset.key.length === 1 && /[a-zA-Zก-๙]/.test(key.dataset.key);
|
|
445
|
+
|
|
446
|
+
if (isLetter) {
|
|
476
447
|
key.textContent = this.capsLockActive
|
|
477
448
|
? key.dataset.key.toUpperCase()
|
|
478
449
|
: key.dataset.key.toLowerCase();
|
|
479
450
|
}
|
|
451
|
+
this.updateKeyContent(key, this.capsLockActive);
|
|
480
452
|
});
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (originalKey) {
|
|
504
|
-
key.textContent = originalKey;
|
|
505
|
-
key.dataset.key = originalKey;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (
|
|
510
|
-
this.capsLockActive &&
|
|
511
|
-
(this.currentLayout === "en" || this.currentLayout === "enSc") &&
|
|
512
|
-
this.EngAlphabetShift[currentChar]
|
|
513
|
-
) {
|
|
514
|
-
key.textContent = this.EngAlphabetShift[currentChar];
|
|
515
|
-
key.dataset.key = this.EngAlphabetShift[currentChar];
|
|
516
|
-
} else if (
|
|
517
|
-
!this.capsLockActive &&
|
|
518
|
-
(this.currentLayout === "en" || this.currentLayout === "enSc") &&
|
|
519
|
-
Object.values(this.EngAlphabetShift).includes(currentChar)
|
|
520
|
-
) {
|
|
521
|
-
const originalKey = Object.keys(this.EngAlphabetShift).find(
|
|
522
|
-
(key) => this.EngAlphabetShift[key] === currentChar
|
|
523
|
-
);
|
|
524
|
-
if (originalKey) {
|
|
525
|
-
key.textContent = originalKey;
|
|
526
|
-
key.dataset.key = originalKey;
|
|
527
|
-
}
|
|
453
|
+
}
|
|
454
|
+
updateKeyContent(key, capsLockActive) {
|
|
455
|
+
const currentChar = key.textContent.trim();
|
|
456
|
+
|
|
457
|
+
const layouts = {
|
|
458
|
+
th: this.ThaiAlphabetShift,
|
|
459
|
+
en: this.EngAlphabetShift,
|
|
460
|
+
enSc: this.EngAlphabetShift,
|
|
461
|
+
full: this.FullAlphabetShift,
|
|
462
|
+
};
|
|
463
|
+
const layout = layouts[this.currentLayout];
|
|
464
|
+
|
|
465
|
+
if (!layout) return;
|
|
466
|
+
|
|
467
|
+
if (capsLockActive && layout[currentChar]) {
|
|
468
|
+
key.textContent = layout[currentChar];
|
|
469
|
+
key.dataset.key = layout[currentChar];
|
|
470
|
+
} else if (!capsLockActive && Object.values(layout).includes(currentChar)) {
|
|
471
|
+
const originalKey = Object.keys(layout).find((k) => layout[k] === currentChar);
|
|
472
|
+
if (originalKey) {
|
|
473
|
+
key.textContent = originalKey;
|
|
474
|
+
key.dataset.key = originalKey;
|
|
528
475
|
}
|
|
529
|
-
}
|
|
476
|
+
}
|
|
530
477
|
}
|
|
531
478
|
|
|
479
|
+
// [6]
|
|
532
480
|
toggleShift() {
|
|
481
|
+
if (this.capsLockActive) {
|
|
482
|
+
return this.toggleCapsLock();
|
|
483
|
+
}
|
|
484
|
+
|
|
533
485
|
this.shiftActive = !this.shiftActive;
|
|
534
486
|
document.querySelectorAll('.key[data-key="Shift ⇧"]').forEach((key) => {
|
|
535
487
|
key.classList.toggle("active", this.shiftActive);
|
|
488
|
+
key.classList.toggle("bg-gray-400", this.shiftActive);
|
|
536
489
|
});
|
|
537
|
-
|
|
490
|
+
|
|
538
491
|
document.querySelectorAll(".key").forEach((key) => {
|
|
539
|
-
|
|
492
|
+
const isLetter = key.dataset.key.length === 1 && /[a-zA-Zก-๙]/.test(key.dataset.key);
|
|
493
|
+
|
|
494
|
+
if (isLetter) {
|
|
540
495
|
key.textContent = this.shiftActive
|
|
541
496
|
? key.dataset.key.toUpperCase()
|
|
542
497
|
: key.dataset.key.toLowerCase();
|
|
543
498
|
}
|
|
499
|
+
this.updateKeyContent(key, this.shiftActive);
|
|
544
500
|
});
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
)
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
);
|
|
568
|
-
if (originalKey) {
|
|
569
|
-
key.textContent = originalKey;
|
|
570
|
-
key.dataset.key = originalKey;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
if (
|
|
575
|
-
this.shiftActive &&
|
|
576
|
-
(this.currentLayout === "en" || this.currentLayout === "enSc") &&
|
|
577
|
-
this.EngAlphabetShift[currentChar]
|
|
578
|
-
) {
|
|
579
|
-
key.textContent = this.EngAlphabetShift[currentChar];
|
|
580
|
-
key.dataset.key = this.EngAlphabetShift[currentChar];
|
|
581
|
-
} else if (
|
|
582
|
-
!this.shiftActive &&
|
|
583
|
-
(this.currentLayout === "en" || this.currentLayout === "enSc") &&
|
|
584
|
-
Object.values(this.EngAlphabetShift).includes(currentChar)
|
|
585
|
-
) {
|
|
586
|
-
// เปลี่ยนกลับเมื่อปิด Shift
|
|
587
|
-
const originalKey = Object.keys(this.EngAlphabetShift).find(
|
|
588
|
-
(key) => this.EngAlphabetShift[key] === currentChar
|
|
589
|
-
);
|
|
590
|
-
if (originalKey) {
|
|
591
|
-
key.textContent = originalKey;
|
|
592
|
-
key.dataset.key = originalKey;
|
|
593
|
-
}
|
|
501
|
+
}
|
|
502
|
+
updateKeyContent(key, shiftActive) {
|
|
503
|
+
const currentChar = key.textContent.trim();
|
|
504
|
+
|
|
505
|
+
const layouts = {
|
|
506
|
+
th: this.ThaiAlphabetShift,
|
|
507
|
+
en: this.EngAlphabetShift,
|
|
508
|
+
enSc: this.EngAlphabetShift,
|
|
509
|
+
full: this.FullAlphabetShift,
|
|
510
|
+
};
|
|
511
|
+
const layout = layouts[this.currentLayout];
|
|
512
|
+
|
|
513
|
+
if (!layout) return;
|
|
514
|
+
|
|
515
|
+
if (shiftActive && layout[currentChar]) {
|
|
516
|
+
key.textContent = layout[currentChar];
|
|
517
|
+
key.dataset.key = layout[currentChar];
|
|
518
|
+
} else if (!shiftActive && Object.values(layout).includes(currentChar)) {
|
|
519
|
+
const originalKey = Object.keys(layout).find((k) => layout[k] === currentChar);
|
|
520
|
+
if (originalKey) {
|
|
521
|
+
key.textContent = originalKey;
|
|
522
|
+
key.dataset.key = originalKey;
|
|
594
523
|
}
|
|
595
|
-
}
|
|
524
|
+
}
|
|
596
525
|
}
|
|
597
526
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
3: "#",
|
|
603
|
-
4: "$",
|
|
604
|
-
5: "%",
|
|
605
|
-
6: "^",
|
|
606
|
-
7: "&",
|
|
607
|
-
8: "*",
|
|
608
|
-
9: "(",
|
|
609
|
-
0: ")",
|
|
610
|
-
"-": "_",
|
|
611
|
-
"=": "+",
|
|
612
|
-
"[": "{",
|
|
613
|
-
"]": "}",
|
|
614
|
-
"\\": "|",
|
|
615
|
-
";": ":",
|
|
616
|
-
"'": '"',
|
|
617
|
-
",": "<",
|
|
618
|
-
".": ">",
|
|
619
|
-
"/": "?",
|
|
620
|
-
};
|
|
621
|
-
|
|
622
|
-
ThaiAlphabetShift = {
|
|
623
|
-
_: "%",
|
|
624
|
-
ๅ: "+",
|
|
625
|
-
"/": "๑",
|
|
626
|
-
"-": "๒",
|
|
627
|
-
ภ: "๓",
|
|
628
|
-
ถ: "๔",
|
|
629
|
-
"ุ": "ู",
|
|
630
|
-
"ึ": "฿",
|
|
631
|
-
ค: "๕",
|
|
632
|
-
ต: "๖",
|
|
633
|
-
จ: "๗",
|
|
634
|
-
ข: "๘",
|
|
635
|
-
ช: "๙",
|
|
636
|
-
ๆ: "๐",
|
|
637
|
-
ไ: '"',
|
|
638
|
-
ำ: "ฎ",
|
|
639
|
-
พ: "ฑ",
|
|
640
|
-
ะ: "ธ",
|
|
641
|
-
"ั": "ํ",
|
|
642
|
-
"ี": "๋",
|
|
643
|
-
ร: "ณ",
|
|
644
|
-
น: "ฯ",
|
|
645
|
-
ย: "ญ",
|
|
646
|
-
บ: "ฐ",
|
|
647
|
-
ล: ",",
|
|
648
|
-
ฃ: "ฅ",
|
|
649
|
-
ฟ: "ฤ",
|
|
650
|
-
ห: "ฆ",
|
|
651
|
-
ก: "ฏ",
|
|
652
|
-
ด: "โ",
|
|
653
|
-
เ: "ฌ",
|
|
654
|
-
"้": "็",
|
|
655
|
-
"่": "๋",
|
|
656
|
-
า: "ษ",
|
|
657
|
-
ส: "ศ",
|
|
658
|
-
ว: "ซ",
|
|
659
|
-
ง: ".",
|
|
660
|
-
ผ: "(",
|
|
661
|
-
ป: ")",
|
|
662
|
-
แ: "ฉ",
|
|
663
|
-
อ: "ฮ",
|
|
664
|
-
"ิ": "ฺ",
|
|
665
|
-
"ื": "์",
|
|
666
|
-
ท: "?",
|
|
667
|
-
ม: "ฒ",
|
|
668
|
-
ใ: "ฬ",
|
|
669
|
-
ฝ: "ฦ",
|
|
670
|
-
};
|
|
527
|
+
// [7]
|
|
528
|
+
EngAlphabetShift = { "`": "~", 1: "!", 2: "@", 3: "#", 4: "$", 5: "%", 6: "^", 7: "&", 8: "*", 9: "(", 0: ")", "-": "_", "=": "+", "[": "{", "]": "}", "\\": "|", ";": ":", "'": '"', ",": "<", ".": ">", "/": "?", };
|
|
529
|
+
ThaiAlphabetShift = { _: "%", ๅ: "+", "/": "๑", "-": "๒", ภ: "๓", ถ: "๔", "ุ": "ู", "ึ": "฿", ค: "๕", ต: "๖", จ: "๗", ข: "๘", ช: "๙", ๆ: "๐", ไ: '"', ำ: "ฎ", พ: "ฑ", ะ: "ธ", "ั": "ํ", "ี": "๋", ร: "ณ", น: "ฯ", ย: "ญ", บ: "ฐ", ล: ",", ฃ: "ฅ", ฟ: "ฤ", ห: "ฆ", ก: "ฏ", ด: "โ", เ: "ฌ", "้": "็", "่": "๋", า: "ษ", ส: "ศ", ว: "ซ", ง: ".", ผ: "(", ป: ")", แ: "ฉ", อ: "ฮ", "ิ": "ฺ", "ื": "์", ท: "?", ม: "ฒ", ใ: "ฬ", ฝ: "ฦ"};
|
|
530
|
+
FullAlphabetShift = { "[": "{", "]": "}", "\\": "|", ";": ":", "'": '"', ",": "<", ".": ">", "/": "?", };
|
|
671
531
|
|
|
532
|
+
// [8]
|
|
672
533
|
toggle() {
|
|
673
534
|
this.isVisible = !this.isVisible;
|
|
674
535
|
this.render();
|
|
675
536
|
}
|
|
676
537
|
|
|
538
|
+
// [9]
|
|
677
539
|
changeLayout(layout) {
|
|
678
540
|
this.currentLayout = layout;
|
|
679
541
|
this.render();
|
|
680
542
|
}
|
|
681
543
|
|
|
544
|
+
// [10]
|
|
682
545
|
shuffleArray(array) {
|
|
683
546
|
for (let i = array.length - 1; i > 0; i--) {
|
|
684
547
|
const j = Math.floor(Math.random() * (i + 1));
|
|
@@ -686,11 +549,12 @@ export class VirtualKeyboard {
|
|
|
686
549
|
}
|
|
687
550
|
}
|
|
688
551
|
|
|
552
|
+
// [11]
|
|
689
553
|
scrambleKeyboard() {
|
|
690
554
|
const keys = document.querySelectorAll(
|
|
691
|
-
"
|
|
555
|
+
":not([data-key='std']):not([data-key='scr']).key:not([data-key=backspace]"
|
|
692
556
|
);
|
|
693
|
-
const numbers =
|
|
557
|
+
const numbers = "1234567890-=+%/*.()".split("");
|
|
694
558
|
this.shuffleArray(numbers);
|
|
695
559
|
keys.forEach((key, index) => {
|
|
696
560
|
key.textContent = numbers[index];
|
|
@@ -698,11 +562,12 @@ export class VirtualKeyboard {
|
|
|
698
562
|
});
|
|
699
563
|
}
|
|
700
564
|
|
|
565
|
+
// [12]
|
|
701
566
|
scrambleEnglishKeys() {
|
|
702
567
|
const keys = document.querySelectorAll(
|
|
703
|
-
".key:not([data-key='
|
|
568
|
+
".key:not([data-key='scrambled']):not([data-key='std']):not([data-key='scr']):not([data-key='Space']):not([data-key='Backspace']):not([data-key='Caps 🄰']):not([data-key='Shift ⇧']):not([data-key='Enter']):not([data-key='Tab ↹'])"
|
|
704
569
|
);
|
|
705
|
-
const englishAlphabet = "abcdefghijklmnopqrstuvwxyz".split("");
|
|
570
|
+
const englishAlphabet = "abcdefghijklmnopqrstuvwxyz/.,';\\][`1234567890-=".split("");
|
|
706
571
|
this.shuffleArray(englishAlphabet);
|
|
707
572
|
keys.forEach((key, index) => {
|
|
708
573
|
key.textContent = englishAlphabet[index];
|
|
@@ -710,37 +575,46 @@ export class VirtualKeyboard {
|
|
|
710
575
|
});
|
|
711
576
|
}
|
|
712
577
|
|
|
578
|
+
// [13]
|
|
713
579
|
scrambleThaiKeys() {
|
|
714
580
|
const keys = document.querySelectorAll(
|
|
715
|
-
".key:not([data-key='Backspace']):not([data-key='Caps 🄰']):not([data-key='Shift ⇧']):not([data-key='Enter']):not([data-key='Space'])"
|
|
716
|
-
);
|
|
717
|
-
const ThaiAlphabet = "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮ".split(
|
|
718
|
-
""
|
|
581
|
+
".key:not([data-key='scrambled']):not([data-key='scr']):not([data-key='Backspace']):not([data-key='Caps 🄰']):not([data-key='Shift ⇧']):not([data-key='Enter']):not([data-key='Space']):not([data-key='Tab ↹'])"
|
|
719
582
|
);
|
|
720
|
-
|
|
721
|
-
|
|
583
|
+
const ThaiAlphabet = '_ๅ/-ภถุึคตจขชๆไำพะัีรนยบลฃฟหกดเ้่าสวงผปแอิืทมใฝ%+๑๒๓๔ู฿๕๖๗๘๙๐"ฎฑธํ๊ณฯญฐ,ฅฤฆฏโฌ็๋ษศซ.ฦฬฒ?์ฺฮฉ)('.split("");
|
|
584
|
+
this.shuffleArray(ThaiAlphabet);
|
|
722
585
|
keys.forEach((key, index) => {
|
|
723
|
-
// อัพเดต textContent และ dataset.key ให้ตรงกับค่าใหม่ที่สับเปลี่ยน
|
|
724
586
|
key.textContent = ThaiAlphabet[index];
|
|
725
|
-
key.dataset.key = ThaiAlphabet[index];
|
|
587
|
+
key.dataset.key = ThaiAlphabet[index];
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// []
|
|
592
|
+
scrambleSymbols() {
|
|
593
|
+
const keys = document.querySelectorAll(
|
|
594
|
+
":not([data-key='std']):not([data-key='scr']).key:not([data-key=backspace]"
|
|
595
|
+
);
|
|
596
|
+
const numbers = "@#$%^&*()_+~`{}|\\:'<>?/[]±§¶!€£¥¢©®™℅‰†".split("");
|
|
597
|
+
this.shuffleArray(numbers);
|
|
598
|
+
keys.forEach((key, index) => {
|
|
599
|
+
key.textContent = numbers[index];
|
|
600
|
+
key.dataset.key = numbers[index];
|
|
726
601
|
});
|
|
727
602
|
}
|
|
728
603
|
|
|
729
|
-
// จัดการการลากคีย์บอร์ด
|
|
604
|
+
// [14] จัดการการลากคีย์บอร์ด
|
|
730
605
|
startDrag(event) {
|
|
731
606
|
this.isDragging = true;
|
|
732
|
-
this.offsetX =
|
|
733
|
-
|
|
734
|
-
this.offsetY =
|
|
735
|
-
event.clientY - document.getElementById("keyboard").offsetTop;
|
|
607
|
+
this.offsetX = event.clientX - document.getElementById("keyboard").offsetLeft;
|
|
608
|
+
this.offsetY = event.clientY - document.getElementById("keyboard").offsetTop;
|
|
736
609
|
|
|
737
|
-
document.addEventListener("mousemove", this.drag.bind(this));
|
|
610
|
+
document.addEventListener("mousemove", this.drag.bind(this));
|
|
738
611
|
document.addEventListener("mouseup", () => {
|
|
739
612
|
this.isDragging = false;
|
|
740
613
|
document.removeEventListener("mousemove", this.drag.bind(this));
|
|
741
614
|
});
|
|
742
615
|
}
|
|
743
616
|
|
|
617
|
+
// [15]
|
|
744
618
|
drag(event) {
|
|
745
619
|
if (this.isDragging) {
|
|
746
620
|
const keyboard = document.getElementById("keyboard");
|
|
@@ -748,4 +622,4 @@ export class VirtualKeyboard {
|
|
|
748
622
|
keyboard.style.top = `${event.clientY - this.offsetY}px`;
|
|
749
623
|
}
|
|
750
624
|
}
|
|
751
|
-
}
|
|
625
|
+
}
|
package/layouts.js
CHANGED
|
@@ -12,43 +12,28 @@ export const layouts = {
|
|
|
12
12
|
["Tab ↹", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "\\"],
|
|
13
13
|
["Caps 🄰", "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "Enter"],
|
|
14
14
|
["Shift ⇧", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "Shift ⇧"],
|
|
15
|
-
["Space"],
|
|
15
|
+
["scrambled", "Space"],
|
|
16
16
|
],
|
|
17
17
|
th: [
|
|
18
18
|
["_", "ๅ", "/", "-", "ภ", "ถ", "ุ", "ึ", "ค", "ต", "จ", "ข", "ช", "Backspace"],
|
|
19
19
|
["Tab ↹", "ๆ", "ไ", "ำ", "พ", "ะ", "ั", "ี", "ร", "น", "ย", "บ", "ล", "ฃ"],
|
|
20
20
|
["Caps 🄰", "ฟ", "ห", "ก", "ด", "เ", "้", "่", "า", "ส", "ว", "ง", "Enter"],
|
|
21
21
|
["Shift ⇧", "ผ", "ป", "แ", "อ", "ิ", "ื", "ท", "ม", "ใ", "ฝ", "Shift ⇧"],
|
|
22
|
-
["Space"],
|
|
22
|
+
["scrambled" ,"Space"],
|
|
23
23
|
],
|
|
24
24
|
numpad: [
|
|
25
|
-
["
|
|
26
|
-
["1", "2", "3", "
|
|
27
|
-
["4", "5", "6", "
|
|
25
|
+
["scr", "+", "-", "*"],
|
|
26
|
+
["1", "2", "3", "/"],
|
|
27
|
+
["4", "5", "6", "%"],
|
|
28
28
|
["7", "8", "9", "."],
|
|
29
29
|
["(", "0", ")", "="],
|
|
30
30
|
["backspace"]
|
|
31
31
|
],
|
|
32
|
-
|
|
33
|
-
[
|
|
34
|
-
[
|
|
35
|
-
["
|
|
36
|
-
[
|
|
37
|
-
["(", "0", ")", "="],
|
|
32
|
+
symbols: [
|
|
33
|
+
['scr', '@', '#', '$', '%', '^', '&', '*', '(', ')'],
|
|
34
|
+
['_', '+', '~', '`', '{', '}', '|', '\\', ':', '!'],
|
|
35
|
+
["'", '<', '>', '?', '/', '[', ']', '±', '§', '¶'],
|
|
36
|
+
['€', '£', '¥', '¢', '©', '®', '™', '℅', '‰', '†'],
|
|
38
37
|
["backspace"]
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
["ก", "ข", "ฃ", "ค", "ฅ", "ฆ", "ง", "จ", "ฉ", "ช", "ซ", "ฌ", "Backspace"],
|
|
42
|
-
["ญ", "ฎ", "ฏ", "ฐ", "ฑ", "ฒ", "ณ", "ด", "ต", "ถ", "ท", "ธ", "น"],
|
|
43
|
-
["บ", "ป", "ผ", "ฝ", "พ", "ฟ", "ภ", "ม", "ย", "ร", "ฤ", "Enter"],
|
|
44
|
-
["ล", "ฦ", "ว", "ศ", "ษ", "ส", "ห", "ฬ", "อ", "ฮ"],
|
|
45
|
-
["Space"],
|
|
46
|
-
],
|
|
47
|
-
enSc: [
|
|
48
|
-
["`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "="],
|
|
49
|
-
["Tab ↹", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "Backspace"],
|
|
50
|
-
["Caps 🄰", "a", "s", "d", "f", "g", "h", "j", "k", "l", "Enter"],
|
|
51
|
-
["Shift ⇧", "z", "x", "c", "v", "b", "n", "m", "Shift ⇧"],
|
|
52
|
-
["Space"],
|
|
53
|
-
],
|
|
54
|
-
};
|
|
38
|
+
]
|
|
39
|
+
};
|