Initial commit

main
Elnu 2 years ago
commit a9a32378d0

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>nicolator</title>
<link rel="stylesheet" href="https://unpkg.com/sakura.css/css/normalize.css" type="text/css">
<link rel="stylesheet" href="https://unpkg.com/sakura.css/css/sakura-pink.css" type="text/css">
<script src="keymap.js"></script>
<script src="words.js"></script>
</head>
<body>
<details open>
<summary>Keymap</summary>
<img src="http://xahlee.info/kbd/i2/japanese_nicola_j_keyboard_layout.png" alt="Keymap">
</details>
<details>
<summary>Settings ⚙️</summary>
Seconds per kana <input type="number" id="timePerKana">
</details>
<h1 id="word" style="text-align: center"></h1>
<input id="input" style="width: 100%" autocomplete="off"><br>
<progress id="timer" value="1" style="width: 100%"></progress>
<div id="hint"></div>
<script src="nicolator.js"></script>
</body>
</html>

@ -0,0 +1,48 @@
const keymap = {
"1": ["", "", null, ""],
"2": ["", "", null, "”"],
"3": ["", null, null, ""],
"4": ["", "「", null, ""],
"5": ["", "」", null, ""],
"6": ["", null, "", ""],
"7": ["", null, "", ""],
"8": ["", null, "", ""],
"9": ["", null, "", ""],
"0": ["", null, null, ""],
"-": ["", null, null, ""],
"=": ["", null, null, ""],
"q": ["。", "ぁ", null, ""],
"w": ["か", "え", "が", ""],
"e": ["た", "り", "だ", ""],
"r": ["こ", "ゃ", "ご", ""],
"t": ["さ", "れ", "ざ", ""],
"y": ["ら", "ぱ", "よ", ""],
"u": ["ち", "ぢ", "に", ""],
"i": ["く", "ぐ", "る", ""],
"o": ["つ", "づ", "ま", ""],
"p": ["", "ぴ", "ぇ", ""],
"[": ["、", null, null, ""],
"]": ["゛", null, "゜", ""],
"\\": ["", null, null, ""],
"a": ["う", "を", null, ""],
"s": ["し", "あ", "じ", ""],
"d": ["て", "な", "で", ""],
"f": ["け", "ゅ", "げ", ""],
"g": ["せ", "も", "ぜ", ""],
"h": ["は", "ば", "み", ""],
"j": ["と", "ど", "お", ""],
"k": ["き", "ぎ", "の", ""],
"l": ["い", "ぽ", "ょ", ""],
";": ["ん", null, "っ", ""],
"'": ["", null, null, ""],
"z": ["", "ぅ", null, ""],
"x": ["ひ", "ー", "び", ""],
"c": ["す", "ろ", "ず", ""],
"v": ["ふ", "や", "ぶ", ""],
"b": ["へ", "ぃ", "べ", ""],
"n": ["め", "ぷ", "ぬ", ""],
"m": ["そ", "ぞ", "ゆ", ""],
",": ["ね", "ぺ", "む", ""],
".": ["ほ", "ぼ", "わ", ""],
"/": ["・", null, "ぉ", ""],
};

@ -0,0 +1,222 @@
// 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 leftShiftCode = 32; // space
const rightShiftCode = 16; // shift key
let leftShift = false;
let rightShift = false;
let inComposition = 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;
}
});
addEventListener("compositionstart", event => inComposition = true);
addEventListener("compositionend", event => inComposition = false);
input.addEventListener("keydown", e => {
if (inComposition) {
return;
}
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];
if (input.value == word) {
clearTimeout(timeout);
wordDisplay.style.color = "green";
wordDisplay.innerHTML += " ✅";
setTimeout(() => {
wordDisplay.style.color = "";
reset();
}, 1000);
}
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 timerTimeout = null;
let timeout = null;
let word = null;
const reset = () => {
input.value = "";
hint.innerHTML = "";
timer.value = 1;
word = words[Math.round(Math.random() * words.length)];
timeout = wordDisplay.innerHTML = word;
const typeTime = typeTimePerKana * word.length;
setTimeout(() => {
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()}`;
if (index > 0) {
t += "<kbd>";
if (index == 1) {
t += "&larr;";
} else if (index == 2) {
t += "&rarr;";
} else if (index == 3) {
t += "&uarr;";
}
t += "</kbd> + ";
}
t += `<kbd>${key}</kbd></h3>`;
hint.innerHTML += t;
}
}, typeTime * 1000);
clearInterval(timerTimeout);
timerTimeout = setInterval(() => {
timer.value -= (1 / timerFPS) / typeTime;
}, 1000 / timerFPS);
};
reset();

File diff suppressed because one or more lines are too long