moved input to input controller module #495

This commit is contained in:
Jack 2021-03-31 19:17:15 +01:00
parent 27fff39cc3
commit 1f7c2c4df6
4 changed files with 810 additions and 796 deletions

View file

@ -105,6 +105,7 @@ const refactoredSrc = [
"./src/js/account-controller.js",
"./src/js/simple-popups.js",
"./src/js/settings.js",
"./src/js/input-controller.js",
"./src/js/account/all-time-stats.js",
"./src/js/account/pb-tables.js",

View file

@ -55,3 +55,4 @@ import * as AllTimeStats from "./all-time-stats";
import * as PbTables from "./pb-tables";
import * as Account from "./account";
import * as VerificationController from "./verification-controller";
import "./input-controller";

808
src/js/input-controller.js Normal file
View file

@ -0,0 +1,808 @@
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 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";
$("#wordsInput").keypress((event) => {
event.preventDefault();
});
let dontInsertSpace = false;
$(document).keyup((event) => {
if (!event.originalEvent.isTrusted) return;
if (TestUI.resultVisible) return;
let now = performance.now();
let diff = Math.abs(TestStats.keypressTimings.duration.current - now);
if (TestStats.keypressTimings.duration.current !== -1) {
TestStats.pushKeypressDuration(diff);
// keypressStats.duration.array.push(diff);
}
TestStats.setKeypressDuration(now);
// keypressStats.duration.current = now;
Monkey.stop();
});
$(document).keydown(function (event) {
if (!(event.key == " ") && !event.originalEvent.isTrusted) return;
if (!TestUI.resultVisible) {
TestStats.recordKeypressSpacing();
}
Monkey.type();
//autofocus
let pageTestActive = !$(".pageTest").hasClass("hidden");
let commandLineVisible = !$("#commandLineWrapper").hasClass("hidden");
let wordsFocused = $("#wordsInput").is(":focus");
let modePopupVisible =
!$("#customTextPopupWrapper").hasClass("hidden") ||
!$("#customWordAmountPopupWrapper").hasClass("hidden") ||
!$("#customTestDurationPopupWrapper").hasClass("hidden") ||
!$("#quoteSearchPopupWrapper").hasClass("hidden") ||
!$("#wordFilterPopupWrapper").hasClass("hidden");
if (
pageTestActive &&
!commandLineVisible &&
!modePopupVisible &&
!TestUI.resultVisible &&
!wordsFocused &&
event.key !== "Enter"
) {
TestUI.focusWords();
wordsFocused = true;
// if (Config.showOutOfFocusWarning) return;
}
//tab
if (
(event.key == "Tab" && !Config.swapEscAndTab) ||
(event.key == "Escape" && Config.swapEscAndTab)
) {
handleTab(event);
// event.preventDefault();
}
//blocking firefox from going back in history with backspace
if (event.key === "Backspace" && wordsFocused) {
let t = /INPUT|SELECT|TEXTAREA/i;
if (
!t.test(event.target.tagName) ||
event.target.disabled ||
event.target.readOnly
) {
event.preventDefault();
}
}
// keypressStats.duration.current = performance.now();
TestStats.setKeypressDuration(performance.now());
if (TestUI.testRestarting) {
return;
}
//backspace
const isBackspace =
event.key === "Backspace" ||
(Config.capsLockBackspace && event.key === "CapsLock");
if (isBackspace && wordsFocused) {
handleBackspace(event);
}
if (event.key === "Enter" && Funbox.active === "58008" && wordsFocused) {
event.key = " ";
}
//space or enter
if (event.key === " " && wordsFocused) {
handleSpace(event, false);
}
if (wordsFocused && !commandLineVisible) {
handleAlpha(event);
}
let acc = Misc.roundTo2(TestStats.calculateAccuracy());
LiveAcc.update(acc);
});
function handleTab(event) {
if (TestUI.resultCalculating) {
event.preventDefault();
}
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 (
$(".pageTest").hasClass("active") &&
!TestUI.resultCalculating &&
$("#commandLineWrapper").hasClass("hidden") &&
$("#simplePopupWrapper").hasClass("hidden")
) {
if (Config.quickTab) {
if (Config.mode == "zen" && !event.shiftKey) {
//ignore
} else {
if (event.shiftKey) ManualRestart.set();
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 (Funbox.active === "nospace") {
TestLogic.input.setCurrent(
TestLogic.input.current.substring(
0,
TestLogic.input.current.length - 1
)
);
}
}
TestLogic.words.decreaseCurrentIndex();
TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex - 1);
TestUI.updateActiveElement(true);
Funbox.toggleScript(TestLogic.words.getCurrent());
TestUI.updateWordElement(!Config.blindMode);
}
} else {
if (Config.confidenceMode === "max") return;
if (event["ctrlKey"] || event["altKey"]) {
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);
}
} else if (event.metaKey) {
TestLogic.input.resetCurrent();
} else {
TestLogic.input.setCurrent(
TestLogic.input.current.substring(0, TestLogic.input.current.length - 1)
);
}
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 && Funbox.active !== "58008")) return;
// if (!isEnter && nextWord === "\n") return;
event.preventDefault();
if (Config.mode == "zen") {
$("#words .word.active").removeClass("active");
$("#words").append("<div class='word active'></div>");
}
let currentWord = TestLogic.words.getCurrent();
if (Funbox.active === "layoutfluid" && Config.mode !== "time") {
const layouts = ["qwerty", "dvorak", "colemak"];
let index = 0;
let outof = TestLogic.words.length;
index = Math.floor((TestLogic.input.history.length + 1) / (outof / 3));
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;
if (currentWord == TestLogic.input.current || Config.mode == "zen") {
//correct word or in zen mode
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 (Funbox.active !== "nospace") {
Sound.playClick(Config.playSoundOnClick);
}
} else {
//incorrect word
PaceCaret.handleSpace(false, currentWord);
if (Funbox.active !== "nospace") {
if (!Config.playSoundOnError || Config.blindMode) {
Sound.playClick(Config.playSoundOnClick);
} else {
Sound.playError(Config.playSoundOnError);
}
}
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();
return;
}
if (Config.stopOnError == "word") {
TestLogic.input.appendCurrent(" ");
TestUI.updateWordElement(true);
Caret.updatePosition();
}
return;
}
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);
if (Config.difficulty == "expert" || Config.difficulty == "master") {
TestLogic.fail();
return;
} else if (TestLogic.words.currentIndex == TestLogic.words.length) {
//submitted last word that is incorrect
TestStats.setLastSecondNotRound();
TestLogic.finish();
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",
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 = event;
event = LayoutEmulator.updateEvent(event);
//start the test
if (
TestLogic.input.current == "" &&
TestLogic.input.history.length == 0 &&
!TestLogic.active
) {
if (!TestLogic.startTest()) return;
} else {
if (!TestLogic.active) return;
}
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 === "" && nextCharInWord == "'") {
event.key = "'";
thisCharCorrect = true;
}
if (event.key === "'" && nextCharInWord == "") {
event.key = "";
thisCharCorrect = true;
}
if (event.key === "”" && nextCharInWord == '"') {
event.key = '"';
thisCharCorrect = true;
}
if (event.key === '"' && nextCharInWord == "”") {
event.key = "”";
thisCharCorrect = true;
}
if ((event.key === "" || event.key === "—") && nextCharInWord == "-") {
event.key = "-";
thisCharCorrect = true;
}
if (
Config.oppositeShiftMode === "on" &&
ShiftTracker.isUsingOppositeShift(originalEvent) === false
) {
thisCharCorrect = false;
}
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(
`<letter class="correct">${event.key}</letter>`
);
}
}
if (thisCharCorrect) {
Sound.playClick(Config.playSoundOnClick);
} else {
if (!Config.playSoundOnError || Config.blindMode) {
Sound.playClick(Config.playSoundOnClick);
} else {
Sound.playError(Config.playSoundOnError);
}
}
if (
Config.oppositeShiftMode === "on" &&
ShiftTracker.isUsingOppositeShift(originalEvent) === false
)
return;
//update current corrected verison. if its empty then add the current key. if its not then replace the last character with the currently pressed one / add it
if (TestLogic.corrected.current === "") {
TestLogic.corrected.setCurrent(TestLogic.input.current + event["key"]);
} else {
let cil = TestLogic.input.current.length;
if (cil >= TestLogic.corrected.current.length) {
TestLogic.corrected.appendCurrent(event["key"]);
} else if (!thisCharCorrect) {
TestLogic.corrected.setCurrent(
TestLogic.corrected.current.substring(0, cil) +
event["key"] +
TestLogic.corrected.current.substring(cil + 1)
);
}
}
TestStats.incrementKeypressCount();
TestStats.pushKeypressWord(TestLogic.words.currentIndex);
// currentKeypress.count++;
// currentKeypress.words.push(TestLogic.words.currentIndex);
if (Config.stopOnError == "letter" && !thisCharCorrect) {
return;
}
//update the active word top, but only once
if (
TestLogic.input.current.length === 1 &&
TestLogic.words.currentIndex === 0
) {
TestUI.setActiveWordTop(document.querySelector("#words .active").offsetTop);
}
//max length of the input is 20 unless in zen mode
if (
Config.mode == "zen" ||
TestLogic.input.current.length < TestLogic.words.getCurrent().length + 20
) {
TestLogic.input.appendCurrent(event["key"]);
}
if (!thisCharCorrect && Config.difficulty == "master") {
TestLogic.fail();
return;
}
//keymap
if (Config.keymapMode === "react") {
Keymap.flashKey(event.key, thisCharCorrect);
} 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()
);
}
let activeWordTopBeforeJump = TestUI.activeWordTop;
TestUI.updateWordElement(!Config.blindMode);
if (Config.mode != "zen") {
//not applicable to zen mode
//auto stop the test if the last word is correct
let currentWord = TestLogic.words.getCurrent();
let lastindex = TestLogic.words.currentIndex;
if (
(currentWord == TestLogic.input.current ||
(Config.quickEnd &&
currentWord.length == TestLogic.input.current.length &&
Config.stopOnError == "off")) &&
lastindex == TestLogic.words.length - 1
) {
TestLogic.input.pushHistory();
TestLogic.corrected.pushHistory();
TestStats.setLastSecondNotRound();
TestLogic.finish();
}
}
//simulate space press in nospace funbox
if (
(Funbox.active === "nospace" &&
TestLogic.input.current.length === TestLogic.words.getCurrent().length) ||
(event.key === "\n" && thisCharCorrect)
) {
$.event.trigger({
type: "keydown",
which: " ".charCodeAt(0),
key: " ",
});
}
let newActiveTop = document.querySelector("#words .word.active").offsetTop;
//stop the word jump by slicing off the last character, update word again
if (
activeWordTopBeforeJump < newActiveTop &&
!TestUI.lineTransition &&
TestLogic.input.current.length > 1
) {
if (Config.mode == "zen") {
let currentTop = Math.floor(
document.querySelectorAll("#words .word")[
TestUI.currentWordElementIndex - 1
].offsetTop
);
if (!Config.showAllLines) TestUI.lineJump(currentTop);
} else {
TestLogic.input.setCurrent(TestLogic.input.current.slice(0, -1));
TestUI.updateWordElement(!Config.blindMode);
}
}
Caret.updatePosition();
}

