Taming.io Keystrokes

A simple smooth, draggable, scalable, and customizable script to display keystrokes and CPS (stylish for recording, streaming, etc).

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Taming.io Keystrokes
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  A simple  smooth, draggable, scalable, and customizable script to display keystrokes and CPS (stylish for recording, streaming, etc).
// @author       Triton
// @match        https://taming.io/
// @icon         https://taming.io/img/item/amber-spear.png
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    //CONFIGURATION (customizable)
    const config = {
        //Keybinds
        upKey: "w", leftKey: "a", downKey: "s", rightKey: "d", spaceKey: " ", //Keybinding

        //Display Text
        upText: "W", leftText: "A", downText: "S", rightText: "D", //Displayed keys

        //Colors
        idleColor: "rgba(34, 34, 34, 0.9)",      //Default key color
        pressColor: "rgba(255, 255, 255, 0.25)", //On press color

        //Style & Position
        opacity: 0.9,
        defaultPositionX: "20px",
        defaultPositionY: "20px",

        // Scaling
        defaultScale: 1.0,  //Initial scale (1.0 = 100%)
        minScale: 0.5,      //Minimum scale (0.5 = 50%)
        maxScale: 2.0,      //Maximum scale (2.0 = 200%)
        scaleStep: 0.05,    //How much to scale with each +/- key press
    };

    //Actual script
    let lmbClicks = 0, rmbClicks = 0;
    let currentScale;
    const keyElements = {};
    const keyMap = {
        [config.upKey]: 'up', [config.leftKey]: 'left', [config.downKey]: 'down',
        [config.rightKey]: 'right', [config.spaceKey]: 'space'
    };

    const css = `
        @keyframes rainbow{0%{color:#ff0000}10%{color:#fc7b03}20%{color:#fcf803}30%{color:#98fc03}40%{color:#03fc28}50%{color:#03fccf}60%{color:#03c2fc}70%{color:#033dfc}80%{color:#6b03fc}90%{color:#e803fc}100%{color:#fc031c}}
        .keystrokes-container{position:fixed;width:240px;height:240px;font-family:"Lato",sans-serif;user-select:none;z-index:9999;opacity:${config.opacity};animation:rainbow 10s infinite;cursor:grab;transform-origin:top left;transition:transform 0.1s ease;}
        .keystrokes-container.dragging{cursor:grabbing;}
        .key-element{position:absolute;text-align:center;vertical-align:middle;background:${config.idleColor};border-radius:5px;transition:background-color 0.1s ease;font-weight:700;pointer-events:none;}
        .wasd{width:58px;height:58px;line-height:58px;font-size:20px;}
        .mouse{font-size:14px;line-height:40px;}
        .key-up{top:15px;left:100px;} .key-left{top:80px;left:35px;} .key-down{top:80px;left:100px;} .key-right{top:80px;left:165px;}
        .key-lmb{width:89.5px;height:40px;top:145px;left:34.5px;} .key-rmb{width:89.5px;height:40px;top:145px;left:132.5px;}
        .key-space{width:187px;height:40px;top:193px;left:35px;}
        .space-svg{width:32px;height:32px;margin-top:4px;fill:currentColor;}
    `;

    const html = `
        <div class="key-element wasd key-up">${config.upText}</div> <div class="key-element wasd key-left">${config.leftText}</div>
        <div class="key-element wasd key-down">${config.downText}</div> <div class="key-element wasd key-right">${config.rightText}</div>
        <div class="key-element mouse key-lmb">LMB: 0</div> <div class="key-element mouse key-rmb">RMB: 0</div>
        <div class="key-element key-space"><svg class="space-svg" viewBox="0 0 512 512"><polygon points="40 288 40 416 464 416 464 288 432 288 432 384 72 384 72 288 40 288"/></svg></div>
    `;

    function init() {
        const styleSheet = document.createElement("style");
        styleSheet.innerText = css;
        document.head.appendChild(styleSheet);

        const container = document.createElement("div");
        container.className = "keystrokes-container";
        container.innerHTML = html;

        container.style.left = localStorage.getItem('keystrokes_X') || config.defaultPositionX;
        container.style.top = localStorage.getItem('keystrokes_Y') || config.defaultPositionY;
        currentScale = parseFloat(localStorage.getItem('keystrokes_scale')) || config.defaultScale;
        container.style.transform = `scale(${currentScale})`;

        document.body.appendChild(container);

        Object.assign(keyElements, {
            up: container.querySelector('.key-up'), left: container.querySelector('.key-left'),
            down: container.querySelector('.key-down'), right: container.querySelector('.key-right'),
            lmb: container.querySelector('.key-lmb'), rmb: container.querySelector('.key-rmb'),
            space: container.querySelector('.key-space')
        });

        const handleKeyDown = e => {
            if (e.key === '-' || e.key === '_') {
                e.preventDefault();
                currentScale = Math.max(config.minScale, currentScale - config.scaleStep);
            } else if (e.key === '+' || e.key === '=') {
                e.preventDefault();
                currentScale = Math.min(config.maxScale, currentScale + config.scaleStep);
            } else {
                const keyName = keyMap[e.key.toLowerCase()];
                if (keyName) keyElements[keyName].style.backgroundColor = config.pressColor;
                return;
            }
            container.style.transform = `scale(${currentScale})`;
            localStorage.setItem('keystrokes_scale', currentScale);
        };
        const handleKeyUp = e => { const keyName = keyMap[e.key.toLowerCase()]; if (keyName) keyElements[keyName].style.backgroundColor = config.idleColor; };
        const handleMouseDown = e => { if (e.button === 0) { lmbClicks++; keyElements.lmb.style.backgroundColor = config.pressColor; } else if (e.button === 2) { rmbClicks++; keyElements.rmb.style.backgroundColor = config.pressColor; } };
        const handleMouseUp = e => { if (e.button === 0) keyElements.lmb.style.backgroundColor = config.idleColor; else if (e.button === 2) keyElements.rmb.style.backgroundColor = config.idleColor; };

        function makeDraggable(element) {
            let initialX, initialY, initialLeft, initialTop;
            const move = e => {
                const dx = e.clientX - initialX;
                const dy = e.clientY - initialY;
                element.style.left = `${initialLeft + dx}px`;
                element.style.top = `${initialTop + dy}px`;
            };
            const endDrag = () => {
                document.removeEventListener('mousemove', move);
                document.removeEventListener('mouseup', endDrag);
                element.classList.remove('dragging');
                localStorage.setItem('keystrokes_X', element.style.left);
                localStorage.setItem('keystrokes_Y', element.style.top);
            };
            element.addEventListener('mousedown', e => {
                if (e.button !== 0) return;
                e.preventDefault();
                initialX = e.clientX; initialY = e.clientY;
                initialLeft = element.offsetLeft; initialTop = element.offsetTop;
                element.classList.add('dragging');
                document.addEventListener('mousemove', move);
                document.addEventListener('mouseup', endDrag);
            });
        }

        window.addEventListener("keydown", handleKeyDown);
        window.addEventListener("keyup", handleKeyUp);
        window.addEventListener("mousedown", handleMouseDown);
        window.addEventListener("mouseup", handleMouseUp);
        window.addEventListener("contextmenu", e => e.preventDefault());
        makeDraggable(container);
        setInterval(() => {
            keyElements.lmb.textContent = `LMB: ${lmbClicks}`;
            keyElements.rmb.textContent = `RMB: ${rmbClicks}`;
            lmbClicks = 0; rmbClicks = 0;
        }, 1000);
    }

    init();
})();