Want to contribute? Fork me on Codeberg.org!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

255 lines
6.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// modified from https://stackoverflow.com/a/14051331
// Issue is keycode conversion for non-alphanumeric keys (e.g. period)
// is not accurate
function convertKeyCode(evt) {
var chara = "";
var keyCode = (evt.which) ? evt.which : evt.keyCode;
var shift = evt.shiftKey;
if (keyCode == 19)
chara = "pause/break";
if (keyCode == 48)
chara = (shift) ? ")" : "0";
if (keyCode == 49)
chara = (shift) ? "!" : "1";
if (keyCode == 50)
chara = (shift) ? "@" : "2";
if (keyCode == 51)
chara = (shift) ? "#" : "3";
if (keyCode == 52)
chara = (shift) ? "$" : "4";
if (keyCode == 53)
chara = (shift) ? "%" : "5";
if (keyCode == 54)
chara = (shift) ? "^" : "6";
if (keyCode == 55)
chara = (shift) ? "&" : "7";
if (keyCode == 56)
chara = (shift) ? "*" : "8";
if (keyCode == 57)
chara = (shift) ? "(" : "9";
if (keyCode == 65)
chara = (shift) ? "A" : "a";
if (keyCode == 66)
chara = (shift) ? "B" : "b";
if (keyCode == 67)
chara = (shift) ? "C" : "c";
if (keyCode == 68)
chara = (shift) ? "D" : "d";
if (keyCode == 69)
chara = (shift) ? "E" : "e";
if (keyCode == 70)
chara = (shift) ? "F" : "f";
if (keyCode == 71)
chara = (shift) ? "G" : "g";
if (keyCode == 72)
chara = (shift) ? "H" : "h";
if (keyCode == 73)
chara = (shift) ? "I" : "i";
if (keyCode == 74)
chara = (shift) ? "J" : "j";
if (keyCode == 75)
chara = (shift) ? "K" : "k";
if (keyCode == 76)
chara = (shift) ? "L" : "l";
if (keyCode == 77)
chara = (shift) ? "M" : "m";
if (keyCode == 78)
chara = (shift) ? "N" : "n";
if (keyCode == 79)
chara = (shift) ? "O" : "o";
if (keyCode == 80)
chara = (shift) ? "P" : "p";
if (keyCode == 81)
chara = (shift) ? "Q" : "q";
if (keyCode == 82)
chara = (shift) ? "R" : "r";
if (keyCode == 83)
chara = (shift) ? "S" : "s";
if (keyCode == 84)
chara = (shift) ? "T" : "t";
if (keyCode == 85)
chara = (shift) ? "U" : "u";
if (keyCode == 86)
chara = (shift) ? "V" : "v";
if (keyCode == 87)
chara = (shift) ? "W" : "w";
if (keyCode == 88)
chara = (shift) ? "X" : "x";
if (keyCode == 89)
chara = (shift) ? "Y" : "y"; if (keyCode == 90)
chara = (shift) ? "Z" : "z";
if (keyCode == 93)
chara = "select key";
if (keyCode == 186 || keyCode == 59)
chara = ";";
if (keyCode == 187 || keyCode == 61)
chara = "=";
if (keyCode == 188)
chara = ",";
if (keyCode == 189 || keyCode == 173)
chara = "-";
if (keyCode == 190)
chara = ".";
if (keyCode == 191)
chara = "/";
if (keyCode == 192)
chara = "`";
if (keyCode == 219)
chara = (shift) ? "{" : "[";
if (keyCode == 220)
chara = "\\";
if (keyCode == 221)
chara = (shift) ? "}" : "]";
if (keyCode == 222)
chara = "'";
return chara;
}
const wordDisplay = document.getElementById("word");
const input = document.getElementById("input");
const timer = document.getElementById("timer");
const hintDisplay = document.getElementById("hint");
const incorrect = document.getElementById("incorrectSfx");
const correct = document.getElementById("correctSfx");
const success = document.getElementById("successSfx");
const leftShiftCode = 32; // space
const rightShiftCode = 16; // shift key
let leftShift = false;
let rightShift = false;
addEventListener("keydown", event => {
switch(event.keyCode) {
case leftShiftCode:
leftShift = true;
event.preventDefault();
break;
case rightShiftCode:
rightShift = true;
event.preventDefault();
break;
}
});
addEventListener("keyup", event => {
switch(event.keyCode) {
case leftShiftCode:
leftShift = false;
break;
case rightShiftCode:
rightShift = false;
break;
}
});
const check = () => {
if (input.value == word) {
if (repeats == 0) {
success.currentTime = 0;
success.play();
} else {
correct.currentTime = 0;
correct.play();
}
clearTimeout(incorrectTimeout);
clearTimeout(timerTimeout);
wordDisplay.style.color = "green";
wordDisplay.innerHTML = `${word}`;
setTimeout(() => {
wordDisplay.style.color = "";
reset();
}, 1000);
}
};
addEventListener("compositionend", event => check());
input.addEventListener("keydown", e => {
const pressed = convertKeyCode(e).toLowerCase(); // String.fromCharCode(e.keyCode).toLowerCase();
if (keymap[pressed] !== undefined) {
let valueIndex = 0;
if (leftShift && keymap[pressed][1]) {
valueIndex = 1;
} else if (rightShift && keymap[pressed][2]) {
valueIndex = 2;
}
input.value += keymap[pressed][valueIndex];
check();
e.preventDefault();
} else if (pressed == " ") {
e.preventDefault();
}
});
// window.requestAnimationFrame() might be better suited
// https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
let typeTimePerKana = 2; // in seconds
const typeTimePerKanaInput = document.getElementById("timePerKana");
typeTimePerKanaInput.value = typeTimePerKana;
typeTimePerKanaInput.addEventListener("change", (e) => {
typeTimePerKana = typeTimePerKanaInput.value;
});
const timerFPS = 60;
let incorrectTimeout = null;
let timerTimeout = null;
let word = null;
let repeats = 0;
let failed = false;
let problemWords = [];
let problemTimes = [];
const reset = () => {
failed = false;
input.value = "";
hint.innerHTML = "";
timer.value = 1;
if (repeats == 0) {
if (problemTimes.length > 0 && new Date() - problemTimes[0] > 60000) {
word = problemWords[0];
problemWords.shift();
problemTimes.shift();
} else {
word = words[Math.round(Math.random() * words.length)];
}
}
wordDisplay.innerHTML = word;
const typeTime = typeTimePerKana * word.length;
incorrectTimeout = setTimeout(() => {
if (!problemWords.includes(word)) {
problemWords.push(word);
problemTimes.push(new Date());
}
repeats += repeats == 0 ? 3 : 1;
failed = true;
wordDisplay.innerHTML = `${word}`;
incorrect.currentTime = 0;
incorrect.play();
for (let i = 0; i < word.length; i++) {
const letter = word[i];
let key = null;
let index = null;
for (let otherKey in keymap) {
for (let i = 0; i < keymap[otherKey].length && !key; i++) {
if (keymap[otherKey][i] == letter) {
key = otherKey;
index = i;
}
}
}
let t = `<h3>${letter.toUpperCase()}<kbd`;
if (index > 0) {
t += ' style="background: ';
if (index == 1) {
t += "yellow";
} else if (index == 2) {
t += "cyan";
} else if (index == 3) {
t += "magenta";
}
t += '"';
}
t += `>${key}</kbd></h3>`;
hint.innerHTML += t;
}
}, typeTime * 1000);
clearInterval(timerTimeout);
timerTimeout = setInterval(() => {
timer.value -= (1 / timerFPS) / typeTime;
}, 1000 / timerFPS);
if (repeats > 0) {
repeats--;
}
};
reset();