let input = []; let currentWord = []; let selected = -1; window.onload = () => { document.querySelectorAll(".ime").forEach(input => { input.addEventListener("keydown", (key) => { imeDown(key, input); }); input.addEventListener("mousedown", (e) => { e.preventDefault(); input.focus(); imeUpdate(input); }) }); } function imeDown(keyEvent, inputField) { keyEvent.preventDefault(); switch (keyEvent.key) { case "Backspace": if (selected == -1) { let latest = input[input.length] console.log(latest); if (currentWord.join("") == "") { currentWord = input.pop() || []; } else { currentWord.pop(); } } else { input[selected].pop(); if (input[selected].join("") == "") { input.splice(selected,1); imeMove("left"); } } break; case "Enter": if (selected == -1) { if (currentWord.join() == "") { //blame js :) let s = document.createElement("p"); s.innerText = input.join(""); document.body.appendChild(s); input = []; selected = -1; } else { input.push(currentWord); currentWord = []; } } else { if (selected+1 >= input.length) { selected = -1; } else { selected += 1; } } imeReset(); break; case "Space": //adds a ' break; case "ArrowLeft": imeMove("left"); break; case "ArrowRight": imeMove("right"); break; case "ArrowDown": imeMove("start"); break; case "ArrowUp": imeMove("end"); break; default: imeInput(keyEvent.key); if (selected == -1) { currentWord = inputFull; } else { input[selected] = inputFull; } break; } imeUpdate(inputField); } function imeUpdate(inputField) { let renderText = ""; input.forEach((w) => { renderText += w.join(""); }) inputField.value = renderText + currentWord.join(""); if (selected == -1) { inputField.setSelectionRange(renderText.length, renderText.length+currentWord.join("").length); } else { from = 0; for (let x = 0; x < selected; x++) { from += input[x].join("").length; } to = from+input[selected].join("").length; inputField.setSelectionRange(from, to); } } function clamp(min, max, value) { return Math.max(min, Math.min(max, value)); } function imeMove(direction) { let d = 1; if (currentWord.join("") != "") { input.push(currentWord); currentWord = []; d = 2; } switch (direction) { case "start": selected = 0; break; case "end": selected = -1; break; case "left": if (selected == -1) selected = input.length; selected -= 1 * d; if (selected != -1) { selected = clamp(0,input.length,selected); //is there even a point in clamping it here,,,, } break; case "right": selected += 1 * d; selected = clamp(0,input.length,selected); //tbh same here, like. //oh well ig ???/ if (selected == input.length) { selected = -1; } break; } imeReset(); } let inputState = 0; //STARTING, COMPOSTING, TRAILING, Fucking Nothing, ...cleanup let stateState = 0; //depends on the state let inputFull = []; let inputCurrent = ""; let hVowels = { //standalone, composing, trailing "a": ["0", "5", "A"], "e": ["1", "6", "B"], "i": ["2", "7", "C"], "o": ["3", "8", "D"], "u": ["4", "9", "E"] }; let hConsonants = { //0 = standalone, 1 = composing, 2-6 = vowels "g": "01", "s": "02", "r": "03", "n": "04", "c": "05", "m": "06", "j": "07", "f": "08", "t": "09", "k": "0A", "w": "0B", "l": "0C", "p": "0D", "b": "0E", "d": "0F", "h": "10", }; function getUnicodeVowel(vowel, sot) { if (sot == "standalone") sot = 0; if (sot == "composing") sot = 1; if (sot == "trailing") sot = 2; return String.fromCharCode(parseInt("E00" + hVowels[vowel][sot], 16)); } function getUnicodeConsonant(consonant, scv) { if (scv == "standalone") {scv = 0;} else if (scv == "trailing") {scv = 1;} else {scv = Number(hVowels[scv][0])+2} return String.fromCharCode(parseInt("E" + hConsonants[consonant] + "" + scv, 16)); } let hVowelsK = Object.keys(hVowels) let hConsonantsK = Object.keys(hConsonants); function debugInput(key) { console.log("pre "+key+": inputstate - "+inputState +", statestate - "+ stateState); console.log("inputfull: " + inputFull.join(" ") + ", inputcurrent:" + inputCurrent); imeInput(key); console.log("post "+key+": inputstate - "+inputState +", statestate - "+ stateState); console.log("inputfull: " + inputFull.join(" ") + ", inputcurrent:" + inputCurrent); console.log("------------------------------") } function imeReset() { stateState = 0; inputState = 0; inputFull = []; inputCurrent = ""; } function imeInput(key) { key = key.toLowerCase(); if (!hConsonantsK.includes(key) && !hVowelsK.includes(key)) return; switch (inputState) { case 0: //starting if (stateState == 0) { if (hVowelsK.includes(key)) { inputFull.push(getUnicodeVowel(key, "standalone")); inputState = 2; } else { inputFull.push(getUnicodeConsonant(key, "standalone")); stateState = 1; inputCurrent = key; } break; } else if (stateState == 1) { if (hVowelsK.includes(key)) { inputState = 1; stateState = 0; } else { inputFull.push(getUnicodeConsonant(key, "trailing")); inputCurrent = key; stateState = 2; break; } } else if (stateState == 2) { if (hVowelsK.includes(key)) { inputState = 1; stateState = 0; } else break; } case 1: //composing if (hVowelsK.includes(key)) { inputState = 2; inputFull.pop(); inputFull.push(getUnicodeConsonant(inputCurrent, key)); inputCurrent = ""; } break; case 2: //trailing if (hVowelsK.includes(key)) { inputFull.push(getUnicodeVowel(key, "trailing")); stateState += 1; } else { inputFull.push(getUnicodeConsonant(key, "trailing")); stateState += 1; } if (stateState == 2) { stateState = 0; inputState = 3; } break; case 3: //do nothing (i.e "waiting 4 u 2 hit enter") break; case 4: //cleanup (reset vars) stateState = 0; inputCurrent = ""; break; } }