Keyboard Display Script

shows keyboard inputs on screen

As of 2019-08-08. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Keyboard Display Script
// @namespace    http://tampermonkey.net/
// @version      0.25.3.1
// @description  shows keyboard inputs on screen
// @author       Oki and meppydc
// @match        https://*.jstris.jezevec10.com/*
// @grant        none
// ==/UserScript==

/**************************
   Keyboard Display Script
**************************/
(function() {
    window.addEventListener('load', function() {

        //Only display the keyboard if either in a Game or Replay
        if (typeof Game != "undefined" || typeof Replayer != "undefined") {

            //labels are    0     1     2          3
            var labels = ['180','SD', 'HD',      'CCW',
                          //4     5     6     7    8    9
                          'HL', 'CW', 'jez', '<', 'v', '>']

            let kbdisplay = {left:7,right:9,sd:1,hd:2,ccw:3,cw:5,hold:5,180:0,reset:6,new:8}

            //each number here corresponds to the label of the corresponding number (ex: 180 is set to 0 so label 0 will be highlighted when 180 key is pressed
            //make sure that each number in `kbdisplay` is unique and points to the right label


            //don't scroll to the bottom

            //nothing important after
            //          left right  sd hd ccw cw hold 180 reset new
            //order is: [6,    8,   1,  2, 3,  5,  4,  0] (.22)
            //order is: [7,    9,   8,  2, 5,  6,  1,  4] (.23)
            //order is: [7,    9,   8,  2, 5,  6,  1,  4] (.24)
            //order is: [7,    9,   8,  2, 5,  6,  1,  4,   0    3] (.24.1)
            //order is: [7,    9,   8,  3, 5,  6,  2,  4,   0    1] (.24.2)
            //0.25 added crap ton of variables, maybe use dictionary instead?
            //0.25.1 enum


            //var highlight = [[6,2],[8,2],[6,0],[8,0],[3,2],[5,2],[0,2],[2,2],[1,2],,[4,2]][this['actions'][this['ptr']]["a"]] //reference




            if (typeof getParams != "function") {
                var getParams = a => {
                    var params = a.slice(a.indexOf("(") + 1);
                    params = params.substr(0, params.indexOf(")")).split(",");
                    return params
                }
            }
            if (typeof trim != "function") {
                var trim = a => {
                    a = a.slice(0, -1);
                    a = a.substr(a.indexOf("{") + 1);
                    return a
                }
            }

            //Create the "keyboard holder". It's a div positioned where the keyboard will be, but it doesnt contain anything yet.
            var kbhold = document.createElement("div");
            kbhold.id = "keyboardHolder";
            kbhold.style.position = "absolute"
            //Im trying to position it relative to the main canvas (this doesnt really work well...)
            kbhold.style.left = (myCanvas.getBoundingClientRect().left - 300) + "px";
            kbhold.style.top = (myCanvas.getBoundingClientRect().top + 100) + "px";

            //Helper method for keyboards in replays
            if (typeof Replayer != "undefined" && typeof Game == "undefined") {
                Replayer["pressKey"] = function(num, type) {
                    console.log(num)
                    //type: 0=release 1=down 2=press
                    //Highlights the corresponding key
                    //gets array of all "kbkey" classes and takes cell "num" and hightlights it
                    document.getElementsByClassName("kbkey")[num].style.backgroundColor = type ? "lightgoldenrodyellow" : ""
                    if (type == 2) {
                        //from replay data you dont really know how long a key has been pressed. im using 100ms as a default
                        setTimeout(x => {
                            document.getElementsByClassName("kbkey")[num].style.backgroundColor = ""
                        }, 100)
                    }

                }
                //positions the keyboard holder differently for replays (thanks to meppydc)
                kbhold.style.left = (myCanvas.getBoundingClientRect().right + 200) + "px";
                kbhold.style.top = (myCanvas.getBoundingClientRect().top + 200) + "px";
            }

            document.body.appendChild(kbhold);


            //(important)
            //this is what is pasted into the keyboard holder and makes up the entire visual keyboard.
            //(i decompressed and tidied it up a bit)
            //basically it's a table consisting of 2 rows and 6 columns
            //maybe read up on css tables if you wanna add new cells

            //nah


            f = `

<style>
#kbo {text-align:center;position: absolute;font-size:15px;}
#kbo .tg {border-collapse:collapse;border-spacing:0;color:red;}
#kbo .tg td{padding:10px 5px;border-style:solid;border-width:2px;}
#kbo .tg th{padding:10px 5px;border-style:solid;border-width:2px;}
#kbo .tg .tg-wp8o{border-color:#000000;border:inherit;}
#kbo .tg .tg-tc3e{border-color:#34ff34;}
#kbo .tg .tg-jy2k{border-color:#f8a102;}
#kbo .tg .tg-p39m{border-color:#f8ff00;
}</style>

<div id=\"kbo\"><div id=\"kps\"></div>
<table class=\"tg\">
	<tr>
		<td class=\"tg-tc3e kbkey\">${labels[0]}</td>
		<td class=\"tg-tc3e kbkey\">${labels[1]}</td>
		<td class=\"tg-tc3e kbkey\">${labels[2]}</td>
		<td class=\"tg-wp8o\"></td>
		<td class=\"tg-jy2k kbkey\">${labels[3]}</td>
		<td class=\"tg-wp8o\"></td>
	</tr>
	<tr>
		<td class=\"tg-p39m kbkey\">${labels[4]}</td>
		<td class=\"tg-p39m kbkey\">${labels[5]}</td>
		<td class=\"tg-p39m kbkey\">${labels[6]}</td>
		<td class=\"tg-jy2k kbkey\">${labels[7]}</td>
		<td class=\"tg-jy2k kbkey\">${labels[8]}</td>
		<td class=\"tg-jy2k kbkey\">${labels[9]}</td>
	</tr>
</table>
</div>
`
            keyboardHolder.innerHTML = f

            //keyboard if in game (not replays)********************************************************************************************************************************
            if (typeof Game != "undefined") {

                document['addEventListener']('keydown', press);
                document['addEventListener']('keyup', press);

                function press(e) {
                    if (~Game['set2ings'].indexOf(e.keyCode)) {

                        //lol

                        //console.log(Game['set2ings'])//displays the keycodes of your controls
                        // left right sd hd ccw cw hold 180
                        //(important)
                        //listens to pressed keys and highlights the corresponsing div.
                        //the magic array converts between the actions and the div that is highlighted.
                        //If you change the order of the boxes, you might also have to adjust the numbers in this array
                        //           left right sd hd ccw cw hold 180 reset new
                        //order is: [6,    8,   1,  2, 3,  5,  4,  0] (.22 order)
                        //order is: [7,    9,   8,  2, 5,  6,  1,  4] (.23 order)
                        //order is: [7,    9,   8,  2, 5,  6,  1,  4] (.24 order)
                        //order is: [7,    9,   8,  2, 5,  6,  1,  4,   0    3] (.24.1 order)
                        //order is: [7,    9,   8,  3, 5,  6,  2,  4,   0    1] (.24.2 order)
                        var corresponding = [kbdisplay.left, kbdisplay.right, kbdisplay.sd, kbdisplay.hd, kbdisplay.ccw, kbdisplay.cw, kbdisplay.hold, kbdisplay['180'], kbdisplay.reset, kbdisplay.new][Game['set2ings'].indexOf(e.keyCode)]
                        document.getElementsByClassName("kbkey")[corresponding].style.backgroundColor = ["lightgoldenrodyellow", ""][+(e.type == "keyup")]
                    }
                }

                //This saves the settings array (which maps all actions in jstris to their keycodes) to a global variable for me to use (called Game['se2ings'])
                //resets every time a new game is started
                var set2ings = Game['prototype']['readyGo'].toString()
                set2ings = "Game['set2ings']=this.Settings.controls;" + trim(set2ings)
                Game['prototype']['readyGo'] = new Function(set2ings);

                //calculates kps from kpp and pps and writes it into the kps element
                var updateTextBarFunc = Game['prototype']['updateTextBar'].toString()
                updateTextBarFunc = trim(updateTextBarFunc) + ";kps.innerHTML='KPS: '+(this.getKPP()*this.placedBlocks/this.clock).toFixed(2)"
                Game['prototype']['updateTextBar'] = new Function(updateTextBarFunc);
            } else {

                //else: we're in a replay********************************************************************************************************************************

                var website = "jstris.jezevec10.com"
                var url = window.location.href
                var parts = url.split("/")

                if (parts[3] == "replay" && parts[2].endsWith(website)) {

                    //making a web request for the sole purpose of getting the DAS that was used for the replay
                    //(can be done more elegantly)
                    fetch("https://" + parts[2] + "/replay/data?id=" + (parts.length == 6 ? (parts[5] + "&live=1") : (parts[4])))
                        .then(function(response) {
                            return response.json();
                        })
                        .then(function(jsonResponse) {
                            var das = jsonResponse.c.das
                            var playT = Replayer['prototype']['playUntilTime'].toString()
                            var playTparams = getParams(playT);


                            //going though the list of actions done in the replay, and translating that into the timings for highlighting the divs
                            //i dont rememer how exactly i did this but it's not pretty
                            var insert1 = `
			kps.innerHTML="KPS: "+(this.getKPP()*this.placedBlocks/(this.clock/1000)).toFixed(2)
			this["delayedActions"] = []
			for (var i = 0; i < this["actions"].length; i++) {
				var action = JSON.parse(JSON.stringify(this["actions"][i]));
				if(action.a == 2 || action.a == 3){
					action.t = (action.t-` + das + `)>0 ? (action.t-` + das + `) : 0
				}
				this["delayedActions"].push(action)
			}

			this["delayedActions"].sort(function(a, b) {
    			return a.t - b.t;
			});

			var oldVals = [this["timer"],this["ptr"]]

			while (` + playTparams[0] + ` >= this['delayedActions'][this['ptr']]['t']) {
			    if (this['ptr']) {
			        this['timer'] += (this['delayedActions'][this['ptr']]['t'] - this['delayedActions'][this['ptr'] - 1]['t']) / 1000
			    };
			    if(this['delayedActions'][this['ptr']]["a"] == 2){
			    	Replayer["pressKey"](${kbdisplay.left},1)
			    }
				if(this['delayedActions'][this['ptr']]["a"] == 3){
			    	Replayer["pressKey"](${kbdisplay.right},1)
			    }

			    this['ptr']++;
			    if (this['delayedActions']['length'] === this['ptr']) {
			        this['reachedEnd'] = true;
			        break
			    }
			};

			this["timer"] = oldVals[0]
			this["ptr"] = oldVals[1]`


                            //this maps a specific action (this['actions'][this['ptr']]["a"]) to what to do with the divs
                            //the list of what action code equals what action is in that one harddrop forum post
                            //for example, if you DAS_LEFT then left will be held down.
                            //You might also adjust the numbers here (the first number in the pairs. remap them the same as in the magic array)
                            var insert2 = `
			var highlight = [[${kbdisplay.left},2],[${kbdisplay.right},2],[${kbdisplay.left},0],[${kbdisplay.right},0],[${kbdisplay.ccw},2],[${kbdisplay.cw},2],[${kbdisplay['180']},2],[${kbdisplay.hd},2],[${kbdisplay.sd},2],,[${kbdisplay.hold},2]][this['actions'][this['ptr']]["a"]]
			if(highlight){
				Replayer["pressKey"](...highlight)
			};
			`

                            playT = playT.replace(";", insert1 + ";")
                            playT = playT.replace("1000};", "1000};" + insert2)
                            Replayer['prototype']['playUntilTime'] = new Function(...playTparams, trim(playT));

                        //i hate myself - Oki
                        //I heard jez whips Oki - meppydc
                        //I hate myself as well once it stopped working when I did basically nothing - meppydc
                        //typing var names sucks - meppydc
                        });
                }
            }
        }
    });
})();