munculin keyboard tambahan di layar untuk website
// ==UserScript==
// @name virtual keyboard ios
// @namespace ios-keyboard-helper
// @version 1.0
// @description munculin keyboard tambahan di layar untuk website
// @match *://*/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
const keys = [
['esc', 'tab', 'enter', 'space'],
['w', 'a', 's', 'd'],
['↑', '←', '↓', '→'],
['shift', 'ctrl', 'e', 'f'],
['1', '2', '3', '4']
];
const keyMap = {
'esc': { key: 'Escape', code: 'Escape', keyCode: 27 },
'tab': { key: 'Tab', code: 'Tab', keyCode: 9 },
'enter': { key: 'Enter', code: 'Enter', keyCode: 13 },
'space': { key: ' ', code: 'Space', keyCode: 32 },
'shift': { key: 'Shift', code: 'ShiftLeft', keyCode: 16 },
'ctrl': { key: 'Control', code: 'ControlLeft', keyCode: 17 },
'↑': { key: 'ArrowUp', code: 'ArrowUp', keyCode: 38 },
'←': { key: 'ArrowLeft', code: 'ArrowLeft', keyCode: 37 },
'↓': { key: 'ArrowDown', code: 'ArrowDown', keyCode: 40 },
'→': { key: 'ArrowRight', code: 'ArrowRight', keyCode: 39 },
};
const style = document.createElement('style');
style.textContent = `
#ios-vkeyboard {
position: fixed;
left: 10px;
bottom: 15px;
z-index: 999999999;
background: rgba(0, 0, 0, 0.72);
padding: 10px;
border-radius: 14px;
font-family: Arial, sans-serif;
user-select: none;
-webkit-user-select: none;
touch-action: none;
}
#ios-vkeyboard.hidden .kb-body {
display: none;
}
#ios-vkeyboard .kb-top {
display: flex;
justify-content: space-between;
align-items: center;
color: white;
font-size: 13px;
margin-bottom: 7px;
gap: 8px;
}
#ios-vkeyboard .kb-title {
font-weight: bold;
}
#ios-vkeyboard .kb-toggle {
background: #222;
color: white;
border: 1px solid #555;
border-radius: 8px;
padding: 5px 9px;
font-size: 12px;
}
#ios-vkeyboard .kb-row {
display: flex;
gap: 6px;
margin-bottom: 6px;
}
#ios-vkeyboard .kb-key {
min-width: 43px;
height: 38px;
border: 1px solid #555;
border-radius: 9px;
background: rgba(255,255,255,0.12);
color: white;
font-size: 15px;
font-weight: bold;
}
#ios-vkeyboard .kb-key:active,
#ios-vkeyboard .kb-key.active {
background: rgba(255,255,255,0.35);
}
#ios-vkeyboard .wide {
min-width: 70px;
}
`;
document.head.appendChild(style);
const box = document.createElement('div');
box.id = 'ios-vkeyboard';
box.innerHTML = `
<div class="kb-top">
<span class="kb-title">keyboard</span>
<button class="kb-toggle">hide</button>
</div>
<div class="kb-body"></div>
`;
document.body.appendChild(box);
const body = box.querySelector('.kb-body');
const toggle = box.querySelector('.kb-toggle');
function getKeyData(label) {
if (keyMap[label]) return keyMap[label];
const upper = label.toUpperCase();
return {
key: label,
code: 'Key' + upper,
keyCode: upper.charCodeAt(0)
};
}
function fireKey(type, label) {
const data = getKeyData(label);
const target = document.activeElement || document.body;
const event = new KeyboardEvent(type, {
key: data.key,
code: data.code,
keyCode: data.keyCode,
which: data.keyCode,
bubbles: true,
cancelable: true
});
target.dispatchEvent(event);
document.dispatchEvent(event);
window.dispatchEvent(event);
if (type === 'keydown') {
insertTextIfInput(target, label);
}
}
function insertTextIfInput(target, label) {
const special = ['esc', 'tab', 'enter', 'space', 'shift', 'ctrl', '↑', '←', '↓', '→'];
if (special.includes(label)) return;
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
const start = target.selectionStart || 0;
const end = target.selectionEnd || 0;
const value = target.value;
target.value = value.slice(0, start) + label + value.slice(end);
target.selectionStart = target.selectionEnd = start + label.length;
target.dispatchEvent(new Event('input', { bubbles: true }));
}
}
keys.forEach(row => {
const rowDiv = document.createElement('div');
rowDiv.className = 'kb-row';
row.forEach(label => {
const btn = document.createElement('button');
btn.className = 'kb-key';
btn.textContent = label;
if (['space', 'enter', 'shift', 'ctrl'].includes(label)) {
btn.classList.add('wide');
}
btn.addEventListener('touchstart', e => {
e.preventDefault();
btn.classList.add('active');
fireKey('keydown', label);
fireKey('keypress', label);
}, { passive: false });
btn.addEventListener('touchend', e => {
e.preventDefault();
btn.classList.remove('active');
fireKey('keyup', label);
}, { passive: false });
btn.addEventListener('mousedown', e => {
e.preventDefault();
btn.classList.add('active');
fireKey('keydown', label);
fireKey('keypress', label);
});
btn.addEventListener('mouseup', e => {
e.preventDefault();
btn.classList.remove('active');
fireKey('keyup', label);
});
rowDiv.appendChild(btn);
});
body.appendChild(rowDiv);
});
toggle.addEventListener('click', () => {
box.classList.toggle('hidden');
toggle.textContent = box.classList.contains('hidden') ? 'show' : 'hide';
});
})();