import * as TestLogic from "./test-logic"; import * as TestUI from "./test-ui"; import * as TestStats from "./test-stats"; import * as Monkey from "./monkey"; import Config, * as UpdateConfig from "./config"; import * as Keymap from "./keymap"; import * as Misc from "./misc"; import * as LiveAcc from "./live-acc"; import * as LiveBurst from "./live-burst"; import * as Funbox from "./funbox"; import * as Sound from "./sound"; import * as Caret from "./caret"; import * as ManualRestart from "./manual-restart-tracker"; import * as Notifications from "./notifications"; import * as CustomText from "./custom-text"; import * as UI from "./ui"; import * as Settings from "./settings"; import * as LayoutEmulator from "./layout-emulator"; import * as PaceCaret from "./pace-caret"; import * as TimerProgress from "./timer-progress"; import * as TestTimer from "./test-timer"; import * as Focus from "./focus"; import * as ShiftTracker from "./shift-tracker"; import * as Replay from "./replay.js"; import * as MonkeyPower from "./monkey-power"; import * as WeakSpot from "./weak-spot"; $("#wordsInput").keypress((event) => { event.preventDefault(); }); let dontInsertSpace = false; function handleTab(event) { if (TestUI.resultCalculating) { event.preventDefault(); } if ( !$("#presetWrapper").hasClass("hidden") || !$("#tagsWrapper").hasClass("hidden") ) { event.preventDefault(); return; } if ($("#customTextPopup .textarea").is(":focus")) { event.preventDefault(); let area = $("#customTextPopup .textarea")[0]; var start = area.selectionStart; var end = area.selectionEnd; // set textarea value to: text before caret + tab + text after caret area.value = area.value.substring(0, start) + "\t" + area.value.substring(end); // put caret at right position again area.selectionStart = area.selectionEnd = start + 1; // event.preventDefault(); // $("#customTextPopup .textarea").val( // $("#customTextPopup .textarea").val() + "\t" // ); return; } else if ( !TestUI.resultCalculating && $("#commandLineWrapper").hasClass("hidden") && $("#simplePopupWrapper").hasClass("hidden") && !$(".page.pageLogin").hasClass("active") ) { if ($(".pageTest").hasClass("active")) { if (Config.quickTab) { if ( (Config.mode == "zen" && !event.shiftKey) || (TestLogic.hasTab && !event.shiftKey) ) { //ignore } else { if (event.shiftKey) { ManualRestart.set(); } else { ManualRestart.reset(); } event.preventDefault(); if ( TestLogic.active && Config.repeatQuotes === "typing" && Config.mode === "quote" ) { TestLogic.restart(true, false, event); } else { TestLogic.restart(false, false, event); } } } else { if ( !TestUI.resultVisible && ((TestLogic.hasTab && event.shiftKey) || (!TestLogic.hasTab && Config.mode !== "zen") || (Config.mode === "zen" && event.shiftKey)) ) { event.preventDefault(); $("#restartTestButton").focus(); } } } else if (Config.quickTab) { UI.changePage("test"); } } } function handleBackspace(event) { event.preventDefault(); if (!TestLogic.active) return; if ( TestLogic.input.current == "" && TestLogic.input.history.length > 0 && TestUI.currentWordElementIndex > 0 ) { //if nothing is inputted and its not the first word if ( (TestLogic.input.getHistory(TestLogic.words.currentIndex - 1) == TestLogic.words.get(TestLogic.words.currentIndex - 1) && !Config.freedomMode) || $($(".word")[TestLogic.words.currentIndex - 1]).hasClass("hidden") ) { return; } else { if (Config.confidenceMode === "on" || Config.confidenceMode === "max") return; if (event["ctrlKey"] || event["altKey"]) { TestLogic.input.resetCurrent(); TestLogic.input.popHistory(); TestLogic.corrected.popHistory(); } else { TestLogic.input.setCurrent(TestLogic.input.popHistory()); TestLogic.corrected.setCurrent(TestLogic.corrected.popHistory()); if (Config.funbox === "nospace") { TestLogic.input.setCurrent( TestLogic.input.current.substring( 0, TestLogic.input.current.length - 1 ) ); } } TestLogic.words.decreaseCurrentIndex(); Replay.addReplayEvent("backWord"); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex - 1); TestUI.updateActiveElement(true); Funbox.toggleScript(TestLogic.words.getCurrent()); TestUI.updateWordElement(!Config.blindMode); } } else if (TestLogic.input.current !== "") { if (Config.confidenceMode === "max") return; if (event["ctrlKey"] || event["altKey"] || event.metaKey) { Replay.addReplayEvent("clearWord"); // let limiter = " "; // if ( // TestLogic.input.current.lastIndexOf("-") > // TestLogic.input.current.lastIndexOf(" ") // ) // limiter = "-"; // let split = TestLogic.input.current.replace(/ +/g, " ").split(limiter); // if (split[split.length - 1] == "") { // split.pop(); // } // let addlimiter = false; // if (split.length > 1) { // addlimiter = true; // } // split.pop(); // TestLogic.input.setCurrent(split.join(limiter)); // if (addlimiter) { // TestLogic.input.appendCurrent(limiter); // } if ( /^[ £§`~!@#$%^&*()_+\\\-=[\]{};':"|,./<>?]*$/g.test( TestLogic.input.getCurrent() ) ) { //pop current and previous TestLogic.input.resetCurrent(); TestLogic.input.popHistory(); TestLogic.corrected.popHistory(); TestUI.updateWordElement(!Config.blindMode); TestLogic.words.decreaseCurrentIndex(); Replay.addReplayEvent("backWord"); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex - 1); TestUI.updateActiveElement(true); Funbox.toggleScript(TestLogic.words.getCurrent()); TestUI.updateWordElement(!Config.blindMode); TestLogic.input.resetCurrent(); } else { const regex = new RegExp( /[ £§`~!@#$%^&*()_+\\\-=[\]{};':"|,./<>?]/, "g" ); let input = TestLogic.input.getCurrent(); regex.test(input); // let puncIndex = regex.lastIndex; let puncIndex = input.lastIndexOfRegex( /[ £§`~!@#$%^&*()_+\\\-=[\]{};':"|,./<>?]/g ); while ( /[ £§`~!@#$%^&*()_+\\\-=[\]{};':"|,./<>?]/g.test(input.slice(-1)) ) { input = input.substring(0, input.length - 1); } puncIndex = input.lastIndexOfRegex( /[ £§`~!@#$%^&*()_+\\\-=[\]{};':"|,./<>?]/g ); TestLogic.input.setCurrent( input.substring(0, puncIndex == 0 ? 0 : puncIndex + 1) ); } } else { TestLogic.input.setCurrent( TestLogic.input.current.substring(0, TestLogic.input.current.length - 1) ); Replay.addReplayEvent("deleteLetter"); } TestUI.updateWordElement(!Config.blindMode); } Sound.playClick(Config.playSoundOnClick); if (Config.keymapMode === "react") { Keymap.flashKey(event.code, true); } else if (Config.keymapMode === "next" && Config.mode !== "zen") { Keymap.highlightKey( TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ) .toString() .toUpperCase() ); } Caret.updatePosition(); } function handleSpace(event, isEnter) { if (!TestLogic.active) return; if (TestLogic.input.current === "") return; // let nextWord = wordsList[TestLogic.words.currentIndex + 1]; // if ((isEnter && nextWord !== "\n") && (isEnter && Config.funbox !== "58008")) return; // if (!isEnter && nextWord === "\n") return; event.preventDefault(); if (Config.mode == "zen") { $("#words .word.active").removeClass("active"); $("#words").append("
"); } let currentWord = TestLogic.words.getCurrent(); if (Config.funbox === "layoutfluid" && Config.mode !== "time") { // here I need to check if Config.customLayoutFluid exists because of my scuffed solution of returning whenever value is undefined in the setCustomLayoutfluid function const layouts = Config.customLayoutfluid ? Config.customLayoutfluid.split("#") : ["qwerty", "dvorak", "colemak"]; let index = 0; let outof = TestLogic.words.length; index = Math.floor( (TestLogic.input.history.length + 1) / (outof / layouts.length) ); if (Config.layout !== layouts[index] && layouts[index] !== undefined) { Notifications.add(`--- !!! ${layouts[index]} !!! ---`, 0); } UpdateConfig.setLayout(layouts[index]); UpdateConfig.setKeymapLayout(layouts[index]); Keymap.highlightKey( TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ) .toString() .toUpperCase() ); Settings.groups.layout.updateButton(); } dontInsertSpace = true; let burst = TestStats.calculateBurst(); LiveBurst.update(Math.round(burst)); TestStats.pushBurstToHistory(burst); if (currentWord == TestLogic.input.current || Config.mode == "zen") { //correct word or in zen mode MonkeyPower.addPower(true, true); PaceCaret.handleSpace(true, currentWord); TestStats.incrementAccuracy(true); TestLogic.input.pushHistory(); TestLogic.words.increaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1); TestUI.updateActiveElement(); Funbox.toggleScript(TestLogic.words.getCurrent()); Caret.updatePosition(); TestStats.incrementKeypressCount(); TestStats.pushKeypressWord(TestLogic.words.currentIndex); // currentKeypress.count++; // currentKeypress.words.push(TestLogic.words.currentIndex); if (Config.funbox !== "nospace") { Sound.playClick(Config.playSoundOnClick); } Replay.addReplayEvent("submitCorrectWord"); } else { //incorrect word MonkeyPower.addPower(false, true); if (Config.funbox !== "nospace") { if (!Config.playSoundOnError || Config.blindMode) { Sound.playClick(Config.playSoundOnClick); } else { Sound.playError(Config.playSoundOnError); } } TestStats.pushMissedWord(TestLogic.words.getCurrent()); TestStats.incrementAccuracy(false); TestStats.incrementKeypressErrors(); let cil = TestLogic.input.current.length; if (cil <= TestLogic.words.getCurrent().length) { if (cil >= TestLogic.corrected.current.length) { TestLogic.corrected.appendCurrent("_"); } else { TestLogic.corrected.setCurrent( TestLogic.corrected.current.substring(0, cil) + "_" + TestLogic.corrected.current.substring(cil + 1) ); } } if (Config.stopOnError != "off") { if (Config.difficulty == "expert" || Config.difficulty == "master") { //failed due to diff when pressing space TestLogic.fail("difficulty"); return; } if (Config.stopOnError == "word") { TestLogic.input.appendCurrent(" "); Replay.addReplayEvent("incorrectLetter", "_"); TestUI.updateWordElement(true); Caret.updatePosition(); } return; } PaceCaret.handleSpace(false, currentWord); if (Config.blindMode) $("#words .word.active letter").addClass("correct"); TestLogic.input.pushHistory(); TestUI.highlightBadWord(TestUI.currentWordElementIndex, !Config.blindMode); TestLogic.words.increaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1); TestUI.updateActiveElement(); Funbox.toggleScript(TestLogic.words.getCurrent()); Caret.updatePosition(); // currentKeypress.count++; // currentKeypress.words.push(TestLogic.words.currentIndex); TestStats.incrementKeypressCount(); TestStats.pushKeypressWord(TestLogic.words.currentIndex); TestStats.updateLastKeypress(); if (Config.difficulty == "expert" || Config.difficulty == "master") { TestLogic.fail("difficulty"); return; } else if (TestLogic.words.currentIndex == TestLogic.words.length) { //submitted last word that is incorrect TestLogic.finish(); return; } Replay.addReplayEvent("submitErrorWord"); } let wordLength; if (Config.mode === "zen") { wordLength = TestLogic.input.getCurrent().length; } else { wordLength = TestLogic.words.getCurrent().length; } let flex = Misc.whorf(Config.minBurstCustomSpeed, wordLength); if ( (Config.minBurst === "fixed" && burst < Config.minBurstCustomSpeed) || (Config.minBurst === "flex" && burst < flex) ) { TestLogic.fail("min burst"); return; } TestLogic.corrected.pushHistory(); if ( !Config.showAllLines || Config.mode == "time" || (CustomText.isWordRandom && CustomText.word == 0) || CustomText.isTimeRandom ) { let currentTop = Math.floor( document.querySelectorAll("#words .word")[ TestUI.currentWordElementIndex - 1 ].offsetTop ); let nextTop; try { nextTop = Math.floor( document.querySelectorAll("#words .word")[ TestUI.currentWordElementIndex ].offsetTop ); } catch (e) { nextTop = 0; } if (nextTop > currentTop && !TestUI.lineTransition) { TestUI.lineJump(currentTop); } } //end of line wrap // Caret.updatePosition(); if (Config.keymapMode === "react") { Keymap.flashKey(event.code, true); } else if (Config.keymapMode === "next" && Config.mode !== "zen") { Keymap.highlightKey( TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ) .toString() .toUpperCase() ); } if ( Config.mode === "words" || Config.mode === "custom" || Config.mode === "quote" || Config.mode === "zen" ) { TimerProgress.update(TestTimer.time); } if ( Config.mode == "time" || Config.mode == "words" || Config.mode == "custom" ) { TestLogic.addWord(); } } function handleAlpha(event) { if ( [ "ContextMenu", "Escape", "Shift", "Control", "Meta", "Alt", "AltGraph", "CapsLock", "Backspace", "PageUp", "PageDown", "Home", "ArrowUp", "ArrowLeft", "ArrowRight", "ArrowDown", "OS", "Insert", "Home", "Undefined", "Control", "Fn", "FnLock", "Hyper", "NumLock", "ScrollLock", "Symbol", "SymbolLock", "Super", "Unidentified", "Process", "Delete", "KanjiMode", "Pause", "PrintScreen", "Clear", "End", "GroupPrevious", "GroupNext", "WakeUp", undefined, ].includes(event.key) ) { TestStats.incrementKeypressMod(); // currentKeypress.mod++; return; } //insert space for expert and master or strict space, //otherwise dont do anything if (event.key === " ") { if (Config.difficulty !== "normal" || Config.strictSpace) { if (dontInsertSpace) { dontInsertSpace = false; return; } } else { return; } } if (event.key === "Tab") { if ( Config.mode !== "zen" && (!TestLogic.hasTab || (TestLogic.hasTab && event.shiftKey)) ) { return; } event.key = "\t"; event.preventDefault(); } if (event.key === "Enter") { if (event.shiftKey && Config.mode == "zen") { TestLogic.finish(); } if ( event.shiftKey && ((Config.mode == "time" && Config.time === 0) || (Config.mode == "words" && Config.words === 0)) ) { TestLogic.setBailout(true); TestLogic.finish(); } event.key = "\n"; } // if (event.key.length > 1) return; if (/F\d+/.test(event.key)) return; if (/Numpad/.test(event.key)) return; if (/Volume/.test(event.key)) return; if (/Media/.test(event.key)) return; if ( event.ctrlKey != event.altKey && (event.ctrlKey || /Linux/.test(window.navigator.platform)) ) return; if (event.metaKey) return; let originalEvent = { code: event.code, }; event = LayoutEmulator.updateEvent(event); //start the test if ( TestLogic.input.current == "" && TestLogic.input.history.length == 0 && !TestLogic.active ) { if (!TestLogic.startTest()) return; MonkeyPower.addPower(); } else { if (!TestLogic.active) return; } if (TestLogic.input.current == "") { TestStats.setBurstStart(performance.now()); } Focus.set(true); Caret.stopAnimation(); //show dead keys if (event.key === "Dead") { Sound.playClick(Config.playSoundOnClick); $( document.querySelector("#words .word.active").querySelectorAll("letter")[ TestLogic.input.current.length ] ).toggleClass("dead"); return; } //check if the char typed was correct let thisCharCorrect; let nextCharInWord; if (Config.mode != "zen") { nextCharInWord = TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ); } if (nextCharInWord == event["key"]) { thisCharCorrect = true; } else { thisCharCorrect = false; } if (Config.language.split("_")[0] == "russian") { if ((event.key === "е" || event.key === "e") && nextCharInWord == "ё") { event.key = nextCharInWord; thisCharCorrect = true; } if ( event.key === "ё" && (nextCharInWord == "е" || nextCharInWord === "e") ) { event.key = nextCharInWord; thisCharCorrect = true; } } if (Config.mode == "zen") { thisCharCorrect = true; } if ( (event.key === `’` || event.key === `‘` || event.key === "'") && (nextCharInWord == `’` || nextCharInWord === `‘` || nextCharInWord === "'") ) { event.key = nextCharInWord; thisCharCorrect = true; } if ( (event.key === `"` || event.key === "”" || event.key == "“" || event.key === "„") && (nextCharInWord == `"` || nextCharInWord === "”" || nextCharInWord === "“" || nextCharInWord === "„") ) { event.key = nextCharInWord; thisCharCorrect = true; } if ( (event.key === "–" || event.key === "—" || event.key == "-") && (nextCharInWord == "-" || nextCharInWord === "–" || nextCharInWord === "—") ) { event.key = nextCharInWord; thisCharCorrect = true; } if ( Config.oppositeShiftMode === "on" && ShiftTracker.isUsingOppositeShift(originalEvent) === false ) { thisCharCorrect = false; } MonkeyPower.addPower(thisCharCorrect); if (!thisCharCorrect) { TestStats.incrementAccuracy(false); TestStats.incrementKeypressErrors(); // currentError.count++; // currentError.words.push(TestLogic.words.currentIndex); thisCharCorrect = false; TestStats.pushMissedWord(TestLogic.words.getCurrent()); } else { TestStats.incrementAccuracy(true); thisCharCorrect = true; if (Config.mode == "zen") { //making the input visible to the user $("#words .active").append( `