Mobile Keyboard Spawner

Adds a draggable button that acts as an input to force the mobile keyboard open.Best for opening cheats on mobile.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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 });
})();