You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
8.7 KiB
234 lines
8.7 KiB
class VirtualKeyboard {
|
|
static show(inputElement) {
|
|
// Create the virtual keyboard container
|
|
const keyboardContainer = document.createElement('div');
|
|
keyboardContainer.classList.add('virtual-keyboard');
|
|
document.body.appendChild(keyboardContainer);
|
|
|
|
// Create the display container for input characters
|
|
const displayContainer = document.createElement('div');
|
|
displayContainer.classList.add('virtual-keyboard-display');
|
|
document.body.appendChild(displayContainer);
|
|
|
|
// Create the text display box above the number keys
|
|
const textDisplayBox = document.createElement('div');
|
|
textDisplayBox.classList.add('virtual-keyboard-text-display');
|
|
textDisplayBox.style.height = '40px'; // Initialize height
|
|
textDisplayBox.textContent = inputElement.value; // Initialize content
|
|
keyboardContainer.appendChild(textDisplayBox);
|
|
|
|
// Define the keys for the virtual keyboard
|
|
const keyLayout = [
|
|
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace'],
|
|
['Tab', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'Del'],
|
|
['CapsLock', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Enter'],
|
|
['Shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'Shift'],
|
|
['Space']
|
|
];
|
|
|
|
let isShift = false;
|
|
let isCapsLock = false;
|
|
|
|
// Create buttons for each key
|
|
keyLayout.forEach(row => {
|
|
const rowContainer = document.createElement('div');
|
|
rowContainer.classList.add('virtual-keyboard-row');
|
|
row.forEach(key => {
|
|
const keyButton = document.createElement('button');
|
|
keyButton.textContent = key;
|
|
keyButton.classList.add(`key-${key.toLowerCase()}`);
|
|
keyButton.addEventListener('mousedown', (event) => {
|
|
event.preventDefault(); // Prevent losing focus from the input element
|
|
keyButton.classList.add('active'); // Add active class on mousedown
|
|
if (key === 'Backspace') {
|
|
inputElement.value = inputElement.value.slice(0, -1);
|
|
} else if (key === 'Del') {
|
|
inputElement.value = '';
|
|
} else if (key === 'Tab') {
|
|
inputElement.value += '\t';
|
|
} else if (key === 'Space') {
|
|
inputElement.value += ' ';
|
|
} else if (key === 'Enter') {
|
|
document.body.removeChild(keyboardContainer);
|
|
document.body.removeChild(displayContainer);
|
|
} else if (key === 'Shift') {
|
|
// isShift = !isShift;
|
|
// this.toggleShift(keyButton, isShift);
|
|
} else if (key === 'CapsLock') {
|
|
isCapsLock = !isCapsLock;
|
|
this.toggleCapsLock(keyButton, isCapsLock);
|
|
} else {
|
|
inputElement.value += isCapsLock ? key.toUpperCase() : key.toLowerCase();
|
|
}
|
|
inputElement.dispatchEvent(new Event('input')); // Trigger input event to update Vue binding
|
|
displayContainer.textContent = inputElement.value; // Update display container with input value
|
|
textDisplayBox.textContent = inputElement.value; // Update text display box with input value
|
|
});
|
|
keyButton.addEventListener('mouseup', () => {
|
|
keyButton.classList.remove('active'); // Remove active class on mouseup
|
|
keyButton.style.background = '#fff'; // Reset background immediately
|
|
});
|
|
keyButton.addEventListener('mouseleave', () => {
|
|
keyButton.classList.remove('active'); // Remove active class if mouse leaves the button
|
|
keyButton.style.background = '#fff'; // Reset background immediately
|
|
});
|
|
rowContainer.appendChild(keyButton);
|
|
});
|
|
keyboardContainer.appendChild(rowContainer);
|
|
});
|
|
|
|
// Position the keyboard at the bottom of the screen
|
|
keyboardContainer.style.position = 'fixed';
|
|
keyboardContainer.style.bottom = '0';
|
|
keyboardContainer.style.left = '50%';
|
|
keyboardContainer.style.transform = 'translateX(-50%)';
|
|
keyboardContainer.style.width = '100%';
|
|
keyboardContainer.style.maxWidth = '800px';
|
|
keyboardContainer.style.margin = '0 auto';
|
|
keyboardContainer.style.border = '1px solid #999';
|
|
|
|
// Position the display container above the keyboard
|
|
displayContainer.style.position = 'fixed';
|
|
displayContainer.style.bottom = 'calc(100% + 10px)';
|
|
displayContainer.style.left = '50%';
|
|
displayContainer.style.transform = 'translateX(-50%)';
|
|
displayContainer.style.width = '100%';
|
|
displayContainer.style.maxWidth = '800px';
|
|
displayContainer.style.textAlign = 'center';
|
|
displayContainer.style.padding = '10px';
|
|
displayContainer.style.background = '#f0f0f0';
|
|
displayContainer.style.borderTop = '1px solid #999';
|
|
displayContainer.style.boxShadow = '0 -2px 10px rgba(0, 0, 0, 0.1)';
|
|
displayContainer.style.zIndex = '1000';
|
|
|
|
// Style the text display box
|
|
textDisplayBox.style.width = '100%';
|
|
textDisplayBox.style.padding = '10px';
|
|
textDisplayBox.style.background = '#e0e0e0';
|
|
textDisplayBox.style.textAlign = 'center';
|
|
textDisplayBox.style.fontSize = '18px';
|
|
textDisplayBox.style.marginBottom = '10px';
|
|
|
|
// Hide the keyboard and display container when the input loses focus
|
|
inputElement.addEventListener('blur', () => {
|
|
setTimeout(() => {
|
|
if (document.activeElement !== inputElement) {
|
|
document.body.removeChild(keyboardContainer);
|
|
document.body.removeChild(displayContainer);
|
|
}
|
|
}, 30);
|
|
});
|
|
}
|
|
|
|
static toggleShift(button, isShift) {
|
|
button.classList.toggle('active', isShift);
|
|
}
|
|
|
|
static toggleCapsLock(button, isCapsLock) {
|
|
const keys = document.querySelectorAll('.virtual-keyboard button');
|
|
keys.forEach(key => {
|
|
if (key.textContent.length === 1 && key.textContent.match(/[a-z]/i)) {
|
|
key.textContent = isCapsLock ? key.textContent.toUpperCase() : key.textContent.toLowerCase();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Add some basic styles for the virtual keyboard
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
.virtual-keyboard {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: #f0f0f0;
|
|
padding: 10px;
|
|
border-top: 1px solid #999;
|
|
border: 1px solid #999;
|
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
|
z-index: 1000;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
}
|
|
.virtual-keyboard-row {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-bottom: 5px;
|
|
}
|
|
.virtual-keyboard button {
|
|
margin: 5px;
|
|
padding: 15px;
|
|
font-size: 18px;
|
|
cursor: pointer;
|
|
border: none;
|
|
border-radius: 5px;
|
|
background: #fff;
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
transition: background 0.3s, box-shadow 0.3s;
|
|
flex: 1 1 8%;
|
|
max-width: 60px;
|
|
}
|
|
.virtual-keyboard button:hover {
|
|
background: #e0e0e0;
|
|
}
|
|
.virtual-keyboard button:active {
|
|
background: #d0d0d0;
|
|
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
}
|
|
.virtual-keyboard button.active {
|
|
background: #d0d0d0;
|
|
}
|
|
.virtual-keyboard .key-backspace {
|
|
flex: 1 1 10%;
|
|
max-width: 100px;
|
|
text-align: center;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.virtual-keyboard .key-enter {
|
|
flex: 1 1 10%;
|
|
max-width: 100px;
|
|
}
|
|
.virtual-keyboard .key-shift {
|
|
flex: 1 1 15%;
|
|
max-width: 150px;
|
|
}
|
|
.virtual-keyboard .key-capslock,
|
|
.virtual-keyboard .key-tab,
|
|
.virtual-keyboard .key-del {
|
|
flex: 1 1 10%;
|
|
max-width: 100px;
|
|
}
|
|
.virtual-keyboard .key-space {
|
|
flex: 1 1 60%;
|
|
max-width: 400px;
|
|
}
|
|
.virtual-keyboard-display {
|
|
font-size: 24px;
|
|
color: #333;
|
|
}
|
|
.virtual-keyboard-text-display {
|
|
width: 100%;
|
|
padding: 10px;
|
|
background: #e0e0e0;
|
|
text-align: center;
|
|
font-size: 18px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.virtual-keyboard-row:first-child {
|
|
justify-content: space-between;
|
|
}
|
|
.virtual-keyboard-row:nth-child(2) {
|
|
justify-content: space-between;
|
|
}
|
|
.virtual-keyboard-row:nth-child(3) {
|
|
justify-content: space-between;
|
|
}
|
|
.virtual-keyboard-row:nth-child(4) {
|
|
justify-content: space-between;
|
|
}
|
|
.virtual-keyboard-row:nth-child(5) {
|
|
justify-content: center;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|