js_lis 1.0.8 → 1.0.9
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 +107 -62
- package/package.json +1 -1
package/VirtualKeyboard.js
CHANGED
|
@@ -5,18 +5,71 @@ export class VirtualKeyboard {
|
|
|
5
5
|
this.currentLayout = 'en';
|
|
6
6
|
this.isVisible = false;
|
|
7
7
|
this.container = document.getElementById('keyboard-container');
|
|
8
|
-
this.currentInput = null;
|
|
8
|
+
this.currentInput = null;
|
|
9
9
|
this.layouts = layouts;
|
|
10
10
|
this.isDragging = false;
|
|
11
11
|
this.offsetX = 0;
|
|
12
12
|
this.offsetY = 0;
|
|
13
13
|
this.shiftActive = false;
|
|
14
14
|
this.capsLockActive = false;
|
|
15
|
-
|
|
15
|
+
this.secretKey = '1234567890abcdef'; // คีย์ที่ใช้ในการเข้ารหัส
|
|
16
|
+
// ใช้ Web Crypto API สำหรับการจัดการคีย์
|
|
17
|
+
this.cryptoKey = null;
|
|
18
|
+
this.iv = window.crypto.getRandomValues(new Uint8Array(12)); // สร้าง IV สำหรับการเข้ารหัส/ถอดรหัส
|
|
19
|
+
this.generateKey();
|
|
20
|
+
|
|
16
21
|
this.render();
|
|
17
22
|
this.initializeInputListeners();
|
|
18
23
|
}
|
|
19
24
|
|
|
25
|
+
async generateKey() {
|
|
26
|
+
this.cryptoKey = await window.crypto.subtle.generateKey(
|
|
27
|
+
{ name: "AES-GCM", length: 256 },
|
|
28
|
+
true,
|
|
29
|
+
["encrypt", "decrypt"]
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async encodeText(text) {
|
|
34
|
+
const encodedData = new TextEncoder().encode(text);
|
|
35
|
+
const encryptedData = await window.crypto.subtle.encrypt(
|
|
36
|
+
{ name: "AES-GCM", iv: this.iv },
|
|
37
|
+
this.cryptoKey,
|
|
38
|
+
encodedData
|
|
39
|
+
);
|
|
40
|
+
return this.arrayBufferToBase64(encryptedData); // แปลงเป็น Base64
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async decodeText(base64Text) {
|
|
44
|
+
const encryptedData = this.base64ToArrayBuffer(base64Text);
|
|
45
|
+
const decryptedData = await window.crypto.subtle.decrypt(
|
|
46
|
+
{ name: "AES-GCM", iv: this.iv },
|
|
47
|
+
this.cryptoKey,
|
|
48
|
+
encryptedData
|
|
49
|
+
);
|
|
50
|
+
return new TextDecoder().decode(decryptedData);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
arrayBufferToBase64(buffer) {
|
|
54
|
+
let binary = '';
|
|
55
|
+
const bytes = new Uint8Array(buffer);
|
|
56
|
+
const len = bytes.byteLength;
|
|
57
|
+
for (let i = 0; i < len; i++) {
|
|
58
|
+
binary += String.fromCharCode(bytes[i]);
|
|
59
|
+
}
|
|
60
|
+
return window.btoa(binary);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
base64ToArrayBuffer(base64) {
|
|
64
|
+
const binaryString = window.atob(base64);
|
|
65
|
+
const len = binaryString.length;
|
|
66
|
+
const bytes = new Uint8Array(len);
|
|
67
|
+
for (let i = 0; i < len; i++) {
|
|
68
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
69
|
+
}
|
|
70
|
+
return bytes.buffer;
|
|
71
|
+
}
|
|
72
|
+
|
|
20
73
|
getLayoutName(layout) {
|
|
21
74
|
switch (layout) {
|
|
22
75
|
case 'en': return 'English Keyboard';
|
|
@@ -29,7 +82,6 @@ export class VirtualKeyboard {
|
|
|
29
82
|
}
|
|
30
83
|
|
|
31
84
|
initializeInputListeners() {
|
|
32
|
-
// เพิ่ม event listener สำหรับทุก input และ textarea
|
|
33
85
|
document.addEventListener('click', (e) => {
|
|
34
86
|
const target = e.target;
|
|
35
87
|
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
|
|
@@ -37,7 +89,6 @@ export class VirtualKeyboard {
|
|
|
37
89
|
}
|
|
38
90
|
});
|
|
39
91
|
|
|
40
|
-
// เพิ่ม event listener สำหรับ focus
|
|
41
92
|
document.addEventListener('focus', (e) => {
|
|
42
93
|
const target = e.target;
|
|
43
94
|
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
|
|
@@ -48,40 +99,35 @@ export class VirtualKeyboard {
|
|
|
48
99
|
document.addEventListener('click', (e) => {
|
|
49
100
|
const target = document.getElementById("toggle");
|
|
50
101
|
target.addEventListener('click', this.toggle.bind(this), { once: true });
|
|
51
|
-
});
|
|
102
|
+
});
|
|
52
103
|
}
|
|
53
104
|
|
|
54
105
|
setCurrentInput(inputElement) {
|
|
55
|
-
// ถ้ามี input เก่า ให้ลบ class active
|
|
56
106
|
if (this.currentInput) {
|
|
57
107
|
this.currentInput.classList.remove('keyboard-active');
|
|
58
108
|
}
|
|
59
|
-
|
|
60
|
-
// เซ็ต input ใหม่และเพิ่ม class active
|
|
109
|
+
|
|
61
110
|
this.currentInput = inputElement;
|
|
62
111
|
this.currentInput.classList.add('keyboard-active');
|
|
63
112
|
}
|
|
64
|
-
|
|
113
|
+
|
|
65
114
|
render() {
|
|
66
115
|
const keyboard = document.createElement('div');
|
|
67
116
|
keyboard.className = 'virtual-keyboard';
|
|
68
117
|
keyboard.style.display = this.isVisible ? 'block' : 'none';
|
|
69
|
-
|
|
70
|
-
// Add the ID for easy reference in dragging
|
|
71
118
|
keyboard.id = 'keyboard';
|
|
72
|
-
|
|
73
|
-
// New: Add Layout selector at the top inside the keyboard div
|
|
119
|
+
|
|
74
120
|
const controlsContainer = document.createElement('div');
|
|
75
121
|
controlsContainer.className = 'controls';
|
|
76
122
|
controlsContainer.style.display = 'flex';
|
|
77
123
|
controlsContainer.style.justifyContent = 'center';
|
|
78
124
|
controlsContainer.style.alignItems = 'center';
|
|
79
|
-
controlsContainer.style.marginBottom = '10px';
|
|
80
|
-
|
|
125
|
+
controlsContainer.style.marginBottom = '10px';
|
|
126
|
+
|
|
81
127
|
const layoutSelector = document.createElement('select');
|
|
82
128
|
layoutSelector.id = 'layout-selector';
|
|
83
129
|
layoutSelector.onchange = (e) => this.changeLayout(e.target.value);
|
|
84
|
-
|
|
130
|
+
|
|
85
131
|
const layouts = ['en', 'enSc', 'th', 'thSc', 'numpad', 'scNum'];
|
|
86
132
|
layouts.forEach(layout => {
|
|
87
133
|
const option = document.createElement('option');
|
|
@@ -91,32 +137,31 @@ export class VirtualKeyboard {
|
|
|
91
137
|
});
|
|
92
138
|
layoutSelector.value = this.currentLayout;
|
|
93
139
|
controlsContainer.appendChild(layoutSelector);
|
|
94
|
-
|
|
140
|
+
|
|
95
141
|
keyboard.appendChild(controlsContainer);
|
|
96
|
-
|
|
142
|
+
|
|
97
143
|
const layout = this.layouts[this.currentLayout];
|
|
98
|
-
|
|
144
|
+
|
|
99
145
|
layout.forEach(row => {
|
|
100
146
|
const rowElement = document.createElement('div');
|
|
101
147
|
rowElement.className = 'keyboard-row';
|
|
102
|
-
|
|
148
|
+
|
|
103
149
|
row.forEach(key => {
|
|
104
150
|
const keyElement = document.createElement('button');
|
|
105
|
-
keyElement.className = 'keyboard-key key';
|
|
151
|
+
keyElement.className = 'keyboard-key key';
|
|
106
152
|
keyElement.textContent = key;
|
|
107
153
|
keyElement.type = 'button';
|
|
108
|
-
|
|
109
|
-
// Add data-key to each key for reference
|
|
154
|
+
|
|
110
155
|
keyElement.dataset.key = key;
|
|
111
|
-
|
|
156
|
+
|
|
112
157
|
if (key === 'Space') {
|
|
113
158
|
keyElement.className += ' space';
|
|
114
159
|
}
|
|
115
|
-
|
|
160
|
+
|
|
116
161
|
if (key === 'backspace') {
|
|
117
162
|
keyElement.className += ' backspacew';
|
|
118
163
|
}
|
|
119
|
-
|
|
164
|
+
|
|
120
165
|
keyElement.onclick = (e) => {
|
|
121
166
|
e.preventDefault();
|
|
122
167
|
const keyPressed = keyElement.dataset.key || keyElement.textContent;
|
|
@@ -126,57 +171,53 @@ export class VirtualKeyboard {
|
|
|
126
171
|
console.error("The key element does not have a valid key value.");
|
|
127
172
|
}
|
|
128
173
|
};
|
|
129
|
-
|
|
174
|
+
|
|
130
175
|
rowElement.appendChild(keyElement);
|
|
131
176
|
});
|
|
132
|
-
|
|
177
|
+
|
|
133
178
|
keyboard.appendChild(rowElement);
|
|
134
179
|
});
|
|
135
|
-
|
|
180
|
+
|
|
136
181
|
this.container.innerHTML = '';
|
|
137
182
|
this.container.appendChild(keyboard);
|
|
138
|
-
|
|
183
|
+
|
|
139
184
|
if (this.currentLayout === "scNum") {
|
|
140
185
|
this.scrambleKeyboard();
|
|
141
186
|
}
|
|
142
|
-
|
|
187
|
+
|
|
143
188
|
if (this.currentLayout === "enSc") {
|
|
144
189
|
this.scrambleEnglishKeys();
|
|
145
190
|
}
|
|
146
|
-
|
|
191
|
+
|
|
147
192
|
if (this.currentLayout === "thSc") {
|
|
148
193
|
this.scrambleThaiKeys();
|
|
149
194
|
}
|
|
150
|
-
|
|
151
|
-
// Add drag functionality to the keyboard
|
|
195
|
+
|
|
152
196
|
keyboard.addEventListener('mousedown', (event) => this.startDrag(event));
|
|
153
197
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
handleKeyPress(keyPressed) {
|
|
198
|
+
|
|
199
|
+
async handleKeyPress(keyPressed) {
|
|
158
200
|
if (!this.currentInput) return;
|
|
159
|
-
|
|
201
|
+
|
|
160
202
|
const start = this.currentInput.selectionStart;
|
|
161
203
|
const end = this.currentInput.selectionEnd;
|
|
162
204
|
const value = this.currentInput.value;
|
|
163
|
-
|
|
205
|
+
|
|
164
206
|
const isCapsActive = this.capsLockActive;
|
|
165
207
|
const isShiftActive = this.shiftActive;
|
|
166
|
-
|
|
208
|
+
|
|
167
209
|
const convertToCorrectCase = (char) => {
|
|
168
210
|
if (isCapsActive || isShiftActive) {
|
|
169
211
|
return char.toUpperCase();
|
|
170
212
|
}
|
|
171
213
|
return char.toLowerCase();
|
|
172
214
|
};
|
|
173
|
-
|
|
174
|
-
// ตรวจสอบค่า keyPressed
|
|
215
|
+
|
|
175
216
|
if (!keyPressed) {
|
|
176
217
|
console.error("Invalid key pressed.");
|
|
177
218
|
return;
|
|
178
219
|
}
|
|
179
|
-
|
|
220
|
+
|
|
180
221
|
switch(keyPressed) {
|
|
181
222
|
case 'Backspace':
|
|
182
223
|
case 'backspace':
|
|
@@ -188,32 +229,32 @@ export class VirtualKeyboard {
|
|
|
188
229
|
this.currentInput.selectionStart = this.currentInput.selectionEnd = start;
|
|
189
230
|
}
|
|
190
231
|
break;
|
|
191
|
-
|
|
232
|
+
|
|
192
233
|
case 'Space':
|
|
193
|
-
this.insertText(' ');
|
|
234
|
+
await this.insertText(' ');
|
|
194
235
|
break;
|
|
195
|
-
|
|
236
|
+
|
|
196
237
|
case 'Tab':
|
|
197
|
-
this.insertText('\t');
|
|
238
|
+
await this.insertText('\t');
|
|
198
239
|
break;
|
|
199
|
-
|
|
240
|
+
|
|
200
241
|
case 'Enter':
|
|
201
242
|
if (this.currentInput.tagName === 'TEXTAREA') {
|
|
202
|
-
this.insertText('\n');
|
|
243
|
+
await this.insertText('\n');
|
|
203
244
|
}
|
|
204
245
|
break;
|
|
205
|
-
|
|
246
|
+
|
|
206
247
|
case 'Caps':
|
|
207
248
|
this.toggleCapsLock();
|
|
208
249
|
break;
|
|
209
|
-
|
|
250
|
+
|
|
210
251
|
case 'Shift':
|
|
211
252
|
this.toggleShift();
|
|
212
253
|
break;
|
|
213
|
-
|
|
254
|
+
|
|
214
255
|
default:
|
|
215
|
-
this.
|
|
216
|
-
|
|
256
|
+
const encryptedText = await this.encodeText(convertToCorrectCase(keyPressed));
|
|
257
|
+
await this.insertText(encryptedText);
|
|
217
258
|
}
|
|
218
259
|
|
|
219
260
|
if (isShiftActive && !isCapsActive) {
|
|
@@ -223,6 +264,17 @@ export class VirtualKeyboard {
|
|
|
223
264
|
this.currentInput.focus();
|
|
224
265
|
const event = new Event('input', { bubbles: true });
|
|
225
266
|
this.currentInput.dispatchEvent(event);
|
|
267
|
+
// console.log(this.encodeText(convertToCorrectCase(keyPressed)));
|
|
268
|
+
// console.log(keyPressed);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async insertText(text) {
|
|
272
|
+
const start = this.currentInput.selectionStart;
|
|
273
|
+
const end = this.currentInput.selectionEnd;
|
|
274
|
+
const decodedText = await this.decodeText(text); // ใช้ถอดรหัสก่อนแทรก
|
|
275
|
+
|
|
276
|
+
this.currentInput.value = this.currentInput.value.slice(0, start) + decodedText + this.currentInput.value.slice(end);
|
|
277
|
+
this.currentInput.selectionStart = this.currentInput.selectionEnd = start + decodedText.length;
|
|
226
278
|
}
|
|
227
279
|
|
|
228
280
|
toggleCapsLock() {
|
|
@@ -356,13 +408,6 @@ export class VirtualKeyboard {
|
|
|
356
408
|
ฝ: "ฦ",
|
|
357
409
|
};
|
|
358
410
|
|
|
359
|
-
insertText(text) {
|
|
360
|
-
const start = this.currentInput.selectionStart;
|
|
361
|
-
const end = this.currentInput.selectionEnd;
|
|
362
|
-
this.currentInput.value = this.currentInput.value.slice(0, start) + text + this.currentInput.value.slice(end);
|
|
363
|
-
this.currentInput.selectionStart = this.currentInput.selectionEnd = start + text.length;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
411
|
toggle() {
|
|
367
412
|
this.isVisible = !this.isVisible;
|
|
368
413
|
this.render();
|