View file

@ -1,13 +1,3 @@
//test timer
//ui
///
// let CustomText = "The quick brown fox jumps over the lazy dog".split(" ");
// let CustomText.isWordRandom = false;
// let CustomText.word = 1;
(function (history) {
var pushState = history.pushState;
history.pushState = function (state) {
@ -35,792 +25,6 @@ $(window).on("popstate", (e) => {
}
});
$("#wordsInput").keypress((event) => {
event.preventDefault();
});
let dontInsertSpace = false;
$(document).keyup((event) => {
if (!event.originalEvent.isTrusted) return;
if (TestUI.resultVisible) return;
let now = performance.now();
let diff = Math.abs(TestStats.keypressTimings.duration.current - now);
if (TestStats.keypressTimings.duration.current !== -1) {
TestStats.pushKeypressDuration(diff);
// keypressStats.duration.array.push(diff);
}
TestStats.setKeypressDuration(now);
// keypressStats.duration.current = now;
Monkey.stop();
});
$(document).keydown(function (event) {
if (!(event.key == " ") && !event.originalEvent.isTrusted) return;
if (!TestUI.resultVisible) {
TestStats.recordKeypressSpacing();
}
Monkey.type();
//autofocus
let pageTestActive = !$(".pageTest").hasClass("hidden");
let commandLineVisible = !$("#commandLineWrapper").hasClass("hidden");
let wordsFocused = $("#wordsInput").is(":focus");
let modePopupVisible =
!$("#customTextPopupWrapper").hasClass("hidden") ||
!$("#customWordAmountPopupWrapper").hasClass("hidden") ||
!$("#customTestDurationPopupWrapper").hasClass("hidden") ||
!$("#quoteSearchPopupWrapper").hasClass("hidden") ||
!$("#wordFilterPopupWrapper").hasClass("hidden");
if (
pageTestActive &&
!commandLineVisible &&
!modePopupVisible &&
!TestUI.resultVisible &&
!wordsFocused &&
event.key !== "Enter"
) {
TestUI.focusWords();
wordsFocused = true;
// if (Config.showOutOfFocusWarning) return;
}
//tab
if (
(event.key == "Tab" && !Config.swapEscAndTab) ||
(event.key == "Escape" && Config.swapEscAndTab)
) {
handleTab(event);
// event.preventDefault();
}
//blocking firefox from going back in history with backspace
if (event.key === "Backspace" && wordsFocused) {
let t = /INPUT|SELECT|TEXTAREA/i;
if (
!t.test(event.target.tagName) ||
event.target.disabled ||
event.target.readOnly
) {
event.preventDefault();
}
}
// keypressStats.duration.current = performance.now();
TestStats.setKeypressDuration(performance.now());
if (TestUI.testRestarting) {
return;
}
//backspace
const isBackspace =
event.key === "Backspace" ||
(Config.capsLockBackspace && event.key === "CapsLock");
if (isBackspace && wordsFocused) {
handleBackspace(event);
}
if (event.key === "Enter" && Funbox.active === "58008" && wordsFocused) {
event.key = " ";
}
//space or enter
if (event.key === " " && wordsFocused) {
handleSpace(event, false);
}
if (wordsFocused && !commandLineVisible) {
handleAlpha(event);
}
let acc = Misc.roundTo2(TestStats.calculateAccuracy());
LiveAcc.update(acc);
});
function handleTab(event) {
if (TestUI.resultCalculating) {
event.preventDefault();
}
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 (
$(".pageTest").hasClass("active") &&
!TestUI.resultCalculating &&
$("#commandLineWrapper").hasClass("hidden") &&
$("#simplePopupWrapper").hasClass("hidden")
) {
if (Config.quickTab) {
if (Config.mode == "zen" && !event.shiftKey) {
//ignore
} else {
if (event.shiftKey) ManualRestart.set();
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 (Funbox.active === "nospace") {
TestLogic.input.setCurrent(
TestLogic.input.current.substring(
0,
TestLogic.input.current.length - 1
)
);
}
}
TestLogic.words.decreaseCurrentIndex();
TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex - 1);
TestUI.updateActiveElement(true);
Funbox.toggleScript(TestLogic.words.getCurrent());
TestUI.updateWordElement(!Config.blindMode);
}
} else {
if (Config.confidenceMode === "max") return;
if (event["ctrlKey"] || event["altKey"]) {
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);
}
} else if (event.metaKey) {
TestLogic.input.resetCurrent();
} else {
TestLogic.input.setCurrent(
TestLogic.input.current.substring(0, TestLogic.input.current.length - 1)
);
}
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 && Funbox.active !== "58008")) return;
// if (!isEnter && nextWord === "\n") return;
event.preventDefault();
if (Config.mode == "zen") {
$("#words .word.active").removeClass("active");
$("#words").append("<div class='word active'></div>");
}
let currentWord = TestLogic.words.getCurrent();
if (Funbox.active === "layoutfluid" && Config.mode !== "time") {
const layouts = ["qwerty", "dvorak", "colemak"];
let index = 0;
let outof = TestLogic.words.length;
index = Math.floor((TestLogic.input.history.length + 1) / (outof / 3));
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;
if (currentWord == TestLogic.input.current || Config.mode == "zen") {
//correct word or in zen mode
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 (Funbox.active !== "nospace") {
Sound.playClick(Config.playSoundOnClick);
}
} else {
//incorrect word
PaceCaret.handleSpace(false, currentWord);
if (Funbox.active !== "nospace") {
if (!Config.playSoundOnError || Config.blindMode) {
Sound.playClick(Config.playSoundOnClick);
} else {
Sound.playError(Config.playSoundOnError);
}
}
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();
return;
}
if (Config.stopOnError == "word") {
TestLogic.input.appendCurrent(" ");
TestUI.updateWordElement(true);
Caret.updatePosition();
}
return;
}
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);
if (Config.difficulty == "expert" || Config.difficulty == "master") {
TestLogic.fail();
return;
} else if (TestLogic.words.currentIndex == TestLogic.words.length) {
//submitted last word that is incorrect
TestStats.setLastSecondNotRound();
TestLogic.finish();
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",
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 = event;
event = LayoutEmulator.updateEvent(event);
//start the test
if (
TestLogic.input.current == "" &&
TestLogic.input.history.length == 0 &&
!TestLogic.active
) {
if (!TestLogic.startTest()) return;
} else {
if (!TestLogic.active) return;
}
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 === "" && nextCharInWord == "'") {
event.key = "'";
thisCharCorrect = true;
}
if (event.key === "'" && nextCharInWord == "") {
event.key = "";
thisCharCorrect = true;
}
if (event.key === "”" && nextCharInWord == '"') {
event.key = '"';
thisCharCorrect = true;
}
if (event.key === '"' && nextCharInWord == "”") {
event.key = "”";
thisCharCorrect = true;
}
if ((event.key === "" || event.key === "—") && nextCharInWord == "-") {
event.key = "-";
thisCharCorrect = true;
}
if (
Config.oppositeShiftMode === "on" &&
ShiftTracker.isUsingOppositeShift(originalEvent) === false
) {
thisCharCorrect = false;
}
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(
`<letter class="correct">${event.key}</letter>`
);
}
}
if (thisCharCorrect) {
Sound.playClick(Config.playSoundOnClick);
} else {
if (!Config.playSoundOnError || Config.blindMode) {
Sound.playClick(Config.playSoundOnClick);
} else {
Sound.playError(Config.playSoundOnError);
}
}
if (
Config.oppositeShiftMode === "on" &&
ShiftTracker.isUsingOppositeShift(originalEvent) === false
)
return;
//update current corrected verison. if its empty then add the current key. if its not then replace the last character with the currently pressed one / add it
if (TestLogic.corrected.current === "") {
TestLogic.corrected.setCurrent(TestLogic.input.current + event["key"]);
} else {
let cil = TestLogic.input.current.length;
if (cil >= TestLogic.corrected.current.length) {
TestLogic.corrected.appendCurrent(event["key"]);
} else if (!thisCharCorrect) {
TestLogic.corrected.setCurrent(
TestLogic.corrected.current.substring(0, cil) +
event["key"] +
TestLogic.corrected.current.substring(cil + 1)
);
}
}
TestStats.incrementKeypressCount();
TestStats.pushKeypressWord(TestLogic.words.currentIndex);
// currentKeypress.count++;
// currentKeypress.words.push(TestLogic.words.currentIndex);
if (Config.stopOnError == "letter" && !thisCharCorrect) {
return;
}
//update the active word top, but only once
if (
TestLogic.input.current.length === 1 &&
TestLogic.words.currentIndex === 0
) {
TestUI.setActiveWordTop(document.querySelector("#words .active").offsetTop);
}
//max length of the input is 20 unless in zen mode
if (
Config.mode == "zen" ||
TestLogic.input.current.length < TestLogic.words.getCurrent().length + 20
) {
TestLogic.input.appendCurrent(event["key"]);
}
if (!thisCharCorrect && Config.difficulty == "master") {
TestLogic.fail();
return;
}
//keymap
if (Config.keymapMode === "react") {
Keymap.flashKey(event.key, thisCharCorrect);
} 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()
);
}
let activeWordTopBeforeJump = TestUI.activeWordTop;
TestUI.updateWordElement(!Config.blindMode);
if (Config.mode != "zen") {
//not applicable to zen mode
//auto stop the test if the last word is correct
let currentWord = TestLogic.words.getCurrent();
let lastindex = TestLogic.words.currentIndex;
if (
(currentWord == TestLogic.input.current ||
(Config.quickEnd &&
currentWord.length == TestLogic.input.current.length &&
Config.stopOnError == "off")) &&
lastindex == TestLogic.words.length - 1
) {
TestLogic.input.pushHistory();
TestLogic.corrected.pushHistory();
TestStats.setLastSecondNotRound();
TestLogic.finish();
}
}
//simulate space press in nospace funbox
if (
(Funbox.active === "nospace" &&
TestLogic.input.current.length === TestLogic.words.getCurrent().length) ||
(event.key === "\n" && thisCharCorrect)
) {
$.event.trigger({
type: "keydown",
which: " ".charCodeAt(0),
key: " ",
});
}
let newActiveTop = document.querySelector("#words .word.active").offsetTop;
//stop the word jump by slicing off the last character, update word again
if (
activeWordTopBeforeJump < newActiveTop &&
!TestUI.lineTransition &&
TestLogic.input.current.length > 1
) {
if (Config.mode == "zen") {
let currentTop = Math.floor(
document.querySelectorAll("#words .word")[
TestUI.currentWordElementIndex - 1
].offsetTop
);
if (!Config.showAllLines) TestUI.lineJump(currentTop);
} else {
TestLogic.input.setCurrent(TestLogic.input.current.slice(0, -1));
TestUI.updateWordElement(!Config.blindMode);
}
}
Caret.updatePosition();
}
ManualRestart.set();
UpdateConfig.loadFromCookie();
Misc.getReleasesFromGitHub();