Adds a draggable button that acts as an input to force the mobile keyboard open.Best for opening cheats on mobile.
// ==UserScript==
// @name Mobile Keyboard Spawner
// @namespace https://greasyfork.org/users/Eternosen
// @version 1.2.1
// @description Adds a draggable button that acts as an input to force the mobile keyboard open.Best for opening cheats on mobile.
// @author Eternosen
// @match *://*/*
// @grant none
// @license MIT
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// PC PROTECTION: Don't show the button on desktop/laptops
if (!('ontouchstart' in window) && !navigator.maxTouchPoints) return;
function createKeyboardTrigger() {
if (document.getElementById('mobile-kb-container')) return;
const container = document.createElement('div');
container.id = 'mobile-kb-container';
(document.body || document.documentElement).appendChild(container);
const shadow = container.attachShadow({mode: 'open'});
const input = document.createElement('input');
input.type = 'text';
input.value = '⌨️';
input.setAttribute('autocomplete', 'off');
input.setAttribute('spellcheck', 'false');
input.setAttribute('autocorrect', 'off');
input.setAttribute('autocapitalize', 'none');
input.style = `
position: fixed; top: 120px; right: 20px;
width: 50px; height: 50px;
background: #222;
border: 2px solid #444; border-radius: 50%;
text-align: center; font-size: 24px;
z-index: 2147483647; cursor: pointer;
box-shadow: 0 4px 10px rgba(0,0,0,0.5);
outline: none; touch-action: none;
caret-color: transparent; color: transparent;
text-shadow: 0 0 0 white;
user-select: none; -webkit-user-select: none;
`;
shadow.appendChild(input);
let isDragging = false, startX, startY, xOffset = 0, yOffset = 0;
input.addEventListener('touchstart', (e) => {
// Stop page from reacting to the touch start
e.stopPropagation();
const touch = e.touches[0];
startX = touch.clientX - xOffset;
startY = touch.clientY - yOffset;
isDragging = false;
}, {passive: false});
input.addEventListener('touchmove', (e) => {
isDragging = true;
// THE FIX: Stop the page from scrolling while dragging the button
if (e.cancelable) e.preventDefault();
e.stopPropagation();
const touch = e.touches[0];
xOffset = touch.clientX - startX;
yOffset = touch.clientY - startY;
input.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
}, {passive: false});
input.addEventListener('touchend', (e) => {
e.stopPropagation();
if (isDragging) {
input.blur();
} else {
input.value = '';
input.focus();
}
});
input.addEventListener('blur', () => { input.value = '⌨️'; });
// BLOCK messy mobile events from leaking to the site
['keydown', 'keyup', 'keypress'].forEach(evtType => {
input.addEventListener(evtType, (e) => { e.stopPropagation(); });
});
input.addEventListener('input', (e) => {
const char = e.data;
if (!char) return;
let codeVal = 'Unidentified';
if (/^[a-zA-Z]$/.test(char)) {
codeVal = `Key${char.toUpperCase()}`;
} else if (/^[0-9]$/.test(char)) {
codeVal = `Digit${char}`;
}
const keyCode = char.toUpperCase().charCodeAt(0);
const isUpper = char === char.toUpperCase() && char !== char.toLowerCase();
const eventParams = {
key: char,
code: codeVal,
keyCode: keyCode,
which: keyCode,
shiftKey: isUpper,
ctrlKey: false, altKey: false, metaKey: false,
bubbles: true, cancelable: true, composed: true,
view: window
};
const down = new KeyboardEvent('keydown', eventParams);
const press = new KeyboardEvent('keypress', eventParams);
const up = new KeyboardEvent('keyup', eventParams);
const target = document.activeElement && document.activeElement !== input
? document.activeElement
: document.body;
target.dispatchEvent(down);
target.dispatchEvent(press);
target.dispatchEvent(up);
window.dispatchEvent(down);
window.dispatchEvent(press);
window.dispatchEvent(up);
input.value = '';
});
}
createKeyboardTrigger();
const observer = new MutationObserver(() => {
if (!document.getElementById('mobile-kb-container')) createKeyboardTrigger();
});
observer.observe(document.documentElement, { childList: true, subtree: true });
})();